The MASM Forum

General => The Workshop => Topic started by: jj2007 on March 04, 2020, 11:29:21 PM

Title: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 04, 2020, 11:29:21 PM
Where is the bug? The proc is 200+ lines, here are the 10% that caused a bug that was well hidden:
xor ecx, ecx
.if edx==STILL_ACTIVE
push chr$("'still active'")
.if [ebx.BuildVars.IsConsole] ; a Windows app is always still active...
dec ecx ; set the flag
.endif
.else
dec ecx
push str$(edx)
.endif
lea edi, buffer
jecxz @F
push eax
invoke lstrcpy, edi, Chr$("** RichMasm warning:", 13, 10, "exit code ")
push edi
call lstrcat
invoke lstrcat, edi, chr$(" **", 13, 10)
SetWin$ hStatus=edi
@@:


I caught it by comparing the stack at start and end of the proc with a dedicated macro that replaced the ret before the endp. Over 100 rets in the 21,000 lines source are ok, this one misbehaved.

The nastiest aspect here is that often you will not notice the problem, because the leave or mov esp, ebp makes sure you return to the correct address. But you are returning there with incorrectly restored esi, edi and ebx... and that may or may not cause a crash, and it may happen when you least suspect it. One of those bugs that will cause you sleepless nights :cool:

So far the routine works fine, and once it will be well tested and stable enough, I will post macro and *.lib file.

But I have a question: Does anybody have an idea how to safely recognise the start and end of a proc that has no stack frame?
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 05, 2020, 01:40:24 PM
In the meantime, I found at least a method to recognise that a proc has no stack frame.

The idea is very simple: in a large source, replace every ret that is followed by somecode endp with @MbRet. It takes an optional argument that should be the name of the proc; if there is no argument, the source line will be shown instead (as in the CodeNoArgs example below).

If the source has stack problems, they will be ## flagged to the console ##, even if the exe was built as a Windows application.

There are basically three cases:
1. too many push instructions: @MbRet will tell you about it, and correct the stack so that at least the uses esi edi ebx works properly.

2. too many pop instructions: @MbRet will tell you about it, and correct the stack but one or more of the regs in the uses esi edi ebx list will be trashed anyway.

3. stack corruption: the return address is somewhere in nirwana land. @MbRet will inform you about it, but the program will crash anyway.

I've tested it with a 20k lines source, and so far I've found one bug with it, see first post above. @MbRet tests runtime behaviour, so its messages will pop up only when you are really using a proc. So for rarely used exotic functions it may take a while until you discover the bug.

Once you have verified that there are no problems, put @MbRet off below the include line, so that only an ordinary ret will be generated.

Here is a little demo with some procs that treat the stack badly (tested ok with WinXP, Win7-64 and Win10):

include \masm32\include\masm32rt.inc ; purest Masm32 SDK code
include MbRet.inc ; must be in the exe's folder
; @MbRet off ; switch it off once tests are OK

.code
TwoArgsNoLocals proc uses esi edi ebx mode, crashArg
  mov ebx, mode ; no Locals, but has args, and therefore a stack frame
  print "2 args: ebx="
  print str$(ebx), 13, 10
  .while sdword ptr ebx>=0
push eax ; stack imbalances will be flagged
dec ebx
  .Endw
  pop eax ; stack is balanced
  pop ecx ; for mode=3
  pop edx
  .if crashArg==99
mov dword ptr [ebp+4], 12345678h ; bad news for the return address ;-)
  .endif
  @MbRet 2ArgsNoLocals ; instead of the ret
TwoArgsNoLocals endp

ThreeArgsLocal123 proc uses ecx mode, arg2, arg3
Local buffer[123]:BYTE
  push eax ; stack not balanced, will be flagged
  @MbRet ThreeArgsLocal123
ThreeArgsLocal123 endp

CodeNoArgs proc uses esi edi ebx ecx ebp
  print "CodeNoArgs - cannot work with @MbRet: "
  ; push eax ; activate to produce a crash
  @MbRet ; no label -> line number 32; @MbRet will say "no frame found"
CodeNoArgs endp

start:
  cls
  m2m esi, 3
  mov ebx, 12345678h
  .Repeat
