[Dwarf-Discuss] Stack tracing and return addresses off by 1

Jayvee Neumann jayvee.neumann@gmail.com
Fri Jul 31 12:37:06 GMT 2020


Hello together!

I am running into a problem while performing a stack trace of x86 code. The
assembly code I am running has been generated by mingw from C++ code and
looks like this:

6c9c1210 <__ZN7my_class9my_methodEs>:
6c9c1210: sub    $0x1c,%esp
6c9c1213: mov    0x20(%esp),%edx
6c9c1217: mov    %edx,%eax
6c9c1219: test   %dx,%dx
6c9c121c: jle    6c9c1221 <__ZN7my_class9my_methodEs+0x11>
6c9c121e: lea    0x1(%edx),%eax
6c9c1221: cwtl
6c9c1222: mov    %eax,(%esp)
6c9c1225: call   6c9c1190 <__Z12my_dummy_functions>
6c9c122a: add    $0x1c,%esp
6c9c122d: ret    $0x4

6c9c1230 <__ZN8my_struct9my_methodEv>:
6c9c1230: sub    $0x1c,%esp
6c9c1233: movzwl 0x4(%ecx),%eax
6c9c1237: test   %ax,%ax
6c9c123a: jle    6c9c1241 <__ZN8my_struct9my_methodEv+0x11>
6c9c123c: add    $0x1,%eax
6c9c123f: jmp    6c9c1246 <__ZN8my_struct9my_methodEv+0x16>
6c9c1241: mov    $0x0,%eax
6c9c1246: cwtl
6c9c1247: add    $0x8,%ecx
6c9c124a: mov    %eax,(%esp)
6c9c124d: call   6c9c1210 <__ZN7my_class9my_methodEs>
6c9c1252: sub    $0x4,%esp
6c9c1255: add    $0x1c,%esp
6c9c1258: ret
6c9c1259: nop
6c9c125a: lea    0x0(%esi),%esi

The problem manifests itself, when the instruction pointer is inside "
__ZN7my_class9my_methodEs" (called at 0x6c9c124d).

In order to perform the stack trace, I use the DWARF frame information for
calculating the previous instruction pointer. This is done by assuming the
return address is the instruction pointer of the previous frame. This is
obviously not entirely correct, since the return address points to a
location AFTER the previous call. Nevertheless, this assumption seems to be
standard for other stack tracers.

I am having a problem with this though:
The address where I start is 0x6c9c121e. Frame information tells me the
following:

00000144 0000001c 00000000 FDE cie=00000000 pc=6c9c1210...6c9c1230
  DW_CFA_advance_loc4: 3
  DW_CFA_def_cfa_offset: +32
  DW_CFA_advance_loc4: 26
  DW_CFA_def_cfa_offset: +4
  DW_CFA_nop:
  DW_CFA_nop:

So the CFA offset is 32. There I find the next return address 0x6c9c124d.
Frame information tells me the following:

00000164 00000028 00000000 FDE cie=00000000 pc=6c9c1230...6c9c1259
  DW_CFA_advance_loc4: 3
  DW_CFA_def_cfa_offset: +32
  DW_CFA_advance_loc4: 31
  DW_CFA_def_cfa_offset: +28
  DW_CFA_advance_loc4: 3
  DW_CFA_def_cfa_offset: +32
  DW_CFA_advance_loc4: 3
  DW_CFA_def_cfa_offset: +4

And here the problem arises. Due to 0x6c9c124d being the return address,
the CFA offset I read is invalid. By assuming an instruction pointer of
0x6c9c124d I also assume that the "ret $0x4" instruction from 0x6c9c122d
has been executed and the stack is 4 bytes shorter. This is however not the
case. The return has not been executed yet.

So my question here is, how shall the stack tracer solve this issue? My
first Idea is to decrement the instruction pointer when looking through the
frame information (except for the deepest frame, where the instruction
pointer is correct). Would that be an approach that works always? How do
other consumers solve this issue?

Best regards
Jayvee
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.dwarfstd.org/pipermail/dwarf-discuss-dwarfstd.org/attachments/20200731/8f8f2827/attachment-0001.html>



More information about the Dwarf-discuss mailing list