How to use gdb to decode stack trace (show line numbers) - gdb

I know I can use info line *<addr> within gdb to decode a single line. But a stack trace has 10+ addresses. Is there an efficient way to let me copy and paste a list of addresses (also without the leading *) and it will list the filenames and line numbers much like the bt command but without the core dump?

Based on the suggestion of #ssbssa, I wrote the following user-defined command that works for me.
define decode
set $i = 0
while $i < $argc
eval "info line *($arg%d)", $i
set $i = $i + 1
end
end

Related

How I can make gdb print all breakpoint executions without stopping on them?

Use case: I want to research program execution by reading breakpoint hits. Hits count is more than 100.
I can't use continue 1, because hits count is too large. I can't use continue <some big number>, because GDB skipping all occurrences and not writing them in log.
What I can do with this case?
define print_all_br
set $i = 0
while $i < $arg0
continue 1
set $i = $i + 1
end
end
This might work with print_all_br(<some_big_number>)

Modifying a pattern-matched line as well as next line in a file

I'm trying to write a script that, among other things, automatically enable multilib. Meaning in my /etc/pacman.conf file, I have to turn this
#[multilib]
#Include = /etc/pacman.d/mirrorlist
into this
[multilib]
Include = /etc/pacman.d/mirrorlist
without accidentally removing # from lines like these
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
I already accomplished this by using this code
linenum=$(rg -n '\[multilib\]' /etc/pacman.conf | cut -f1 -d:)
sed -i "$((linenum))s/#//" /etc/pacman.conf
sed -i "$((linenum+1))s/#//" /etc/pacman.conf
but I'm wondering, whether this can be solved in a single line of code without any math expressions.
With GNU sed. Find row starting with #[multilib], append next line (N) to pattern space and then remove all # from pattern space (s/#//g).
sed -i '/^#\[multilib\]/{N;s/#//g}' /etc/pacman.conf
If the two lines contain further #, then these are also removed.
Could you please try following, written with shown samples only. Considering that multilib and it's very next line only you want to deal with.
awk '
/multilib/ || found{
found=$0~/multilib/?1:""
sub(/^#+/,"")
print
}
' Input_file
Explanation:
First checking if a line contains multilib or variable found is SET then following instructions inside it's block.
Inside block checking if line has multilib then set it to 1 or nullify it. So that only next line after multilib gets processed only.
Using sub function of awk to substitute starting hash one or more occurences with NULL here.
Then printing current line.
This will work using any awk in any shell on every UNIX box:
$ awk '$0 == "#[multilib]"{c=2} c&&c--{sub(/^#/,"")} 1' file
[multilib]
Include = /etc/pacman.d/mirrorlist
and if you had to uncomment 500 lines instead of 2 lines then you'd just change c=2 to c=500 (as opposed to typing N 500 times as with the currently accepted solution). Note that you also don't have to escape any characters in the string you're matching on. So in addition to being robust and portable this is a much more generally useful idiom to remember than the other solutions you have so far. See printing-with-sed-or-awk-a-line-following-a-matching-pattern/17914105#17914105 for more.
A perl one-liner:
perl -0777 -api.back -e 's/#(\[multilib]\R)#/$1/' /etc/pacman.conf
modify in place with a backup of original in /etc/pacman.conf.back
If there is only one [multilib] entry, with ed and the shell's printf
printf '/^#\[multilib\]$/;+1s/^#//\n,p\nQ\n' | ed -s /etc/pacman.conf
Change Q to w to edit pacman.conf
Match #[multilib]
; include the next address
+1 the next line (plus one line below)
s/^#// remove the leading #
,p prints everything to stdout
Q exit/quit ed without error message.
-s means do not print any message.
Ed can do this.
cat >> edjoin.txt << EOF
/multilib/;+j
s/#//
s/#/\
/
wq
EOF
ed -s pacman.conf < edjoin.txt
rm -v ./edjoin.txt
This will only work on the first match. If you have more matches, repeat as necessary.
This might work for you (GNU sed):
sed '/^#\[multilib\]/,+1 s/^#//' file
Focus on a range of lines (in this case, two) where the first line begins #[multilib] and remove the first character in those lines if it is a #.
N.B. The [ and ] must be escaped in the regexp otherwise they will match a single character that is m,u,l,t,i or b. The range can be extended by changing the integer +1 to +n if you were to want to uncomment n lines plus the matching line.
To remove all comments in a [multilib] section, perhaps:
sed '/^#\?\[[^]]*\]$/h;G;/^#\[multilib\]/M s/^#//;P;d' file

Does gdb support comments in the command line (gdb prompt)?

I want to comment gdb commands in the command prompt at the end of the line for two use case:
Writing a tutorial
Documenting a gdb command file for automatic execution
While gdb command files seem to support comments via the hash (#) symbol
I cannot find any command marker for the gdb command line:
(gdb) print 1
$2 = 1
(gdb) print 1 // comment
A syntax error in expression, near `/ comment'.
(gdb) print 1 -- comment
A syntax error in expression, near `comment'.
(gdb) print 1 # comment
Invalid character '#' in expression.
(gdb) print 1 ; comment
Invalid character ';' in expression.
(gdb) print 1 /* comment */
No symbol "comment" in current context.
How can I append comments?
Edit: According to the gdb documentation
Any text from a # to the end of the line is a comment;
it does nothing.
This is useful mainly in command files
I am not sure why it doesn't work as documented...
You can use it on its own line, but not at the end of a line. E.g.:
(gdb) # foo
(gdb) print "foo"
$1 = "foo"

gdb user-defined functions: how to pass complex argument?

I want to examine several QString variables,
so I found macros for this in Internet:
define printqstring
printf "(QString)0x%x (length=%i): \"",&$arg0,$arg0.d->size
set $i=0
while $i < ($arg0).d->size
set $c=$arg0.d->data[$i++]
if $c < 32 || $c > 127
printf "\\u0x%04x", $c
else
printf "%c", (char)$c
end
end
printf "\"\n"
end
But when I try to use it, I got such error:
(gdb) printqstring ((MyWidget *)0xd98cb0)->caption_
A syntax error in expression, near `,((MyWidget.d->size'.
if I try to use commands from macros by hand, they work fine:
(gdb) printf "(QString)0x%x (length=%i): \"",&((MyWidget *)0xd98cb0)->caption_,((MyWidget *)0xd98cb0)->caption_.d->size
(QString)0xd98ccc (length=3)
So how can I pass such complex argument to gdb macros?
Unfortunately gdb always divides input to a user-defined function at any space character, even if that character is inside parentheses or something like that.
So you can just make sure you don't use any spaces in the argument you want to pass:
(gdb) printqstring ((MyWidget*)0xd98cb0)->caption_
^~~ removed space
I don't know of any good way to make this more convenient and allow spaces.

Scripting in gdb

Say, for example, I have a C source file with a method like foo(a) where a is a character.
I want to print the output of foo for every character is there an easier way than going through systematically and entering p foo('a') then p foo('b')?
Ideally I'd really like to script it so it's a bit quicker.
I managed to figure it out, my code was basically:
define foo_test
set $a = 97
set $b = 123
while $a < $b
p (char)foo($a)
set $a = $a + 1
end
end
perl -e 'foreach $i ("a" .. "z") { print "print foo('\''$i'\'')\n"; }' > /tmp/t.$$ &&
gdb --batch -x /tmp/t.$$ ./a.out ; rm -f /tmp/t.$$
You should also look into GDB Python scripting.
It sounds like the first thing you should add is some "Breakpoint command lists",
those will let you run some gdb commands after a breakpoint has hit.
So if you add so your print runs when someone calls the functions foo,
you should be are getting kind of close.