invoke TwoArgsNoLocals, esi, 123
print hex$(ebx), ": ebx after the invoke", 13, 10, 10
dec esi
  .Until Zero?
  invoke CodeNoArgs
  invoke ThreeArgsLocal123, 123, 456, 789
  inkey chr$(10, "hit any key for the stack corruption test:", 13, 10)
  invoke TwoArgsNoLocals, 2, 99
  MsgBox 0, "You won't see this box", "Hi", MB_OK
  invoke ExitProcess, 0
end start


The procs have little problems with a sloppy use of the push and pop instructions. Here is the output:
2 args: ebx=3
### MbRet 2ArgsNoLocals: stack is -4 bytes off, 1 push(es) too many ###
12345678: ebx after the invoke

2 args: ebx=2
12345678: ebx after the invoke

2 args: ebx=1
### MbRet 2ArgsNoLocals: stack is 4 bytes off, 1 pop(s) too many - check uses ###
0040107A: ebx after the invoke

CodeNoArgs - cannot work with @MbRet: ### MbRet 31: no stack frame found ###
### MbRet ThreeArgsLocal123: stack is -4 bytes off, 1 push(es) too many ###

hit any key for the stack corruption test:

2 args: ebx=2
### stack corruption? 2ArgsNoLocals: retaddr 12345678h is above the code segment ###


After the stack corruption test, it will produce an exception.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: HSE on March 05, 2020, 11:47:07 PM
Very interesting JJ   :thumbsup:

When there is no stack perhaps you can make an @MbTestStack.

Text output is a little confusing, perhaps in a line " MbRet name  [file , line]" , details in following lines and finally an empty line.

Of course a summary: N_stack_procs, N_non_stack_procs (yellow if > 0?), unbalances detected (green when 0, red some case)   :biggrin:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 06, 2020, 02:47:00 AM
It may help a little if you looked for the alignment padding after a RET but fundamentally a no stack frame procedure is hard to determine because you don't have an immediate technique to find the start and end of the proc. If it is being found with a disassembler, the output generally shows the start label (address) of the proc but if you have to do it in bare mnemonics you have a hard task in front of you.

With a disassembler it checks the address that a CALL mnemonic addresses which gives you the start address but there is no easy way to get the procedure end, possible the last RET before the next known CALL label and if it has alignment padding between the RET and the next label.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 06, 2020, 04:29:43 AM
The current version can determine if it is a no-frame procedure, and where its end is. What it cannot do so easily is find the start of the proc. So at present it will just issue a line saying "can't check a no frame proc".

Is anybody aware of a big asm source in the public domain? I need a test case that looks different from my own stuff.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: HSE on March 06, 2020, 04:55:46 AM
Quote from: jj2007 on March 06, 2020, 04:29:43 AM
What it cannot do so easily is find the start of the proc. So at present it will just issue a line saying "can't check a no frame proc".

iI you bother to write @MbRet at procedures ends, cost you just a cent to write @MbTestStack at its beginnings.  :cool:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: Biterider on March 06, 2020, 06:41:54 AM
What about writing custom prologues and epilogues?
Biterider
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 06, 2020, 07:18:23 AM
Quote from: HSE on March 06, 2020, 04:55:46 AM
If you bother to write @MbRet at procedures ends, cost you just a cent to write @MbTestStack at its beginnings.  :cool:

Correct, but replacing a hundred ret..whatever endp pairs in a big source is done in a single Find & Replace command. Inserting a macro on top, after the LOCALS, is a bit more involved.

Quote from: Biterider on March 06, 2020, 06:41:54 AM
What about writing custom prologues and epilogues?

Sure, that's the best option, but you risk breaking old code. The current @MbRet does not require such efforts, and it also doesn't generate any extra code once you switch if off with a single statement. It is an absolutely harmless add-on.

Custom prologues have much bigger implications. For example, you must manage 'by hand' all those cases where you restore prologuedef because a proc required option prologue:none. That's a can of worms.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: HSE on March 06, 2020, 09:20:58 AM
Quote from: jj2007 on March 06, 2020, 07:18:23 AM
Inserting a macro on top, after the LOCALS, is a bit more involved.
Perhaps a little parser. :thumbsup:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 06, 2020, 10:32:03 PM
if you make a test.asm piece that is made up with calling every proc,mixed with INT3's and run in debugger and it would be possible to find the faulty PROC
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 07, 2020, 12:23:21 AM
Quote from: daydreamer on March 06, 2020, 10:32:03 PM
if you make a test.asm piece that is made up with calling every proc,mixed with INT3's and run in debugger and it would be possible to find the faulty PROC

