Reputation: 1282
I'm developing an application that, at some point, must use a different stack, that will be managed by a library I developed. So, I call the initialization function of this library and the stack pointer ($sp) is set to the memory address I wanted.
When running this code via GDB, after the initialization of my other stack is done and execution returns to the caller function, GDB gives me this warning:
warning: GDB can't find the start of the function at 0x12.
GDB is unable to find the start of the function at 0x12
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
This problem is most likely caused by an invalid program counter or
stack pointer.
However, if you think GDB should simply search farther back
from 0x12 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.
Also, when printing the $sp, the old value is shown.
Since this part of the code performs correctly without GDB, and there is no function at 0x12, this happens because GDB uses the stack pointer to address to keep track of the function's frame.
Is there any way to avoid this behavior and be able to debug this application?
Upvotes: 4
Views: 1650
Reputation: 9315
this happens because GDB uses the stack pointer to address to keep track of the function's frame.
Yes, apparently it does:
get_frame_id in gdb_reader_funcs is to return a gdb_frame_id corresponding to the current frame. [...] One way to do this is by having the CODE_ADDRESS point to the function's first instruction and STACK_ADDRESS point to the value of the stack pointer when entering the function.
I guess one way to fix this would be to separate your code in two different functions (event if you simply jump between them).
Upvotes: 1
Reputation: 4727
I think what you need is GDB/Python's frame unwinding. I never used it myself, but frame unwinding is the (internal) process of reconstructing the process callstack.
As you mentioned, you alter $SP
value, so GDB doesn't recognize the standard calling conventions. Custom frame unwinders should let you teach GDB what stack layout you use.
Here is the example they provide in the documentation:
from gdb.unwinders import Unwinder
class FrameId(object):
def __init__(self, sp, pc):
self.sp = sp
self.pc = pc
class MyUnwinder(Unwinder):
def __init__(....):
super(MyUnwinder, self).__init___(<expects unwinder name argument>)
def __call__(pending_frame):
if not <we recognize frame>:
return None
# Create UnwindInfo. Usually the frame is identified by the stack
# pointer and the program counter.
sp = pending_frame.read_register(<SP number>)
pc = pending_frame.read_register(<PC number>)
unwind_info = pending_frame.create_unwind_info(FrameId(sp, pc))
# Find the values of the registers in the caller's frame and
# save them in the result:
unwind_info.add_saved_register(<register>, <value>)
....
# Return the result:
return unwind_info
As per the documentation, you can access the CPU registers with PendingFrame.read_register (reg_name or reg_id)
, but obviously, reading local variables might be a problem!
Once you unwinder is well built, it should be transparently integrated into GDB, and all the usual CLI mechanisms should be available.
Upvotes: 1