0

So here's the deal. I am working on a debugger using a pin tool and the dwarf info from the process that I am attaching to. Pin is a framework that lets you create instrumentation tools for processes that are already running, I attach to the process and then I parse the DWARF info from it.

Obviously, pin let me grab the registers in the precise moment on where I attach to the program. I am able to get ebp, esp, and eip. But the information from the stack doesn't match the information from the DWARF info.

For example:

Pin tells me that ebp is: bfe0abe8 I assume this is the actual address of the register and not the value that is inside of it.

If I go to the stack I have this:

bfe0abb5 -> 00000020   \\this is esp
bfe0abb6 -> 0804855d
bfe0abb7 -> 08048720
bfe0abb8 -> 0000000a
bfe0abb9 -> bfe0abe8    \\this is what I think is ebp, but according to pin is not
bfe0abba -> 0015711f
bfe0abbb -> bfe0ac28
bfe0abbc -> 4236b852     \\this is a local float variable named jos
bfe0abbd -> 42c0947b     \\this is a local float variable named tib
bfe0abbe -> 0000000a
bfe0abbf -> 08048724
bfe0abc0 -> bfe0abf8
bfe0abc1 -> bfe0ac28
bfe0abc2 -> 08048612
bfe0abc3 -> 00000000
bfe0abc4 -> 0000000a
bfe0abc5 -> 00006680
bfe0abc6 -> 08048689
bfe0abc7 -> 00266324
bfe0abc8 -> 00265ff4
bfe0abc9 -> 936498a8
bfe0abca -> 4072464d
bfe0abcb -> 0013f4a5
bfe0abcc -> 424ab852    \\this is another local variable
bfe0abcd -> 42bc947b    \\this is another local variable
bfe0abce -> 0000000a
bfe0abcf -> 08048670
bfe0abd0 -> 00000000
bfe0abd1 -> bfe0aca8

And a lot more, I don't know what is actually the bottom of the stack, so I am showing just a bit of it.

If I go to the DWARF info, this is the function that the top of the stack is currently in, and which ebp should be pointing to:

<1><  962>  DW_TAG_subprogram
    DW_AT_external              yes(1)
    DW_AT_name                  add
    DW_AT_decl_line             36
    DW_AT_prototyped            yes(1)
    DW_AT_low_pc                0x8048513
    DW_AT_high_pc               0x804855f
    DW_AT_frame_base            <loclist with 3 entries follows>
        [ 0]<lowpc=0x2f><highpc=0x30>DW_OP_breg4+4
        [ 1]<lowpc=0x30><highpc=0x32>DW_OP_breg4+8
        [ 2]<lowpc=0x32><highpc=0x7b>DW_OP_breg5+8

I know this because the local variables that I see on the stack are inside this function. These local variables are:

 <2>< 1029> DW_TAG_variable
    DW_AT_name                  tib
    DW_AT_decl_line             38
    DW_AT_type                  <837>
    DW_AT_location              DW_OP_fbreg -24
 <2>< 1043> DW_TAG_variable
    DW_AT_name                  jos
    DW_AT_decl_line             39
    DW_AT_type                  <837>
    DW_AT_location              DW_OP_fbreg -28

I know that according to DWARF (and this: How to see variables stored on the stack with GDB), ebp in this function should be the current ebp + 8 (which because I am working with DWORD should be +2). And then I should subtract -24 to 8, making it ebp-16 (ebp-4 in reality). On paper this should work, but when going to the stack I am encountering a lot of problems:

  • I am not even seeing near the top of the stack the address of the current ebp that pin is returning to me.
  • Assuming that bfe0abb9 is the current ebp and that pin is actually returning the value, and not the address, of the register if I subtract 4 from that register I would not be getting the value of tib, since as my understanding of the stack, I would be going up not down. And even if I would be going down when trying to get jos (ebp-28+8 = ebp -20 = ebp -5) I would definitely not be getting jos but 000000a.