Great advice, Magnus :thumbsup:

Can you post one of your major sources, so that we can test it?
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 07, 2020, 12:40:25 AM
What I am not sure about is what format you are working with, if its source code, you would list every CALL mnemonic which includes any variant of invoke and list the targets by their line number once you had the list. I gather you already have a technique to find the end of the procedure, even if it has multiple RET instructions in it. If you are dealing with binary format mnemonics you would basically be designing a dis-assembler.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 07, 2020, 12:52:00 AM
Hutch,
It's not source code, it's the executable:
MyStuff proc uses esi edi bla1 bla2
...
ret
MyStuff endp

MyStuff proc uses esi edi bla1 bla2
...
@MbRet  ; <<<<<<<<<<<<< it it's OFF, just a ret; if it's ON, call TESTWHATEVER, then ret
MyStuff endp
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 08, 2020, 02:51:42 AM
Quote from: jj2007 on March 07, 2020, 12:23:21 AM
Quote from: daydreamer on March 06, 2020, 10:32:03 PM
if you make a test.asm piece that is made up with calling every proc,mixed with INT3's and run in debugger and it would be possible to find the faulty PROC

Great advice, Magnus :thumbsup:

Can you post one of your major sources, so that we can test it?
maybe if I put together all PROC's I wrote in one file converted to MACROs? :smiley:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 08, 2020, 05:18:57 AM
Yes, go ahead, do that and post it here!
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: JK on March 11, 2020, 04:48:09 AM
Hi jj2007,


if i get this right, you want an automated test, if the stack is balanced, when you leave any kind of procedure. What about doing it the other way round ?

Save ESP before the procedure call (invoke ...) and test it afterwards. You could wrap invoke with a macro and add the test code inside this macro. The more, the procedure name is already there as a parameter - so it´s easy to output a meaningful debug message, and it´s easy to adapt existing code, just replace "invoke" with your new macro .
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 11, 2020, 04:56:00 PM
Quote from: JK on March 11, 2020, 04:48:09 AMSave ESP before the procedure call (invoke ...) and test it afterwards. You could wrap invoke with a macro

Hi JK,

Your idea is good but there are three problems:

1. many people do not invoke but push parameters manually (even I do that often)
2. when invoking procs that have a stack frame, your macro will not see the problem because esp is ok
3. when invoking procs that do have a stack frame, your macro will not be able to print the message because the return will be to no man's land.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 11, 2020, 10:02:04 PM
there is alternative to pushs/pops to save/restore general purpose registers,bigger opcodes(3bytes) to save/restore in SIMD registers,but doesnt mess up stack
there is fastcall convention as alternative to use stack together with invoke if its your own made PROC's
you use registers instead of stack for data
windows api call you need to stick to invoke/stack
if you only call the PROC from one place in the code,a MACRO version of that proc,would get rid of possibility of ret to "nomansland",but if you want to use it several times,its no good to use it 5 times,because that will insert it inline resulting in 5 times bigger code than one PROC
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 11, 2020, 10:15:23 PM
Great ideas, daydreamer. Post some examples, please. Code :cool:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 11, 2020, 10:50:56 PM
If its a test of the stack balance, that is in fact easy, allocate a variable then move ESP into it BEFORE you call the proc then display the variable in either a MessageBox or at the console.. After the proc has returned compare the two results, if they are the same, the stack is balanced, if not you have something to fix.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 11, 2020, 11:25:12 PM
Quote from: hutch-- on March 11, 2020, 10:50:56 PM
If its a test of the stack balance, that is in fact easy, allocate a variable then move ESP into it BEFORE you call the proc then display the variable in either a MessageBox or at the console.. After the proc has returned compare the two results, if they are the same, the stack is balanced, if not you have something to fix.

Apart from being a clumsy way to do that check: Most of the time the stack will be balanced even if you have a bug. The miraculous leave instruction balances the stack for you, and leaves subtle little problems such as esi edi ebx out of tune. Often there is no immediate crash, but it may bite you later. Thanks to @MbRet, I've identified three little problems in my editor - and it looked stable before, I work with it every day.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 12, 2020, 12:35:41 AM
This is what I don't understand what you are trying to do. At the minimum a proc with no stack frame has a start address and at one or more locations, it is exited by a RET. I still don't know if this is with a disassembly, parsed source code or assembled code. If you do the normal STDCALL preservation of registers, the stack increments by the size of the PUSH mnemonic up to the number of preserved registers.

