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

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.

Related

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

bash substitutions don't appear to work when matching newline characters

I have an executable file called test.script containing this simple bash script:
#!/bin/bash
temp=${1//$'\n'/}
output=${temp//$'\r'/}
printf "$output" > output.txt
When I run
sudo ./test.script "^\r\r\n\n\r\n\r\n\r\n\r\n\n\r\n\rHello World\n\n\r\r\r\n\n\r\r\r$"
in the same directory as test.script, I expect to end up with an output.txt looking like this:
^Hello World$
but when I take a look I instead see this:
^
Hello World
$
Clearly I have a misunderstanding about regex in bash.
Please explain to me what I am missing, then show me how to write the bash so that all newline characters are removed from the string before said string is written to a file. Thanks in advance.
You can "fix" your script like this (although I must say this isn't typical usage of printf):
#!/bin/bash
temp=${1//'\n'/}
output=${temp//'\r'/}
printf "$output"
The argument to your script $1 doesn't contain real newlines or carriage returns, which is what $'\n' and $'\r' are for. Instead, it looks like you just want to remove the literal strings '\n' and '\r'.
To elaborate on my point about printf, normally two (or more) arguments are passed: the format specifier and the variables that are to be inserted. For example, to print a single string you would use something like printf '%s' "$output". In your script, the variable $output is being treated as the format specifer; you're relying on printf to expand your \n and \r into newlines and carriage returns.
You're not actually using regular expressions here by the way; the syntax ${var//match/replace} is a substring replacement, where // means that all occurrences of the substring match in $var are replaced. As you haven't specified anything to replace the substring with, the substring is replaced with nothing (i.e. removed).

How can I make GDB print a string literally (without escaping)?

I have a big, long string that I want to capture to a file. I can use logging to get most of the way there:
set logging on
set logging file gdb.log
…but if I use p or x/s to print the string, quotes and junk are all escaped. How can I get the string as-is?
For a really large string you can also use:
(gdb) set variable $s = MY_STRING
(gdb) dump binary memory FILE $s $s + (size_t)strlen($s)
which can be easily adapted to handle buffers with null bytes. Also the content of FILE would never contain anything other than the string.
Ah, I totally forgot about printf:
printf "%s\n", some_string

Perl, regex, extract data from a line

Im trying to extract part of a line with perl
use strict;
use warnings;
# Set path for my.txt and extract datadir
my #myfile = "C:\backups\MySQL\my.txt";
my #datadir = "";
open READMYFILE, #myfile or die "Error, my.txt not found.\n";
while (<READMYFILE>) {
# Read file and extract DataDir path
if (/C:\backups/gi) {
push #datadir, $_;
}
}
# ensure the path was found
print #datadir . " \n";
Basically at first im trying to set the location of the my.txt file. Next im trying to read it and pull part of the line with regex. The error Im getting is:
Unrecognized escape \m passed through
at 1130.pl line 17.
I took a look at How can I grab multiple lines after a matching line in Perl? to get an idea of how to read a file and match a line within it, however im not 100% sure I'm doing this right or in the best way. I also seem to produce the error:
Error, my.txt not found.
But the file does exist in the folder C:\backups\MySQL\
When Perl sees the string "C:\backups\MySQL\my.txt" it tries to parse any escape sequences, such as \n. But when it sees \m in \my.txt, it's an unrecognized escape sequence, hence the error.
One way to fix this is to properly escape your backslashes: "C:\\backups\\MySQL\\my.txt". Another way to fix this is to use single quotes instead of double quotes: 'C:\backups\MySQL\my.txt'. Yet another way is to use the q() construct: q(C:\backups\MySQL\my.txt).
Since there are several problems I'll put comments on the changes I've made in the code below.
use strict;
use warnings;
# For pretty dumping of arrays and what not.
use Data::Dumper;
# Use single quotes so you don't have to worry about escaping '\'s.
# Use a scalar ($) instead of an array(#) for storing the string.
my $myfile = 'C:\backups\MySQL\my.txt';
# No need to initialize the array.
my #datadir;
# I believe using a scalar is preferred for file handles.
# $! will contain the error if we couldn't open the file.
open(my $readmyfile, $myfile) or die "error opening: $!";
while (<$readmyfile>) {
# You must escape '\'s by doubling them.
# If you are just testing to see if the line contains 'c:\backups' you do not
# need /g for the regex. /g is for repeating matches
if (/C:\\backups/i) {
push(#datadir, $_);
}
}
# Data::Dumper would be better for dumping the array for debugging.
# Dumper wants a reference to the array.
print Dumper(\#datadir);
Update:
If you're referring to the output from Data::Dumper, it's just there for a pretty representation of the array. If you need a specifically formatted output you'll have to code it. A start would be:
print "$_\n" for (#datadir);
Use forward slashes instead of backslahes
Shouldn't you be using $myfile instead of #myfile? The latter gives you an array, and since you're referencing it in scalar context, it's getting dereferenced (so it's actually trying to open a "file" called something like ARRAY(0xdeadbeef) instead of the actual filename).
The file is not being found because you are passing an array to open when it's expecting a scalar, so I'd guess that the array is being evaluated in a scalar context instead of as a list so you're actually telling perl to try opening the file named '1' instead of your 'my.txt' file.
Try something like this instead:
my $a = 'filename';
open FH, $a or die "Error, could not open $a: $!";
...
As other people have said, part of the issue is using " " rather than ' ' type of quoting.
I try always to use ' ' unless I know I need to include an escape or interpolate a variable.
Here are a number of pitfalls
use 5.10.0 ;
use warnings ;
say "file is c:\mydir" ;
say "please pay $100 ";
say "on VMS the system directory is sys$system" ;
say "see you #5 ";
With double quotes
Unrecognized escape \m passed through at (eval 1) line 2.
Possible unintended interpolation of #5 in string at (eval 1) line 5.
file is c:mydir
Use of uninitialized value $100 in concatenation (.) or string at (eval 1) line 3.
please pay
Use of uninitialized value $system in concatenation (.) or string at (eval 1) line 4.
on VMS the system directory is sys
see you
With single quotes
file is c:\mydir
please pay $100
on VMS the system directory is sys$system
see you #5

How to print wstring in gdb

How can I print wstring in gdb?
call printf %ls only works sometimes, but to get it to work at all in gdb 6.3 you need the void cast and linefeed \n shown here:
call (void)printf("\"%ls\"\n",str.c_str())
here is a more reliable command you can put in your .gdbinit that also shows non-ASCII code points:
define wc_print
echo "
set $c = (wchar_t*)$arg0
while ( *$c )
if ( *$c > 0x7f )
printf "[%x]", *$c
else
printf "%c", *$c
end
set $c++
end
echo "\n
end
just enter wc (short for wc_print) with either a std::wstring or wchar_t*.
More detail at http://www.firstobject.com/wchar_t-gdb.htm
Suppose you've got a std::wstring str. The following should work in gdb:
call printf("%ls", str._M_data())
(The -l option in printf makes it a long string, and I believe you need the "call" statement because the ordinary gdb printf doesn't like that option.)
I did some research, and this is gdb PR716, PR1998, PR2264. Apparently this is an often-requested feature that is not yet implemented.