When I run gdb, there seems to be a notion of a main file, as if I set a breakpoint with just a number, it will get set for the source file that contains the main function.
How can I reconfigure gdb to set this to the file containing a function named my_main? (My actual main is provided by my library, in 99.9% of cases I want to focus on the the wrapped and prefixed main that the actual, library-provided, main calls).
GDB isn't doing what you say. When you say break LINE it sets a breakpoint in the "current" file, as per the docs:
The current source file is the last file whose source text was printed.
So perhaps what you want is to always set a breakpoint in my_main. If it helps you can make GDB let you up-arrow or Ctrl-R search backward through commands entered in previous sessions by following the instructions here: How can I make gdb save the command history?
You can set a breakpoint using directly function name: break my_main or you can specify filename and line: break file.c:100
Related
I'm debugging a C program with GDB. I've got an array which the values are updated many times (a little bit less than 4.000). I want to write thoses value in a different file for each iterations.
I tried to set the log file name directly in a GDB file:
break test.c:95
commands
silent
# Set the logging file
set $_file=(char*)malloc(64)
call snprintf($_file, 64, "~/path/to/logging/file_%04d.txt", i) # i is the for variable
set logging file $_file
call free($_file)
set logging redirect on
set pagination off
set logging overwrite on
set logging on
set $_data=array
set $_x=0
while ($_x<2000)
set $_y=0
while ($_y<2000)
printf "%f ", $_data[$_x][$_y]
set $_y++
end
printf "\n"
set $_x++
end
# Log default setup
set logging off
set logging redirect off
set logging overwrite off
set pagination on
continue
end
But gdb created a file $_file in my working directory instead of reading the value of the variable.
I then tried to put the file name in which I want log the output in a variable fileName in my code (also with snprintf). And the result is the same, a fileName file is created in my working directory.
Finaly I tried to put the debug code into a gdb function, and give the fileName as an argument of the function, but as previously, it does not interpret the string.
My question
With GDB, how can I use the value of a C-string as a logging file name?
You can use eval to insert variables value into gdb's commands. In your case, logging file name could be setted to $_file by command:
eval "set logging file %s", $_file
Also you can use dump, in case if you want to dump array to fileName by gdb builtin commands:
eval "dump value %s array", fileName
Note: dumped value is binary.
But gdb created a file $_file in my working directory instead of reading the value of the variable.
It looks like GDB set logging file is missing an eval of its argument. You should file a bugzilla feature request issue for that.
If your GDB is built with embedded Python, you can trivially do what you want by attaching a Python command to the breakpoint.
As I have learnt that a Perl debugger can be controlled dynamically using the file .perldb in your home directory, I was wondering if there is a C debugger also which can be manipulated in the same way. So I could set breakpoints at a certain point and print some variables and so on.
You can set breakpoints and print values in GDB via commands in ~/.gdbinit, yes.
How do you extract data from gdb so you can examine it in another program?
I am using gdb to debug a program. To see what is in array udata, I have created a source file called printudata with the following contents:
print udata[0]
print udata[1]
print udata[2]
...
print udata[143]
From within gdb I can execute that using source command and get output like this:
(gdb) source printudata
$399 = 1
$400 = 2.5
$401 = .3-10
...
$542 = <number>
So far, that is the best I can do for examining memory.
The only thing I can think of to do with this is (learn regular expressions and) strip off everything up to the equal sign so I can paste this into a spreadsheet which will tell me whether it's correct.
Is this the really the best way to get output from gdb? I am learning all this on my own and only have the basic, free tools that come with Linux (and am a beginner with all the above listed technologies)
You can print an array if it is really an array like this:
p udata
But, if udata is really a pointer, then you can use a cast to make gdb print it like an array.
p *(double(*)[144])udata
If you really want the line at a time output of your current "script", you can define a function and use a loop:
define print_udata
set $i=0
while ($i < 144)
p udata[$i]
set $i=$i+1
end
end
To log the output to a file, you can enable/disable logging:
set logging on
...gdb commands...
set logging off
The output will be in a file called gdb.txt.
In addition to the above, gdb has the "output" and "printf" commands. These don't enter the value into the value history, and they let you control the output much more precisely.
gdb has built-in scripting in both its own scripting language and in python. You can even script GDB from within a python program. You can use any of those options to write the data to a file.
More information about python & gdb here.
Is it possible to add GDB breakpoints in a C files, before compilation? Currently, I have to specify breakpoints after compilation through GDB.
I'm looking for something similar to JavaScript's debugger; statement.
Not as such, but you can insert some helpful function calls:
One option is to create a function:
void break_here ()
{
/* do nothing */
}
then call it wherever you want, but be careful it doesn't get inlined (put it in a different file, or add a "noinline" attribute).
Then, in GDB, just set a breakpoint on break_here, and you're done. If you find it tedious to set that breakpoint every time, you can create a file named .gdbinit in your home directory or in the current working directory that contains the breakpoint command.
Another option that works on Linux is to use a signal:
raise (SIGUSR1);
You could use any signal you like, but it's better to use one that doesn't kill your program (although you can configure GDB to not pass them onto your program, if you choose).
I'm not aware of a way to directly set a breakpoint, but GDB will catch interrupts, so that is one possible solution.
Something like this should work. You'll need to include signal.h:
raise(SIGABRT);
on linux, which I'm assuming you're on since you're using gdb you could make a script to do it with comments in the code
#!/bin/bash
#debug: Script to run programs in gdb with comments to specify break
points
echo "file ./a.out" > run
grep -nrIH "/\*GDB\*/" |
sed "s/\(^[^:]\+:[^:]\+\):.*$/\1/g" |
awk '{print "b" " " $1 }'|
grep -v $(echo $0| sed "s/.*\///g") >> run
gdb --init-command ./run -ex=r
exit 0
then wherever you need a breakpoint, just add /*GDB*/, the script will use grep to find the line numbers and files with those comments, and set a break point on each line of each file it finds them on, then start gdb
I created a little mini shell and it let's the user enter a command like 'ls' and it will list the contents of the directory like it's supposed to using execv() in my code, but that doesn't seem to work for when the user enters something like 'set name="bob"'. I've been looking all over the place for what I should use in my code to execute a set command when the user enters it and the best I can find is system(), but that still isn't working for me. Any ideas?
set is a shell-builtin command, not an external command (indeed it needs to be to have the intended effect, which is to modify a shell variable within the shell process itself).
This means that you need to look for and handle set within your shell itself, by adding the named variable to some internal data structure that tracks shell variables (or updating it if it already exists there).
Since you're doing a fork-and-exec or a system(), the command is really being run in a separate process. What happens in that process (like setting an environment variable) does not affect the parent's environment. (A separate issue is that set doesn't actually create an environment variable. You'd need export in [ba]sh or setenv in [t]csh to do that.)
So you need to code your mini-shell to handle the set command explicitly, rather than passing it off to another program.
You might want to look at setenv(3) and getenv(3). These are functions for changing and reading environment variables from within a C program.