I still don't know what you are trying to achieve.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 12, 2020, 02:51:47 AM
Quote from: jj2007 on March 11, 2020, 10:15:23 PM
Great ideas, daydreamer. Post some examples, please. Code :cool:
inspired by windows message proc handler switch,using readable constants instead of numbers
so far,same problem with unbalanced stack so I solved with commented out so I use eax instead(fastcall)
maincompos proc ; vers:DWORD
mov vers2,eax

lea ebx,cbuffer
mov eax,0
mov ecx,0
@@L1:
        mov [ebx+ecx*4],eax
     
     inc ecx
     cmp ecx,1000000
     jne @@L1
;mov ebx,esi
switch vers2 ;check if mul,SSE2,SSE,fpu,AVX version

case ordinary
    jmp @@v1
case sse2
    ;jmp SSE2vers
case sse
    ssem
case fpu
    ;jmp fpuvers
case avx
    jmp avxvers
endsw



gonna test conditional assembly on PROC's not needed when using MACRO version
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 12, 2020, 02:56:48 AM
I think he wanted code that actually worked.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 12, 2020, 09:14:28 AM
Quote from: hutch-- on March 12, 2020, 02:56:48 AM
I think he wanted code that actually worked.

Correct :tongue:

Quote from: hutch-- on March 12, 2020, 12:35:41 AMAt the minimum a proc with no stack frame has a start address and at one or more locations, it is exited by a RET. I still don't know if this is with a disassembly, parsed source code or assembled code.

It won't work with frameless procs, sorry. There is no way to do certain calculations:

My editor has about 200 procs, counted as "endp", full word search. About 130 have now instead of
ret
xxx endp

@MbRet
xxx endp

It's a simple Find & Replace action. What @MbRet does is:
- go back to the start of the proc
- check if there is a stack frame
- count the number of LOCALs allocated over the stack
- go back to the RET position
- count the number of POPs (mostly pop ebx, edi, esi from xxx proc uses esi edi ebx)
- calculated the expected esp
- shout foul if it doesn't coincide with the factual esp
- correct the stack if necessary, so that the uses work correctly
- do a quick check if the return address is in the .code section of your program
- print a line to the screen if it isn't (the program will crash but after that line)
- last but not least: insert a ret

In the testing phase, the program runs a tiny bit slower because of all those checks, and it adds some bloat. Once @MbRet stops printing error messages, you simply switch it off, and then all it does is insert the ret.

I have discovered three errors so far in the 200 procs and 20k lines of code. That is not much, but it was three bugs too many :cool:

P.S.: No MasmBasic needed :mrgreen:
P.P.S: Inspired by this thread, I've implemented a new function: find push or pop :cool:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 13, 2020, 12:28:55 AM
my point was to use registers instead of stack similar to 64bit mode does,Hutch probably has better example of 64bit using 4 general purpose registers and XMM0-XMM3 for floats
this thread inspired me to test conditional assembly together with MACRO version of PROC's
but I cant get it to work properly,when I want it to assemble
using one MACRO instead of PROC+
YESPROC=1 ;if assemble proc's or not
IFDEF (YESPROC)
...code
ENDIF
all unused PROC in .inc file is not assembled and results in more than -1k smaller exe
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 13, 2020, 01:10:50 AM
Zip it and post it, daydreamer. We are curious to see code - complete code.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: hutch-- on March 13, 2020, 01:33:26 AM
magnus,

In win32 you can do a simulated version of FASTCALL but you only have 3 registers you can use, EAX ECX & EDX. As win32 does not normally use the 3 available registers and only works with stack memory with STDCALL, you can use the 3 registers and put any others on the stack with the normal PUSH notation. Whether you will see any difference is another matter but it can be done.
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 15, 2020, 12:50:15 AM
Hutch,from Intel optimize manual,its alternative save/restore registers to SIMD registers and dont messup stack,but it takes opcode takes 3bytes instead of 1byte for push/pop
maybe good outside innerloop,but when unrolling inside innerloop maybe too many 3byte MOVD makes it too big to fit into cacheline
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 15, 2020, 02:52:25 AM
You attached code, daydreamer :thumbsup:

Can you explain where exactly you are testing your ideas?
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: daydreamer on March 15, 2020, 09:27:00 PM
Quote from: jj2007 on March 15, 2020, 02:52:25 AM
You attached code, daydreamer :thumbsup:

