Syntax for passing a user-defined variable as a command option - lldb

With LLDB version 8 I'm trying to dump the code bytes for a function "fh", using the memory read command, using variables to calculate the length:
(lldb) expr unsigned $addr = (unsigned) fh
(lldb) expr unsigned $next_addr = (unsigned) fi
(lldb) expr unsigned $len = $next_addr - $addr
(lldb) p/x $addr
(unsigned int) $addr = 0x00000286
(lldb) p/x $next_addr
(unsigned int) $next_addr = 0x000002e4
(lldb) p/x $len
(unsigned int) $len = 0x0000005e
Passing $addr as the address is correctly interpreted with a literal integer as the length:
(lldb) memory read --size 1 --format x --count 0x5e $addr
0x00000286: 0xc8 0x47 0202 0x48 0xc9 0x42 ...
but passing $len as an argument to the count option fails:
(lldb) memory read --size 1 --format x --count $len $addr
error: invalid uint64_t string value: '$len'
This also happens with the breakpoint syntax, so it may be a general limitation with option parsing:
(lldb) breakpoint set -l $len
error: invalid line number: $len.
I also tried passing it through a command alias in the hope that substitution of the variable value would then happen earlier, but had similar results:
(lldb) command alias foop memory read --size 1 --format x --count %1 %2
(lldb) foop $len $addr
error: invalid uint64_t string value: '$len'
Is there some other syntax for evaluating a command with variables? I would prefer to avoid relying on the Python support as the toolchain I'm using doesn't reliably provide it.

You can tell whether an option argument will be evaluated or read in directly by looking at the help for the option. For instance, the argument to memory read is given as an <address-expression> and:
(lldb) help address-expression
<address-expression> -- An expression that resolves to an address.
but count is just of type "count" - which is just an unsigned int.
But... Another bit of lldb syntax is that if any argument or option value is surrounded by `` it is first evaluated as an expression and if the result is a scalar, that value is used for the option.
So you want to say:
memory read --size 1 --format x --count `$len` $addr

Related

what is the "Value" field in output of readelf -s

Here is my code:
#include <stdio.h>
int variable;
int main(){
printf("%p", &variable);
}
Output in couple of runs:
~ % ./a.out
0x559bae5c4030
~ % ./a.out
0x55b9d1038030
~ %
as you can see, there's a "30" at the end of both addresses.
and the symbol table:
~ % readelf -s a.out | grep variable
Num: Value Size Type Bind Vis Ndx Name
51: 0000000000004030 4 OBJECT GLOBAL DEFAULT 23 variable
~ %
again there's this "30" at the end of Value field.
My question is, what exactly is that value field and what does it have to do with the output of code? and why the last two digits are preserved in every run?
sorry for my poor english
The Value field from readelf corresponds to the address of the variable in the executable a.out.
What you see in the output is the actual loaded address of variable at runtime. So your executable is loaded at (starting address) 0x559bae5c0000 in the first run ( = 0x559bae5c4030 - 0x4030). And is loaded at 0x55b9d1034000 in the second run (0x55b9d1038030 - 0x4030).
You can see this by inspecting /proc/<PID>/maps of the executable a.out when running.
The load address changes from run to run because of Address Space Layout Randomization on Linux.

snprintf() overflows specified length

