What do the contents of the general purpose registers contain?

5

I included the iOS tag, but I'm running in the simulator on a Core i7 MacBook Pro (x86-64, right?), so I think that's immaterial.

I'm currently debugging a crash in Flurry's video ads. I have a breakpoint set on Objective-C exceptions. When the breakpoint is hit I am in objc_msgSend. The callstack contains a mix of private Flurry and iOS methods, nothing public and nothing that I've written. Calling register read from the objc_msgSend stack frame outputs the following:

(lldb) register read
General Purpose Registers:
       eax = 0x1ac082d0
       ebx = 0x009600b5  "spaceWillDismiss:interstitial:"
       ecx = 0x03e2cddb  "makeKeyAndVisible"
       edx = 0x0000003f
       edi = 0x0097c6f3  "removeWindow"
       esi = 0x00781e65  App`-[FlurryAdViewController removeWindow] + 12
       ebp = 0xbfffd608
       esp = 0xbfffd5e8
        ss = 0x00000023
    eflags = 0x00010202  App`-[FeedTableCell setupVisibleCommentAndLike] + 1778 at FeedTableCell.m:424
       eip = 0x049bd09b  libobjc.A.dylib`objc_msgSend + 15
        cs = 0x0000001b
        ds = 0x00000023
        es = 0x00000023
        fs = 0x00000000
        gs = 0x0000000f

I've got a few questions about this output.

  • I assumed $ebx contains the selector that caused the crash and $edi is the last executing method. Is that the case?
  • $eip is where I crashed. Is that usually the case?
  • $eflags references an instance method that, as far as I know, has nothing to do with this crash. What is that?
  • Is there any other information I can pry out of these registers?
ios
objective-c
macos
cpu-registers
asked on Stack Overflow Mar 4, 2013 by kubi

1 Answer

1

I can't speak to iOS/Objective-C frame layouts specifically, so I can't answer your question about EBX and EDI. But I can help you regarding EIP and EFLAGS and give you some general hints about ESP/EBP and the selector registers. (By the way, the simulator is simulating a 32-bit x86 environment; you can tell because your registers are 32 bits long.)

EIP is the instruction pointer register, also known as the program counter, which contains the address of the currently executing machine instruction. Thus it will point to where your program crashed, or more generally, where your program is when it hits a breakpoint, dumps core etc.

EIP is saved and restored to implement function calls (at the machine code level -- inlining may result in high-level language calls not performing actual calls). In memory-unsafe languages, a stack buffer overflow can overwrite the saved value of the instruction pointer, causing the return instruction to return to the wrong place. If you're lucky, the overwritten value will trigger a segfault on the next memory fetch, but the value of EIP will be arbitrary and unhelpful in debugging the problem. If you're unlucky, an attacker crafted the new EIP to point to useful code, so many environments use "stack cookies" or "canaries" to detect these overwrites before restoring the saved/overwritten EIP, in which case the EIP value may be useful.

EFLAGS isn't a memory address, and arguably isn't a general purpose register. Each bit of EFLAGS is a flag that can be set or tested by various instructions. The most important flags are the carry, zero and sign flags, which are set by arithmetic instructions and used for conditional branching. Your debugger is misinterpreting it as a memory address and displaying it as the closest function, but that isn't actually related to your crash. (The + 1778 is the giveaway: this means EFLAGS points 1778 bytes into the function, but the function is unlikely to actually be 1778 bytes long.)

ESP is the stack pointer and EBP is (usually) the frame pointer (also called the base pointer). These registers bound the current frame on the call stack. Your debugger usually can show you the values of stack variables and the current call stack based on these pointers. In case of corruption, sometimes you can manually inspect the stack to recover EBP and manually unwind the call stack. Note that code can be compiled without frame pointers (frame pointer omission), freeing EBP for other uses; this is common on x86 because there are so few general-purpose registers.

SS, CS, DS, ES, FS and GS hold segment selectors, used in the bad old days before paging to implement segmentation. Today FS and GS are commonly used by operating systems for process and thread state blocks; they were the only selector registers carried forward into x86-64. The selector registers are generally not helpful for debugging.

answered on Stack Overflow Oct 6, 2014 by Jeffrey Bosboom

User contributions licensed under CC BY-SA 3.0