Can you explain where exactly you are testing your ideas?
MACRO versions only take place when used in code,PROC versions only need to be assembled if you want to use them instead of MACRO version,calling from several places,if use MACRO's instead IFDEF is used to avoid twice size of code =MACRO version+PROC version
also IFDEF can be used to reduce size not assemble PROC's that are never called
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 16, 2020, 11:58:48 AM
No, I meant examples from the source you posted. Where do you test your ideas, and how?
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: LiaoMi on March 17, 2020, 01:09:39 AM
Quote from: jj2007 on March 05, 2020, 01:40:24 PM
In the meantime, I found at least a method to recognise that a proc has no stack frame.

The idea is very simple: in a large source, replace every ret that is followed by somecode endp with @MbRet. It takes an optional argument that should be the name of the proc; if there is no argument, the source line will be shown instead (as in the CodeNoArgs example below).

If the source has stack problems, they will be ## flagged to the console ##, even if the exe was built as a Windows application.

There are basically three cases:
1. too many push instructions: @MbRet will tell you about it, and correct the stack so that at least the uses esi edi ebx works properly.

2. too many pop instructions: @MbRet will tell you about it, and correct the stack but one or more of the regs in the uses esi edi ebx list will be trashed anyway.

3. stack corruption: the return address is somewhere in nirwana land. @MbRet will inform you about it, but the program will crash anyway.

I've tested it with a 20k lines source, and so far I've found one bug with it, see first post above. @MbRet tests runtime behaviour, so its messages will pop up only when you are really using a proc. So for rarely used exotic functions it may take a while until you discover the bug.

Once you have verified that there are no problems, put @MbRet off below the include line, so that only an ordinary ret will be generated.

Here is a little demo with some procs that treat the stack badly (tested ok with WinXP, Win7-64 and Win10):

include \masm32\include\masm32rt.inc ; purest Masm32 SDK code
include MbRet.inc ; must be in the exe's folder
; @MbRet off ; switch it off once tests are OK

.code
TwoArgsNoLocals proc uses esi edi ebx mode, crashArg
  mov ebx, mode ; no Locals, but has args, and therefore a stack frame
  print "2 args: ebx="
  print str$(ebx), 13, 10
  .while sdword ptr ebx>=0
push eax ; stack imbalances will be flagged
dec ebx
  .Endw
  pop eax ; stack is balanced
  pop ecx ; for mode=3
  pop edx
  .if crashArg==99
mov dword ptr [ebp+4], 12345678h ; bad news for the return address ;-)
  .endif
  @MbRet 2ArgsNoLocals ; instead of the ret
TwoArgsNoLocals endp

ThreeArgsLocal123 proc uses ecx mode, arg2, arg3
Local buffer[123]:BYTE
  push eax ; stack not balanced, will be flagged
  @MbRet ThreeArgsLocal123
ThreeArgsLocal123 endp

CodeNoArgs proc uses esi edi ebx ecx ebp
  print "CodeNoArgs - cannot work with @MbRet: "
  ; push eax ; activate to produce a crash
  @MbRet ; no label -> line number 32; @MbRet will say "no frame found"
CodeNoArgs endp

start:
  cls
  m2m esi, 3
  mov ebx, 12345678h
  .Repeat
invoke TwoArgsNoLocals, esi, 123
print hex$(ebx), ": ebx after the invoke", 13, 10, 10
dec esi
  .Until Zero?
  invoke CodeNoArgs
  invoke ThreeArgsLocal123, 123, 456, 789
  inkey chr$(10, "hit any key for the stack corruption test:", 13, 10)
  invoke TwoArgsNoLocals, 2, 99
  MsgBox 0, "You won't see this box", "Hi", MB_OK
  invoke ExitProcess, 0
end start


The procs have little problems with a sloppy use of the push and pop instructions. Here is the output:
2 args: ebx=3
### MbRet 2ArgsNoLocals: stack is -4 bytes off, 1 push(es) too many ###
12345678: ebx after the invoke

2 args: ebx=2
12345678: ebx after the invoke

2 args: ebx=1
### MbRet 2ArgsNoLocals: stack is 4 bytes off, 1 pop(s) too many - check uses ###
0040107A: ebx after the invoke

CodeNoArgs - cannot work with @MbRet: ### MbRet 31: no stack frame found ###
### MbRet ThreeArgsLocal123: stack is -4 bytes off, 1 push(es) too many ###