I was writing my own ncurses library and suddenly I found in GDB that snprintf() returned length larger than I specified. Is this defined behaviour or some mistake of mine ? The (reproducible) snippet code is this:
niko: snippets $ cat snprintf.c
#include <unistd.h>
#include <stdio.h>
char *example_string="This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout";
void snprintf_test(void) {
char tmp[72];
char fmt[32];
int len;
unsigned short x=20,y=30;
snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
write(STDOUT_FILENO,tmp,len);
}
int main(void) {
snprintf_test();
}
niko: snippets $
Now we compile with debugging info and run:
niko: snippets $ gcc -g -o snprintf snprintf.c
niko: snippets $ gdb ./snprintf -ex "break snprintf_test" -ex run
.....
Reading symbols from ./snprintf...done.
Breakpoint 1 at 0x40058e: file snprintf.c, line 10.
Starting program: /home/deptrack/depserv/snippets/snprintf
Breakpoint 1, snprintf_test () at snprintf.c:10
10 unsigned short x=20,y=30;
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-16.fc23.x86_64
(gdb) s
12 snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
(gdb) print sizeof(fmt)
$1 = 32
(gdb) print sizeof(tmp)
$2 = 72
(gdb) s
13 len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
(gdb) print fmt
$3 = "\033[%d;%dH\033[0m\033[48;5;%dm%48s\000\000\000\000\000"
(gdb) print example_string
$4 = 0x4006c0 "This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout"
(gdb) s
14 write(STDOUT_FILENO,tmp,len);
(gdb) print len
$5 = 124
(gdb) print sizeof(tmp)
$6 = 72
(gdb)
The program outputs garbage at the end of the string. As you can see, the len variable returned from snprintf() is indicating that function has printed more than the allowed size of 72. Is this a bug or my mistake? If this behaviour is defined, then why snprintf() docs say it will print at most n characters. Very misleading and bug prone statement. I will have to write my own snprintf() to solve this problem.
Actually (from "man snprintf"):
If the output was
truncated due to this limit then the return value is the number of
characters (excluding the terminating null byte) which would have been
written to the final string if enough space had been available.

calling a function using expr during an LLDB session

I'm trying to get a better grasp of LLDB and am currently stuck trying to call a locally defined function (using LLDB's expr) while debugging some code. For the sake of simplicity, lets consider this toy code:
testing_lldb.c:
unsigned long factorial(unsigned input) {
unsigned long ret_val = 0;
if (input == 0)
ret_val = 1;
else
ret_val = input * (factorial(input-1));
return ret_val;
}
I compile it like this:
$ clang -g -Weverything -c lldb_test.c
and then run LLDB by typing:
$ lldb testing_lldb.o
In my LLDB session, I'd like to be able to call factorial(). My first attempt:
(lldb) expr unsigned long i = factorial(i);
error: 'factorial' has unknown return type;
cast the call to its declared return type
The error message includes a clear hint, so I try again:
(lldb) expr unsigned long i = (unsigned long)factorial(i);
error: warning: function 'factorial' has internal linkage but is not defined
note: used here
error: Can't run the expression locally: Interpreter doesn't handle one of the expression's opcodes
Fine, I try to define factorial() manually by following the answer for this SO question:
(lldb) expr typedef unsigned long (*$factorial_type)(unsigned)
(lldb) expr $factorial_type $factorial_function = ($factorial_type)0x0000000000000000
(lldb) expr unsigned long i = (unsigned long)factorial(i);
error: warning: function 'factorial' has internal linkage but is not defined
note: used here
error: Can't run the expression locally: Interpreter doesn't handle one of the expression's opcodes
And this gives me exactly same error as above. I double checked the starting address of factorial() by running:
(lldb) image lookup -Avi -n factorial
Question
Given testing_lldb.c, what's required to be able to use factorial() in expressions in LLDB?
Some details regarding the enviroment:
$ uname -r
3.16.0-4-amd64
$ lldb -v
lldb version 3.4.2 ( revision )
$ clang -v
Debian clang version 3.4.2-14 (tags/RELEASE_34/dot2-final) (based on LLVM 3.4.2)
Target: x86_64-pc-linux-gnu
You can only use the expression parser to evaluate expressions that run functions if you are debugging a live process. You are not only not debugging a live process, but you are also debugging a .o file - which isn't fully linked - so it could never run. lldb can inspect .o files, dump the symbol tables and some things like that, but not everything will work.
You want to add a little main function to your "testing_lldb.c", and build a runnable program (drop the -c flag.) Then set a breakpoint on main:
(lldb) break set -n main
run the program
(lldb) run
then when you hit the breakpoint, try calling your function.

How do I print a pointer address without materializing the struct in LLDB