Am I missing something here? Am I having a wrong understanding of the stack and/or registers or DWARF info? Or is Pin screwing me up and giving the wrong information?

Any suggestions?

Community
  • 1
  • 1
attis
  • 171
  • 1
  • 4
  • 16
  • I think you're missing something (or I'm completely misunderstanding you). Registers don't HAVE addresses -- they contain values (that might be addresses). Each address really only refers to a single byte -- when we speak of the 32-bit word at address X, we really mean the bytes at X, X+1, X+2, and X+3 combined into a word. So your dump of the stack above makes no sense... – Chris Dodd Nov 14 '12 at 01:07
  • But my understanding is that each register also has a an address in the `bf...` space, and by dereferencing that address I would get the actual value inside the register @ChrisDodd – attis Nov 14 '12 at 02:09

2 Answers2

1

I'll ignore the stack dump because I'm not sure what you're trying to show there.

The DWARF you've cited says that the frame base of the function is initially $esp + 4, then it changes to $esp + 8, then it changes to $ebp + 8. That's the standard "push $ebp; mov $esp, $ebp" instruction sequence that opens most i386 functions. On function entry the frame base is the value of esp plus 4. Once we've saved the caller's ebp register on the stack, the frame base is now esp plus 8 because esp has changed thanks to the push. Finally the value in esp is copied into ebp and that value will remain unchanged for the rest of the function (while esp is further adjusted, typically).

What you're seeing here -- the "frame base" -- is also referred to as the Canonical Frame Address or CFA in the debug_frame section. The CFA is an address on the stack that is the same for the entire duration of the function. On i386, the CFA address is the caller's esp value before it executes the call instruction to call the function you're looking at.

The DWARF says that the variable tib is found at the frame base -24. The frame base for your function is ebp + 8 so yes, the value of the ebp register, minus 16, is an address on the stack. The variable is stored at that address.

I often find it helpful to read the actual assembly code for your function if the DWARF is unclear, assuming you have a reasonable understanding of assembly language. You can also single instruction step through your program, examining the registers and stack addresses as you progress through it. A small amount of hands-on experimentation with real code can almost always answer any questions.

Jason Molenda
  • 14,835
  • 1
  • 59
  • 61
  • Hey, I figured the exact same thing yesterday, and it is giving me the correct variables now. That was not the correct stack, I was going through the stack 4 bytes at a time and treating each address as a DWORD, later figured out that the address is just a byte and 4 addresses make the DWORD. I am not too familiar with assembly language, that is why I am having so much troubles. I have a final question for you, why is my pin tool giving me ebp as a value that is way below esp in the stack? I thought that pin would give the last ebp hence an address near the top of the stack.. @JasonMolenda – attis Nov 15 '12 at 18:59
  • 1
    In x86 the stack moves downward so once the function prologue instructions have executed, the `ebp` register value will be higher than, or equal to, the `esp` register value. I don't know anything about this pin tool you're using or how it behaves or shows you information. i386 functions are not required to set up an `ebp` register - it is legal for a function to just use `esp` for its stack frame although this can make backtracing more difficult for debuggers so it is uncommon. – Jason Molenda Nov 15 '12 at 20:29
  • I think my question is: I need to -- pretty much -- parse the stack in some sense. The problem is that I need the ebp closest to the stack and then dereference it to get the next ebp, and then dereference that ebp and so on. That way I can work with the ebp register and add or subtract according to DWARF. The question is, is there any way to do this by just having the DWARF info and esp? Or do I also need what is considered to be ebp in the program so I can do the recursive calling of ebp's trace? @JasonMolenda – attis Nov 15 '12 at 21:36
0

It is weird because it is not like a stack addressing, bfe0abb5, bfe0abb6, bfe0abb7, bfe0abb8, bfe0abb9, bfe0abba, ....
It should be in 4-byte alignment in 32-bit machine. Based on the stack address you provided, I also cannot calculate the real address even you gave the correct DWARF information.

jclin
  • 2,449
  • 1
  • 21
  • 27