hit any key for the stack corruption test:

2 args: ebx=2
### stack corruption? 2ArgsNoLocals: retaddr 12345678h is above the code segment ###


After the stack corruption test, it will produce an exception.

Hi jj2007,

this code does not work for me ..


0040104F                                    | C2 0800                    | RET     8                                                       |


0019FF64                                      0019FF80   


0019FF80                                    | DCFF                       | FDIV    ST(7), ST(0)                                            |
0019FF82                                    | 1900                       | SBB     DWORD PTR DS:[EAX], EAX                                 |
0019FF84                                    | 74 7B                      | JE      1A0001                                                  |


EAX : 00000002
EBX : 00000002
ECX : 00000002
EDX : 00000002
EBP : 00000003
ESP : 0019FF70
ESI : 00401076     <mbret4masm32.EntryPoint>
EDI : 12345678
EIP : 0019FF80
EFLAGS : 00000206     L'Ȇ'
ZF : 0
OF : 0     L'Ȁ'
CF : 0     L'Ā'
PF : 1
SF : 0
TF : 0     L'Ā'
AF : 0
DF : 0
IF : 1
LastError : 000036B7 (ERROR_SXS_KEY_NOT_FOUND)
LastStatus : C0150008 (STATUS_SXS_KEY_NOT_FOUND)
GS : 002B
ES : 002B
CS : 0023
FS : 0053
DS : 002B
SS : 002B     '+'
x87r0 : 00000000000000000000
x87r1 : 00000000000000000000
x87r2 : 00000000000000000000
x87r3 : 00000000000000000000
x87r4 : 00000000000000000000
x87r5 : 00000000000000000000
x87r6 : 00000000000000000000
x87r7 : 00000000000000000000
x87TagWord : FFFF
x87ControlWord : 027F     L'ɿ'
x87StatusWord : 0000
x87TW_0 : 3 (Empty)
x87TW_1 : 3 (Empty)
x87TW_2 : 3 (Empty)
x87TW_3 : 3 (Empty)
x87TW_4 : 3 (Empty)
x87TW_5 : 3 (Empty)
x87TW_6 : 3 (Empty)
x87TW_7 : 3 (Empty)
x87SW_B : 0
x87SW_C3 : 0
x87SW_TOP : 0 (ST0=x87r0)
x87SW_C2 : 0
x87SW_C1 : 0
x87SW_O : 0
x87SW_ES : 0
x87SW_SF : 0
x87SW_P : 0
x87SW_U : 0
x87SW_Z : 0
x87SW_D : 0
x87SW_I : 0
x87SW_C0 : 0
x87CW_IC : 0
x87CW_RC : 0 (Round Near)
x87CW_PC : 2 (Real8)
x87CW_PM : 1
x87CW_UM : 1
x87CW_OM : 1
x87CW_ZM : 1
x87CW_DM : 1     L'ā'
x87CW_IM : 1
MxCsr : 00001F80
MxCsr_FZ : 0
MxCsr_PM : 1
MxCsr_UM : 1
MxCsr_OM : 1
MxCsr_ZM : 1
MxCsr_IM : 1     L'ā'
MxCsr_DM : 1
MxCsr_DAZ : 0
MxCsr_PE : 0
MxCsr_UE : 0
MxCsr_OE : 0
MxCsr_ZE : 0
MxCsr_DE : 0
MxCsr_IE : 0
MxCsr_RC : 0 (Round Near)
MM0 : 0000000000000000
MM1 : 0000000000000000
MM2 : 0000000000000000
MM3 : 0000000000000000
MM4 : 0000000000000000
MM5 : 0000000000000000
MM6 : 0000000000000000
MM7 : 0000000000000000
XMM0  : 00000000000000000000000000000000
XMM1  : 00000000000000000000000000000000
XMM2  : 00000000000000000000000000000000
XMM3  : 00000000000000000000000000000000
XMM4  : 00000000000000000000000000000000
XMM5  : 00000000000000000000000000000000
XMM6  : 00000000000000000000000000000000
XMM7  : 00000000000000000000000000000000
YMM0  : 0000000000000000000000000000000000000000000000000000000000000000
YMM1  : 0000000000000000000000000000000000000000000000000000000000000000
YMM2  : 0000000000000000000000000000000000000000000000000000000000000000
YMM3  : 0000000000000000000000000000000000000000000000000000000000000000
YMM4  : 0000000000000000000000000000000000000000000000000000000000000000
YMM5  : 0000000000000000000000000000000000000000000000000000000000000000
YMM6  : 0000000000000000000000000000000000000000000000000000000000000000
YMM7  : 0000000000000000000000000000000000000000000000000000000000000000
DR0 : 00000000
DR1 : 00000000
DR2 : 00000000
DR3 : 00000000
DR6 : 00000000
DR7 : 00000000