I'm trying to figure out which of several variables are null in a program. Unfortunately lldb just tells me it can't materialize the struct when I try to build it. Any ideas how I get lldb to print the address of the struct (but not the struct)?
(lldb) print *arg3
error: Couldn't materialize struct: size of variable arg3 (8) disagrees with the ValueObject's size (0)
Errored out in Execute, couldn't PrepareToExecuteJITExpression
(lldb) print (int*) arg3
error: Couldn't materialize struct: size of variable arg3 (8) disagrees with the ValueObject's size (0)
Errored out in Execute, couldn't PrepareToExecuteJITExpression
(lldb) frame variable
(td_val_t *) out = 0x00007fff5fbfe5e8
(char *) fname = 0x00000001000029b0 "bokeh_wrap.visualize"
(td_val_t *) arg1 = <variable not available>
(td_val_t *) arg2 = <variable not available>
(td_val_t *) arg3 = <variable not available>
(PyObject *) pArgs = 0x00000001073cd1e0
(lldb) print #arg1
error: unexpected '#' in program
error: 1 errors parsing expression
(lldb) expr arg1
error: Couldn't materialize struct: size of variable arg1 (8) disagrees with the ValueObject's size (0)
Errored out in Execute, couldn't PrepareToExecuteJITExpression
(lldb) expr &arg1
error: Couldn't materialize struct: size of variable arg1 (8) disagrees with the ValueObject's size (0)
Errored out in Execute, couldn't PrepareToExecuteJITExpression
Your arg variables are not available - that means that LLDB has no clue where any of them are located
Hence, the short answer would be "no, you're out of luck". One might investigate your source code/compiler settings to check why they would be unavailable (out of scope at that location? DWARF simply omitted them because they were optimized out?), but as it stands, we don't know where the variable is, we can't tell you about it.
Longer answer: are you building optimized? Any chance you can build at -O0 and still have the bug reproduce? If so, there's your solution
If this only reproduces in optimized code, it might be time to look at assembly code (LLDB has a disassemble command), and try to figure out where your program is accessing the arg variables from (registers vs some memory location) and manually issue a memory read/register read for that location, then take it from there with your inspection

Specify the type residing in a specific address

I use Bash to get a c program variables' addresses. How to know if the address is related to an integer, float or double variable?
As the comments mentioned you can't get the type unless you have debugging symbols. But if you do have the symbols then you can use GDB. Consider this program:
#include <stdio.h>
static int i = 42;
static float f = 42.1;
static double d = 42.2;
int main (int argc, char **argv) {
printf("i=%d, f=%f, d=%f\n", i, f, d);
return (0);
}
If you compile it as follows:
gcc -g -o types types.c
You can then get the type of variables like this:
ubuntu#ubuntu:~$ echo ptype i | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = int
ubuntu#ubuntu:~$ echo ptype f | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = float
ubuntu#ubuntu:~$ echo ptype d | gdb --silent types
Reading symbols from /home/ubuntu/types...done.
(gdb) type = double
ubuntu#ubuntu:~$
If you only have the symbol table and not full debugging information, i.e. the binary was compiled with -g, then processed by strip -d, then the best you can do is get the size of the given object using binary dump utilities such as nm, objdump or readelf.
Using nm:
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' i$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
4
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' f$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
4
ubuntu#ubuntu:~$ read addr next_addr <<< $(nm -n types | grep -A1 ' d$' | cut -d' ' -f1)
ubuntu#ubuntu:~$ echo "ibase=16; ${next_addr^^} - ${addr^^}" | bc
8
ubuntu#ubuntu:~$
This works as follows:
nm -n lists the symbol table with addresses in numerical order
grep -A1 ' i$ filters the symbol we are interested long with the immediately following line. Note this is a regular expression search constructed to find exactly the symbol i and nothing else
cut -d' ' -f1 lists just the addresses
read addr next_addr puts the addresses into two variables
The expression piped into bc then calculates the difference between the address we are interested in and the immediately following address. Note the addresses are in hex, so we need to tell bc that with the ibase parameter. Also the ${var^^} bash expansion converts the hex digits a-f to uppercase as bc requires this.

Resources