Search code examples
stackstack-tracegoogle-breakpad

Stack trace: stack scanning vs call frame vs given as instruction pointer in context


I'm using breakpad in my project to handle crashes and generate stack trace. In stack trace, there are different ways how function calls info found by stackwalker. Process described here Finding_the_caller_frame:

  • Found by: stack scanning
  • Found by: call frame info
  • Found by: given as instruction pointer in context

What`s the difference between them? And more importantly how they could help in terms of debugging?

Thread 0 (crashed)
  0  test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4]
      r4 = 0x00015530    r5 = 0xbea2cbe4    r6 = 0xffffff38    r7 = 0xbea2cb5c
      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
      sp = 0xbea2cb50    lr = 0x00009025    pc = 0x00008f84
     Found by: given as instruction pointer in context
  1  test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3]
      r4 = 0x00015530    r5 = 0xbea2cbe4    r6 = 0xffffff38    r7 = 0xbea2cb5c
      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
      sp = 0xbea2cb50    pc = 0x00009025
     Found by: call frame info
  2  libc.so + 0x164e5
      r4 = 0x00008f64    r5 = 0xbea2cc34    r6 = 0x00000001    r7 = 0xbea2cc3c
      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
      sp = 0xbea2cc18    pc = 0x400c34e7
     Found by: call frame info

Solution

  • The instruction pointer method means that there's a CPU register already pointing at the function's memory location so there was no need to search for the function. This is the easiest and most reliable way to find the current stack frame.

    Next using the call frame technique you can find the caller of the current function by looking at the place in stack memory where the return address is stored. This is the exact technique that a "return" would use to find its return destination. This technique can be chained because each previous call also put its return value on the stack. This is pretty reliable, but can fail if some stack memory got corrupted (maybe stack overflow, maybe buggy pointer write) and one or more return addresses were obliterated.

    Finally the least reliable technique is to just search the stack memory for anything that looks like a function address. This can help you recover from a corrupted stack but it can be hard to tell data (including function pointers!) apart from function addresses so it's guesswork. If you find one, though, you can often then chain back to the call frame technique if you find some stack that wasn't trashed.