INT3 breakpoint at mbret4masm32.0040104F (0040104F)!
EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 0019FF82
        NumberParameters: 2
ExceptionInformation[00]: 00000001 Write
ExceptionInformation[01]: 00000002 Inaccessible Address
First chance exception on 0019FF82 (C0000005, EXCEPTION_ACCESS_VIOLATION)!
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: jj2007 on March 17, 2020, 01:17:34 AM
Sorry, LiaoMi, I don't understand: what is not working? It doesn't assemble, or it crashes? Could you post a complete source please, so that I can check if there is a problem in my routine? Thanks :thup:
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: LiaoMi on March 17, 2020, 02:05:26 AM
Quote from: jj2007 on March 17, 2020, 01:17:34 AM
Sorry, LiaoMi, I don't understand: what is not working? It doesn't assemble, or it crashes? Could you post a complete source please, so that I can check if there is a problem in my routine? Thanks :thup:

Your finished example does not display messages like yours, instead, the program prints the first line and exits  :rolleyes:, after debugging, I showed the place where the crash occurs.

2 args: ebx=3 <- Exit
### MbRet 2ArgsNoLocals: stack is -4 bytes off, 1 push(es) too many ###
12345678: ebx after the invoke

2 args: ebx=2
12345678: ebx after the invoke

2 args: ebx=1
### MbRet 2ArgsNoLocals: stack is 4 bytes off, 1 pop(s) too many - check uses ###
0040107A: ebx after the invoke

CodeNoArgs - cannot work with @MbRet: ### MbRet 31: no stack frame found ###
### MbRet ThreeArgsLocal123: stack is -4 bytes off, 1 push(es) too many ###

hit any key for the stack corruption test:

2 args: ebx=2
### stack corruption? 2ArgsNoLocals: retaddr 12345678h is above the code segment ###
Title: Re: Debugging: how to recognise a no stack frame proc
Post by: LiaoMi on March 17, 2020, 08:34:54 AM
Quote from: jj2007 on March 06, 2020, 04:29:43 AM
What it cannot do so easily is find the start of the proc.

How to trace the call stack under x64 Windows? - https://stackoverflow.com/questions/18889376/how-to-trace-the-call-stack-under-x64-windows (https://stackoverflow.com/questions/18889376/how-to-trace-the-call-stack-under-x64-windows)
CaptureStackBackTrace function - https://docs.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace (https://docs.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace)
How to Log Stack Frames with Windows x64 - https://stackoverflow.com/questions/590160/how-to-log-stack-frames-with-windows-x64 (https://stackoverflow.com/questions/590160/how-to-log-stack-frames-with-windows-x64)

Fast capture stack trace on windows / 64-bit / mixed mode - https://exceptionshub.com/fast-capture-stack-trace-on-windows-64-bit-mixed-mode.html (https://exceptionshub.com/fast-capture-stack-trace-on-windows-64-bit-mixed-mode.html)
A Mixed-Mode Stackwalk with the IDebugClient Interface - https://www.codeproject.com/Articles/371137/A-Mixed-Mode-Stackwalk-with-the-IDebugClient-Inter (https://www.codeproject.com/Articles/371137/A-Mixed-Mode-Stackwalk-with-the-IDebugClient-Inter)
Walking the callstack - https://www.codeproject.com/Articles/11132/Walking-the-callstack-2 (https://www.codeproject.com/Articles/11132/Walking-the-callstack-2)

How To Get a Stack Trace on Windows - http://www.rioki.org/2017/01/09/windows_stacktrace.html (http://www.rioki.org/2017/01/09/windows_stacktrace.html)
(http://www.rioki.org/media/2017-01-09_stacktrace.png)
StackWalk function - https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-stackwalk?redirectedfrom=MSDN (https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-stackwalk?redirectedfrom=MSDN)

StackWatcher - https://www.ivanlef0u.tuxfamily.org/?p=6 (https://www.ivanlef0u.tuxfamily.org/?p=6)