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

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>)

Related

GDB loop_continue produces warning message

In order to practice loop_continue, I wrote the following user-defined GDB command:
#
# Print all odd numbers less than a given number.
#
define print_all_odds_less_than
set $max = $arg0
set $i = 0
while $i < ($max - 1)
set $i = $i + 1
if ($i % 2) == 0
loop_continue
end
printf "Odd number %u is less than %u\n", $i, $max
end
printf "Done\n"
end
Sample run:
(gdb) print_all_odds_less_than 10
Odd number 1 is less than 10
Odd number 3 is less than 10
Odd number 5 is less than 10
Odd number 7 is less than 10
Odd number 9 is less than 10
Done
However, when I provide a value such that the while loop does not execute again after the last loop_continue, a warning message is produced and my user-defined command aborts execution.
(gdb) print_all_odds_less_than 9
Odd number 1 is less than 9
Odd number 3 is less than 9
Odd number 5 is less than 9
Odd number 7 is less than 9
warning: Error executing canned sequence of commands.
Documentation for loop_continue:
This command skips the execution of the rest of the body of commands
in the while loop in whose body it is included. Execution branches to
the beginning of the while loop, where it evaluates the controlling
expression.
From the documentation, I am unable to understand the mistake in my code.
My GDB version:
bash$ gdb --version
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Any help would be appreciated :)

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

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

How to add a prefix to all lines that don't start with one of multiple words

I am trying to add a prefix to all the lines in a file that don't start with one of multiple words using sed.
Example :
someText
sleep 1
anotherString
sleep 1
for i in {1..50}
do
command
sleep 1
secondCommand
sleep 1
done
Should become
PREFIX_someText
sleep 1
PREFIX_anotherString
sleep 1
for i in {1..50}
do
PREFIX_command
sleep 1
PREFIX_secondCommand
sleep 1
done
I am able to exclude any line starting with a single pattern word (ie: sleep, for, do, done), but I don't know how to exclude all lines starting with one of multiple patterns.
Currently I use the following command :
sed -i '/^sleep/! s/^/PREFIX_/'
Which works fine on all the lines starting with sleep.
I imagine there is some way to combine pattern words, but I can't seem to find a solution.
Something like this (which obviously doesn't work) :
sed -i '/[^sleep;^for;^do]/! s/^/PREFIX_/'
Any help would be greatly appreciated.
Use alternation with multiple words for negation:
sed -i -E '/^(sleep|for|do)/! s/^/PREFIX_/' file
PREFIX_someText
sleep 1
PREFIX_anotherString
sleep 1
for i in {1..50}
do
PREFIX_command
sleep 1
PREFIX_secondCommand
sleep 1
done
/^(sleep|for|do)/! will match all lines except those that start with sleep, or for or do words.
I like awk.
awk '/sleep|for|do/ { print; next; } { print "PREFIX_" $0 }' filename

How to delete specific contents of file using tcl

I am very new to tcl, and am working through basic example to get some good understanding before I start my project.
I would appreciate if someone would help or advice the best way of deleting specific contents of a file.
In my case I have some data in LogData.dat file, I would like to open this file delete Line number 3 and at same time delete the first column (#Name, #Index#, #mspace) and then save the file after the changes have been made.
The number of columns may be more than 5 but it is always the first column with #Name, #Index#, #mspace that needs deleting and line 3 that needs deleting.
I wondering is it better to first delete line 3 (which gets rid of #mspace) and then match words #Name, #Index with regexp and then somehow delete #Name & #Index
I also need to keep in mind that these files might be very large (100mb) and there will be multiple files so I’d need to loop these till all files are modified. Therefore need to avoid any memory problems, if I have to read and write such big files quickly.
Would appreciate if some can give some help or provide an easy clean example.
Example (cut down version) shown below.
#Name Length Width height Time
#Index m - - s
#mSpace 0 0 0 0
13.4112 0 0 0
13.411177 0 1.8827043e-007 0.001
13.411122 0 1.8827043e-007 0.002
I would suggest you to read the file and write to another to make it easier to follow your own code. You could do it a bit like that:
# Open file for reading
set input [open "LogData.dat" r]
# Open file for writing
set output [open "newLogData.dat" w]
# This variable will help us know the line number
set ln 0
# Loop through each line of the file
while {[gets $input line] != -1} {
incr ln
if {$ln < 4} {
if {$ln < 3} {
# On lines 1 to 2, split the line on tab, remove the first
# element of the result list and join it back with tabs
set line [join [lreplace [split $line \t] 0 0] \t]
} else {
# Skip line 3 completely
continue
}
}
puts $output $line
}
close $input
close $output
codepag demo
You don't really need regex in there, the above is an example with the file contents already in a variable.
You can put something like file delete LogData.dat and file rename newLogData.dat LogData.dat to remove the initial file and rename the new one with the old one's name.
I'll swipe Jerry's suggestion to read from one file and write to another:
set input [open LogData.dat r]
set output [open newLogData.dat w]
The fields don't seem to be character-delimited, so split won't work as intended. If every line is a proper list with no whitespace within the fields, this will not cause any problems.
If the third line always has the string #mSpace in the first field and no other line has it in the first field, we don't need to count lines. (Update: fixed stupid typo in the if condition, sorry.)
# Loop through each line of the file
while {[chan gets $input line] != -1} {
set data [lassign $line first]
if {$first ne "#mSpace"} {
chan puts $output $data
}
}
On output, this code will compact consecutive whitespace characters between the fields into single space characters.
chan close $input
chan close $output
This code removes the first field from every line, since that seemed to be what you were asking for. Re-reading your question, it now seems that you only wanted to take it out in the first three lines. Updated code:
# Loop through each line of the file
while {[chan gets $input line] != -1} {
set data [lassign $line first]
if {[string match #* $first]} {
if {$first ne "#mSpace"} {
chan puts $output $data
}
} else {
chan puts $output $line
}
}
Documentation: chan, if, lassign, open, set, while
(Note: the 'Hoodiecrow' mentioned in the comments is me, I used that nick earlier.)

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.