GDB backtrace :Find total number of frame - gdb

I am trying to find the start and end of stack using macro from a core file. To accomplish the same I am trying to find the esp value from last and first frame . Difference of the same will give me the stack size in use.
Do we have a way to find number of frames in the stack?
bt give me all the frame . from frame 0 i can find the top of the stack?
do we have a way to find the last frame number ?
Do do we have another way to find the start of the stack and end of the stack ?
Thanks

You can find the frame number of the outermost frame using bt -1:
(gdb) bt -1
#9 0x0000000000464c45 in main (argc=<optimized out>, argv=<optimized out>)
at ../../binutils-gdb/gdb/gdb.c:32
You can see that the outermost frame is #9.
However, scripting this is a bit of a pain. For example, you can't use frame -1 to select that frame.
At this point you have two options.
One option is to use the gdb Python API to iterate over frames and do whatever you like. This is the simplest route, if it is available to you. The Python API is documented and easy to use; in this case you will mostly be interested in the gdb.Frame code.
If you can't use Python, you can use the traditional, horrible gdb hack of using set logging to write the output of bt -1 to a file; then shell to rewrite the contents of this file to be a valid gdb command (like frame 9); and finally source the resulting transformed file.

Related

What is GDB's "here"?

I am trying to troubleshoot a bus error with some inline SSE2 assembly. The source code has a macro that uses 5 pointers, and I suspect one of them is not aligned.
I set a breakpoint on the source line. But when I perform a disass, it disassembles from the top of the function, and not where the debugger is stopped. There are hundreds of lines of assembly, so its not really helpful to me. Pressing ENTER 30 to 40 times in response to "Press ENTER to continue" got old very quickly.
I tried a disass $pc, but it dsassembled from the top of the function. I also tried a disass . (with the dot meaning "here"), but that resulted in:
A syntax error in expression, near `.'.
What does GDB use to denote "here"?
You were correct with the use of $pc to represent the current location. The reason that this did not do what you expected when used with the disassemble command is that the disassemble command tries by default to disassemble the function containing the given address which is what you are seeing.
There are alternative forms that can be given to disassemble, for example start,end where start and end are addresses, or start,+length where start is an address and length is a number of bytes.
Try help disassemble at the gdb prompt for more information.
As an alternative you can also use the x (examine) command to display instructions, without the smart find the beginning of the function behaviour, so x/10i $pc will display 10 instructions starting from $pc. This can be helpful if you only want the instructions disassembled, however you don't have access to the /m or /r modifiers that are available on the disassemble command. These modifiers display interleaved source and assembler (for /m) or the raw instruction bytes (for /r).
Also, if the whole press ENTER to continue thing is getting old then you can try set height 0 to turn off the pager, do make sure that you have enough scroll back in your terminal though :)

GDB: How to check current line number during debug

How do I check the current line number that I'm stopped in when debugging with GDB? I would have thought this would be obvious (and maybe it is) but I don't see it on the GDB Cheat Sheet.
Some digging around revealed the following methods:
frame: This command was exactly what I was looking for. Output looked as follows:
(gdb) frame
#0 MyDialog::on_saveButton_clicked (this=0x72bf9e0) at src/ui/dialog/MyDialog.cxx:86
86 _item->save();
(gdb)
where or bt (same effect): This prints out the call stack, ending on the current line.
list *$pc: This doesn't tell you the exact line but it prints out the surrounding lines with the current line in the center.
x/i $eip
eip(rip) points to the next instruction

How can I use GDB to get the length of an instruction?

The problem I am trying to solve is that I want to dynamically compute the length of an instruction given its address (from within GDB) and set that length as the value of a variable. The challenge is that I don't want any extraneous output printed to the console (e.g. disassembled instructions, etc.).
My normal approach to this is to do x/2i ADDR, then subtract the two addresses. I would like to achieve the same thing automatically; however, I don't want anything printed to the console. If I could disable console output then I would be able to do this by doing x/2i ADDR, followed by $_ - ADDR.
I have not found a way to disable the output of a command in GDB. If you know such a way then please tell me! However, I have discovered interpreter-exec and GDB/MI. A quick test shows that doing x/2i works on GDB/MI, and the value of $_ computed by the MI interpreter is shared with the console interpreter. Unfortunately, this approach also spits out a lot of output.
Does anyone know a way to either calculate the length of an instruction without displaying anything, or how to disable the output of interpreter-exec, thus allowing me to achieve my goal? Thank you.
I'll give an arguably cleaner and more extensible solution that's not really shorter. It implements $instn_length() as a new GDB convenience function.
Save this to instn-length.py
import gdb
def instn_length(addr_expr):
t = gdb.execute('x/2i ' + addr_expr, to_string=True)
return long(gdb.parse_and_eval('$_')) - long(gdb.parse_and_eval(addr_expr))
class InstnLength(gdb.Function):
def __init__(self):
super(InstnLength, self).__init__('instn_length')
def invoke(self, addr):
return instn_length(str(long(addr)))
InstnLength()
Then run
$ gdb -q -x instn-length.py /bin/true
Reading symbols from /usr/bin/true...Reading symbols from /usr/lib/debug/usr/bin/true.debug...done.
done.
(gdb) start
Temporary breakpoint 1 at 0x4014c0: file true.c, line 59.
Starting program: /usr/bin/true
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffde28) at true.c:59
59 if (argc == 2)
(gdb) p $instn_length($pc)
$1 = 3
(gdb) disassemble /r $pc, $pc + 4
Dump of assembler code from 0x4014c0 to 0x4014c4:
An alternative implementation of instn_length() is to use the gdb.Architecture.disassemble() method in GDB 7.6+:
def instn_length(addr_expr):
addr = long(gdb.parse_and_eval(addr_expr))
arch = gdb.selected_frame().architecture()
return arch.disassemble(addr)[0]['length']
I have found a suitable solution; however, shorter solutions would be preferred. This solution sets a logging file to /dev/null, sets to to be overridden if it exists, and then redirects the console output to the log file temporarily.
define get-in-length
set logging file /dev/null
set logging overwrite on
set logging redirect on
set logging on
x/2i $arg0
set logging off
set logging redirect off
set logging overwrite off
set $_in_length = ((unsigned long) $_) - ((unsigned long) $arg0)
end
This solution was heavily inspired by another question's answer: How to get my program name in GDB when writting a "define" script?.

Linux Kernel Text Symbols

When I look through a linux kernel OOPS output, the EIP and other code address have values in the range of 0xC01-----. In my System.map and objdump -S vmlinux output, all the code addresses are at least above 0xC1------. My vmlinux has debug symbols included (CONFIG_DEBUG_INFO).
When I debug over a serial connection (kgdb), and I load gdb with gdb ./vmlinux, again I have the same issue that I cannot reconcile $eip with what I have in System.map and objdump output. When I run where in gdb, I get a jumbled mess on the stack:
#0 0xC01----- in ?? ()
#1 0xC01----- in ?? ()
#2 0xC01----- in ?? ()
...
Can anyone make any suggestions on how to resolve this/these issues? My main concern is how I actually map an eip value from an OOPS to System.map or objdump -S vmlinux. I know that the OOPS will give me the function name and offset into the object code, but I am more concerned about the previously mentioned issue and why gdb can't correctly display a stack backtrace.
Looks like the OOPS is because you jumped into a place that's not a function.
This would easily cause a crash, and would also prevent the debugger from resolving the address as a symbol.
You can check this by disassembling the area around this EIP. If I'm correct, it won't make sense as machine code.
There are generally two causes for such things:
1. Function call using a corrupt function pointer. In this case, the stack frame before the last should show the caller. But you don't have this frame, so it may be the other reason.
2. Stack overrun - your return address is corrupt, so you've returned to a bad location. If it's so, the data ESP points to should contain the address in EIP. Debugging stack overruns is hard, because the most important source of information is missing. You can try to print the stack in "raw" format (x/xa addr), and try to make sense of it.

Analyze Core Dump

We have a binary that generates coredump. So I ran the gdb command to analyze the issue. Please note the binary and code are in two different locations and we cannot build the whole binary using debugging symbols. Hence how and what details can I find from below backtarce:
gdb binary corefile
(gdb) where
#0 0x101fa37a in f1()
#1 0x10203812 in operator f2< ()
#2 0x085f6244 in f3 ()
#3 0x085f1574 in f4()
#4 0x0805b27b in sigsegv_handler ()
#5 <signal handler called>
#6 0x1018d945 in f5()
#7 0x1018e021 in f6()
..................................
#29 0x08055c5c in main ()
(gdb)
Please provide me gdb commands that I can issue to find what’s data inside each stack frame, what’s the issue probably is, where it is failing, other debugging methods if any?
You can use help in gdb. To navigate the stack : help stack
The main useful commands to navigate the stack are up and down. If you have debugging symbols at hand, you can use list to see where you are. Then to get information, you need print (abbreviated as 'p'). For example, if you have an int called myInt then you just type p myInt. With no debug info it will be harder. From your stack frame it seems that the problem is in f5(). One thing you can do is start your program inside gdb. it will stop right where the segfault happens. When you have hints about the part of your code that segfaults, you can compile this code unit with debugging options.
That the basics. Tell us more if you want more help.
my2c