As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Can you post your most tricky and useful commands while you run a debugger like gdb or dbx.
backtrace full: Complete backtrace with local variables
up, down, frame: Move through frames
watch: Suspend the process when a certain condition is met
set print pretty on: Prints out prettily formatted C source code
set logging on: Log debugging session to show to others for support
set print array on: Pretty array printing
finish: Continue till end of function
enable and disable: Enable/disable breakpoints
tbreak: Break once, and then remove the breakpoint
where: Line number currently being executed
info locals: View all local variables
info args: View all function arguments
list: view source
rbreak: break on function matching regular expression
Start gdb with a textual user interface
gdb -tui
Starting in gdb 7.0, there is reversible debugging, so your new favourite commands are:
* reverse-continue ('rc') -- Continue program being debugged but run it in reverse
* reverse-finish -- Execute backward until just before the selected stack frame is called
* reverse-next ('rn') -- Step program backward, proceeding through subroutine calls.
* reverse-nexti ('rni') -- Step backward one instruction, but proceed through called subroutines.
* reverse-step ('rs') -- Step program backward until it reaches the beginning of a previous source line
* reverse-stepi -- Step backward exactly one instruction
* set exec-direction (forward/reverse) -- Set direction of execution.
Instead of launching GDB with "-tui" param you can also switch to text mode after a while using by typing "wh".
thread apply all bt or thread apply all print $pc: For finding out quickly what all threads are doing.
For example the macros defined in stl-views.gdb
scripting gdb is a good trick, other than that I like
set scheduler locking on / off to prevent the running of other threads when you are stepping in one.
Using the -command=<file with gdb commands> option while firing up gdb. Same as -x <command file>. This command file can contain gdb commands like breakpoints, options, etc. Useful in case a particular executable needs to be put through successive debug runs using gdb.
Using .gdbinit (start up file where you can write macros and call from gdb). Place .gdbinit in your home directory so that it is picked up every time gdb is loaded
info threads to list all the active threads, and f(#) -> # thread number you want to switch to
sometime i use gdb to convert from hex to decimal or binary, its very handy instead of opening up a calculator
p/d 0x10 -> gives decimal equivalent of 0x10
p/t 0x10 -> binary equivalent of 0x10
p/x 256 -> hex equivalent of 256
Instead of starting gdb with the option -tui to see a child process that contains a screen that highlights where the executing line of code is in your program, jump in and out of this feature with C-x o and C-x a. This is useful if you're using the feature and what to temporarily not use it so you can use the up-arrow to get a previous command.
This can be useful, I am sure it could be improved though, help welcome:
define mallocinfo
set $__f = fopen("/dev/tty", "w")
call malloc_info(0, $__f)
call fclose($__f)
To debug STL, add content to .gdbinit, follow these instructions:
http://www.yolinux.com/TUTORIALS/GDB-Commands.html#STLDEREF
Related
We're learning to use GDB in my Computer Architecture class. To do this we do most of our work by using SSH to connect to a raspberry pi. When running GDB on some code he gave us to debug though it ends with an error message on how it can't find raise.c
I've tried:
installing libc6, libc6-dbg (says they're already up-to-date)
apt-get source glibc (gives me: "You must put some 'source' URIs in your sources.list")
https://stackoverflow.com/a/48287761/12015458 (apt source returns same thing as the apt-get source above, the "find $PWD" command the user gave returns nothing)
I've tried looking for it manually where told it may be? (/lib/libc doesn't exist for me)
This is the code he gave us to try debugging on GDB:
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
However, whenever I run the code in GDB I get the following error:
Program received signal SIGFPE, Arithmetic exception.
__GI_raise (sig=8) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
I asked him about it and he didn't really have any ideas on how to fix it.
It does not really matter that the source for raise() is not found. It would only show you the line where the exception is finally raised, but not the place where the error is triggered.
Run the erroneous program again in GDB. And when the exception is raised, investigate the call stack and the stackframes with GBDs commands. This is the point in your task, so I won't give you more than this hint.
If you're clever you can see the error in the given source just by looking at it. ;-)
When GDB does not know any symbol, you need to compile with the option -g to get debugger support.
EDIT
Now on a Windows system this is my log (please excuse the colouring, I didn't found a language selector for pure text):
D:\tmp\StackOverflow\so_027 > type crash1.c
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
D:\tmp\StackOverflow\so_027 > gcc crash1.c -g -o crash1.out
crash1.c:2:1: warning: return type defaults to 'int' [-Wimplicit-int]
main()
^~~~
D:\tmp\StackOverflow\so_027 > dir
[...cut...]
04.09.2019 08:33 144 crash1.c
04.09.2019 08:40 54.716 crash1.out
D:\tmp\StackOverflow\so_027 > gdb crash1.out
GNU gdb (GDB) 8.1
[...cut...]
This GDB was configured as "x86_64-w64-mingw32".
[...cut...]
Reading symbols from crash1.out...done.
(gdb) run
Starting program: D:\tmp\StackOverflow\so_027\crash1.out
[New Thread 4520.0x28b8]
[New Thread 4520.0x33f0]
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) backtrace
#0 0x0000000000401571 in main () at crash1.c:7
(gdb) help stack
Examining the stack.
The stack is made up of stack frames. Gdb assigns numbers to stack frames
counting from zero for the innermost (currently executing) frame.
At any time gdb identifies one frame as the "selected" frame.
Variable lookups are done with respect to the selected frame.
When the program being debugged stops, gdb selects the innermost frame.
The commands below can be used to select other frames by number or address.
List of commands:
backtrace -- Print backtrace of all stack frames
bt -- Print backtrace of all stack frames
down -- Select and print stack frame called by this one
frame -- Select and print a stack frame
return -- Make selected stack frame return to its caller
select-frame -- Select a stack frame without printing anything
up -- Select and print stack frame that called this one
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
(gdb) next
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) next
[Inferior 1 (process 4520) exited with code 030000000224]
(gdb) next
The program is not being run.
(gdb) quit
D:\tmp\StackOverflow\so_027 >
Well, it marks directly the erroneous source line. That is different to your environment as you use a Raspi. However, it shows you some GDB commands to try.
Concerning your video:
It is clear that inside raise() you can't access x. That's why GDB moans about it.
If an exception is raised usually the program is about to quit. So there is no value in stepping forward.
Instead, as shown in my log, use GDB commands to investigate the stack frames. I think this is the issue you are about to learn.
BTW, do you know that you should be able to copy the screen content? This will make reading so much easier for us.
From a practical standpoint the other answer is correct, but if you do want the libc sources:
apt-get source is the right way to get the sources of libc, but yes, you do need to have source repositories configured in /etc/apt/sources.list.
If you're using Ubuntu, see the deb-src lines in https://help.ubuntu.com/community/Repositories/CommandLine
For debian, see https://wiki.debian.org/SourcesList#Example_sources.list
Then apt-get source should work. Remember to tell GDB where those sources are using the "directory" command.
I had a program that was segfaulting.
When I went to investigate and ran dmesg I could see lines like this:
[955.915050] traps: foo_bar[123] general protection ip:7f5fcc2d4306 sp:7ffd9e5868b8 ...
Now the program has been fixed and I'm trying to write some analysis scripts across different systems to find similar messages and was hoping to induce a line in the dmesg log to get a baseline for what to look for and see if there's a difference between, say, a sigbus(10) and a sigill(4)
I tried to do it via kill -11 on the command line . No entry in dmesg
I tried to do it via signal(getpid(), 11) in the code. No entry in dmesg
I tried to do it via signal 11 after attaching in gdb . No entry in dmesg
I tried to do it via writing bad code and it worked for SEGV, but I can't figure out how to trigger a SIGBUS (for example)
I'm guessing that there is more than one path for handling the signal depending on how it occurs and my attempts above just aren't doing it the right way.
How can I trigger/send a signal to my program that'll get a line in dmesg? Is there some kernel or log configuration I can twiddle to get those lines?
Update:
" __builtin_trap: when to use it? " shows how to get a SIGILL but alas doesn't have a signal-agnostic solution)
I am working on Pintos OS project. I get this message:
Page fault at 0xbfffefe0: not present error writing page in user context.
The problem with Pintos OS project is that it won't simply tell the line and method that caused the exception.
I know how to use breakpoints/watchpoints etc. but is there any way to step right to it without going through the WHOLE flow and ALL OS files line by line so that I could jump into line that caused exception and put breakpoint there? I looked at GDB commands but didn't find anything.
When I debug this project I have to step through the whole program until I find that error/exception which is very time consuming. There is probably a faster way to do this.
Thanks.
Whole trace:
nestilll#vdebian:~/Class/pintos/proj-3-bhling-nestilll-nsren/src/vm/build$ pintos -v -k -T 60 --qemu --gdb --filesys-size=2 -p tests/vm/pt-grow-pusha -a pt-grow-pusha --swap-size=4 -- -q -f run pt-grow-pusha
Use of literal control characters in variable names is deprecated at /home/nestilll/Class/pintos/src/utils/pintos line 909.
Prototype mismatch: sub main::SIGVTALRM () vs none at /home/nestilll/Class/pintos/src/utils/pintos line 933.
Constant subroutine SIGVTALRM redefined at /home/nestilll/Class/pintos/src/utils/pintos line 925.
warning: disabling timeout with --gdb
Copying tests/vm/pt-grow-pusha to scratch partition...
qemu -hda /tmp/N2JbACdqyV.dsk -m 4 -net none -nographic -s -S
PiLo hda1
Loading............
Kernel command line: -q -f extract run pt-grow-pusha
Pintos booting with 4,088 kB RAM...
382 pages available in kernel pool.
382 pages available in user pool.
Calibrating timer... 419,020,800 loops/s.
hda: 13,104 sectors (6 MB), model "QM00001", serial "QEMU HARDDISK"
hda1: 205 sectors (102 kB), Pintos OS kernel (20)
hda2: 4,096 sectors (2 MB), Pintos file system (21)
hda3: 98 sectors (49 kB), Pintos scratch (22)
hda4: 8,192 sectors (4 MB), Pintos swap (23)
filesys: using hda2
scratch: using hda3
swap: using hda4
Formatting file system...done.
Boot complete.
Extracting ustar archive from scratch device into file system...
Putting 'pt-grow-pusha' into the file system...
Erasing ustar archive...
Executing 'pt-grow-pusha':
(pt-grow-pusha) begin
Page fault at 0xbfffefe0: not present error writing page in user context.
pt-grow-pusha: dying due to interrupt 0x0e (#PF Page-Fault Exception).
Interrupt 0x0e (#PF Page-Fault Exception) at eip=0x804809c
cr2=bfffefe0 error=00000006
eax=bfffff8c ebx=00000000 ecx=0000000e edx=00000027
esi=00000000 edi=00000000 esp=bffff000 ebp=bfffffa8
cs=001b ds=0023 es=0023 ss=0023
pt-grow-pusha: exit(-1)
Execution of 'pt-grow-pusha' complete.
Timer: 71 ticks
Thread: 0 idle ticks, 63 kernel ticks, 8 user ticks
hda2 (filesys): 62 reads, 200 writes
hda3 (scratch): 97 reads, 2 writes
hda4 (swap): 0 reads, 0 writes
Console: 1359 characters output
Keyboard: 0 keys pressed
Exception: 1 page faults
Powering off...
to have the GDB debugger run and stop at the desired location:
gdb filename <--start debug session
br main <--set a breakpoint at the first line of the main() function
r <--run until that breakpoint is reached
br filename.c:linenumber <--set another breakpoint at the desired line of code
c <--continue until second breakpoint is encuntered
The debugger will stop at the desired location in the file, IF it ever actually gets there,
When I debug this project I have to step through the whole program
until I find what caused error/exception which is very time consuming.
There is probably a faster way to do this.
Normally what you would do is set a breakpoint just before the error. Then your program will run at full speed, without your intervention, until it reaches that point.
There are several wrinkles here.
First, sometimes it is difficult to know where to put the breakpoint. In this case I suppose I would look for the code that is printing the message, then work backward from there. Sometimes you have to stop at the failure point, examine the stack, set a new breakpoint further up, and re-run the program.
Then there is the mechanics of setting the breakpoint. One simple way is to break by function name, like break my_function. Another is to use the file name and line number, like break my_file.c:73.
Finally, sometimes a breakpoint can be hit many times before the failure is seen. You can use ignore counts (see help ignore) or conditional breakpoints (like break my_function if variable = 27) to limit the number of stops.
I am still learning about debugging C using python within gdb (arm-none-eabi-gdb, in my case). I am trying to use this facility to get thread information of a real-time OS running on ARM Cortex-M. Reading some OS structures, I can access the thread control blocks of the OS. I know the PC and the SP of each thread. How can I use gdb's Python to dump the threads' backtrace. Is there a generic API that can traverse the stack when given PC and SP?
I have read https://sourceware.org/gdb/current/onlinedocs/gdb/Unwinding-Frames-in-Python.html#Unwinding-Frames-in-Python and I feel there might be a way to achieve that but I need some help.
Also, if possible, can I make gdb aware of the different threads of the OS? This link:
https://sourceware.org/gdb/current/onlinedocs/gdb/Threads-In-Python.html#Threads-In-Python touches on threads but relies on OS info. Can these be overload with what I know about the different OS threads from their respective control blocks?
Thanks!
After some more reading and trying to make use of old debugger knowledge that I have accumulated over the years, I managed to get this working. It lacks optimization but for now, I'm very please. This can be considered a poor-man's debugger making use of GDB's Python support to track the active threads in the system. It's generic, I assume, but the implementation targeted RTX (Keil's OS). It worked on Cortex-M0. It may need some tweaking to fit other operating systems or different cores.
The main idea:
Use OS structures, to identify where the thread control block reside.
From the thread control block identify where is the different thread stacks are.
Read from the stack all the vital registers; SP, LR, and PC
Save the same registers for the current, running thread.
Loop over the different thread, change the vital registers to the ones matching the thread, then print the backtrace.
Enjoy a poor-man's OS-aware debugger.
The script can be found here:
https://gitlab.com/hesham/gdb-rtx-thread-backtrce/blob/master/rtx-threads-bt.py
It was a very good exercise to explore the power of GDB's Python extension!
For FreeRTOS I use the following gdb script:
define printtasklist
# $arg0 is a pointer to an uxList of tasks.
set $plist = (List_t*)$arg0
printf ": %d tasks\n", $plist->uxNumberOfItems
set $iter = $plist->xListEnd.pxNext
while ($iter != &$plist->xListEnd)
set $vtask = ($iter->pvOwner)
set $task = (tskTCB*)$vtask
print $task
print $task->pcTaskName
set $iter = $iter->pxNext
end
end
define printtasks
printf "%d tasks:\n", uxCurrentNumberOfTasks
printf "pending ready"
printtasklist &xPendingReadyList
printf "suspended"
printtasklist &xSuspendedTaskList
printf "delayedW"
printtasklist pxDelayedTaskList
printf "delayedO"
printtasklist pxOverflowDelayedTaskList
set $prio = 0
set $maxprio = sizeof(pxReadyTasksLists) / sizeof(pxReadyTasksLists[0])
while ($prio < $maxprio)
printf " ready at prio"
printf "%d", $prio
printtasklist &pxReadyTasksLists[$prio]
set $prio = $prio + 1
end
end
define savestate
set $svpc = $pc
set $svsp = $sp
set $svlr = $lr
end
define restorestate
set $pc = $svpc
set $sp = $svsp
set $lr = $svlr
end
define cm3bttask
# arg0: task handle (pointer to tskTCB)
savestate
set $ptsk = (tskTCB*)$arg0
set $tskstk = (uint32_t*)$ptsk->pxTopOfStack
set $lr = $tskstk[13]
set $pc = $tskstk[14]
set $sp= $tskstk + 16
bt
end
The idea is that I use printtasks to get the list of task control blocks, then use cm3bttask $26 if the task I'm interested in has the control block pointer in the GDB history printed as line $26. I can see that on the output of printtasks.
This question already has answers here:
What is the origin of magic number 42, indispensable in coding? [closed]
(6 answers)
Closed 6 years ago.
Why do we use 42 as an argument of exit while exiting the process? I am wondering is it some macro value (like 1 is value of EXIT_FAILURE macro) or it has some deeper meaning?
if(pid == 0) {
printf("something\n");
exit(42);
}
It is kind of clear that it doesn't matter if I use exit(1) or exit(42), but why just 42?
Any number except for 0 would have done. But 42 is the Answer to the Ultimate Question of Life, the Universe, and Everything.
Very popular among IT people...
But why did Douglas Adams pick 42?
I sat at my desk, stared into the garden and thought '42 will do'. I
typed it out. End of story
Such magic value may be used to indicate exact exit reason to parent process. You may threat it like a some kind of minimalistic IPC. Of course both processes must agree about actual values and their meanings, as well as do not use special reserved exit codes.
It is kind of clear that it doesn't matter if I use exit(1) or exit(42)
It actually matters a lot.
The exit code can be used by the process that launches the exiting process to know how it completed and why it failed.
The process that launches your program can inspect the value of the environment variable $? immediately after your program completes to know if it succeeded or why it failed, if it didn't succeed.
Let's say your program downloads a file from a remote site and stores it in a local directory. It expects to use an existing local directory and it doesn't attempt to create it if it doesn't exist. It can exit, for example, with code 37 when the remote file cannot be downloaded because the remote site return 404 Not Found, with code 62 when it cannot download the file because the network is down (or a timeout happens) and code 41 when the local directory does not exist.
A bash script, for example, that invokes your program can check the value of the environment variable $? immediately after your program completes. If its value is 37 (remote file is not found) it must not attempt to retry because the error is permanent. On exit code 62 (network issues) it can wait a couple of seconds and try again (the error condition is transient, it could disappear after a while). On exit code 41 (local directory not found) it can create the local directory then launch your program again (a precondition was not met).