Watchpoint on memory writes for a local static? - static

I want to set a watchpoint on the static local s_db:
static sqlite3*& GetSqliteDb()
{
static std::once_flag flag;
static sqlite3* s_db = NULL;
std::call_once(flag, []() {
s_db = ...
...
});
}
I've tried setting a watchpoint with file::function::name, but its giving me trouble:
$ gdb
GNU gdb (GDB) 7.6.2
Copyright (C) 2013 Free Software Foundation, Inc.
...
(gdb) file ./bin/Debug/ac-test
Reading symbols from ...
(gdb) watch ac-sqlite.cpp::GetSqliteDb::s_db
No symbol "ac" in current context.
(gdb) watch "ac-sqlite.cpp::GetSqliteDb::s_db"
Cannot watch constant value `"ac-sqlite.cpp::GetSqliteDb::s_db"'.
(gdb) watch GetSqliteDb()::s_db
A syntax error in expression, near `s_db'.
(gdb) watch GetSqliteDb::s_db
No symbol "s_db" in specified context.
(gdb) watch s_db
No symbol "s_db" in current context.
(gdb)
For completeness, I built with -O0 -g3, so even symbolic constant names are available.
How do I set a watchpoint for writes on the static local s_db?

It seems that you need to dereference the address of s_db variable with * operator.
See Setting Watchpoints in documentation. This watchpoint should work:
(gdb) watch *("ac-sqlite.cpp::GetSqliteDb::s_db")

It seems that if I set a watchpoint with a mangled C++ name then everything is OK. If I set a watchpoint with a demangled C++ name then gdb does not find a static varable in a function. This is an example that I tested with gcc and gdb on Windows:
void GetSqliteDb()
{
static int *s_db = 0;
s_db = new int;
*s_db = 1;
*s_db = 2;
s_db = 0;
}
int main()
{
GetSqliteDb();
return 0;
}
This is nm output:
>nm a.exe | grep s_db
00405020 b __ZZ11GetSqliteDbvE4s_db
>nm a.exe | grep s_db | c++filt
00405020 b GetSqliteDb()::s_db
This is a gdb session:
>gdb -q a.exe
Reading symbols from a.exe...done.
(gdb) watch GetSqliteDb::s_db
No symbol "s_db" in specified context.
(gdb) watch _ZZ11GetSqliteDbvE4s_db
Hardware watchpoint 1: _ZZ11GetSqliteDbvE4s_db
(gdb) start
Temporary breakpoint 2 at 0x4013cb: file main.cpp, line 11.
Starting program: a.exe
[New Thread 1688.0xff8]
(gdb) info watchpoints
Num Type Disp Enb Address What
1 hw watchpoint keep y _ZZ11GetSqliteDbvE4s_db
Temporary breakpoint 2, main () at main.cpp:11
11 {
(gdb) c
Continuing.
Hardware watchpoint 1: _ZZ11GetSqliteDbvE4s_db
Old value = 0
New value = 4007328
GetSqliteDb () at main.cpp:5
5 *s_db = 1;
(gdb) c
Continuing.
Hardware watchpoint 1: _ZZ11GetSqliteDbvE4s_db
Old value = 4007328
New value = 0
GetSqliteDb () at main.cpp:8
8 }
(gdb) c
Continuing.
[Inferior 1 (process 1688) exited normally]
Update
I tested the same example on RHEL 6.3 (2.6.32-279.el6.x86_64) with gdb 7.6.2 and it sets a watchpoint correctly. So I cannot reproduce the problem on this platform:
>gdb a.out
GNU gdb (GDB) 7.6.2
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/a.out...done.
(gdb) watch GetSqliteDb::s_db
Hardware watchpoint 1: GetSqliteDb::s_db
(gdb) r
Starting program: /home/a.out
Hardware watchpoint 1: GetSqliteDb::s_db
Old value = (int *) 0x0
New value = (int *) 0x601010
GetSqliteDb () at main.cpp:5
5 *s_db = 1;
(gdb) c
Continuing.
Hardware watchpoint 1: GetSqliteDb::s_db
Old value = (int *) 0x601010
New value = (int *) 0x0
GetSqliteDb () at main.cpp:8
8 }
(gdb)

Related

different results while displaying data at the same address depending if i use gdb

Need to extract a few values from an auxiliary vector. You can read more about it here. That's where I got and slightly modified code below:
#include <stdio.h>
#include <elf.h>
int main(int argc, char* argv[], char* envp[])
{
Elf64_auxv_t *auxv;
while (*envp++ != NULL); /* from stack diagram above: *envp = NULL marks end of envp */
for (auxv = (Elf64_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++)
/* auxv->a_type = AT_NULL marks the end of auxv */
{
if (AT_EXECFN == auxv->a_type)
{
char *str = (char *)auxv->a_un.a_val;
printf("%s\n", str);
break;
}
}
return 0;
}
I compile the code with gcc -g aux-extractor.c.
Here is the weird part. If I run the code as ./a.out I get and output as ./a.out which makes sense. However when I debug it in gdb and print the value at a specific address I get /tmp/a.out, which also makes sense I compiled my code in /tmp directory. My question is why I'm getting two different results, a.out and /tmp/a.out?
Here is my debugging session (pay attention to the output of the x/s command:
$ gdb ./a.out
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu". T
ype "show configuration" for configuration details.
For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x1149: file auxv-extractor.c, line 5.
Starting program: /tmp/a.out
Temporary breakpoint 1, main (argc=21845, argv=0x0, envp=0x5555555551c0 <__libc_csu_init>) at auxv-extractor.c:5
5 {
(gdb) break 15
Breakpoint 2 at 0x555555555198: file auxv-extractor.c, line 15.
(gdb) c
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffe408, envp=0x7fffffffe520) at auxv-extractor.c:15
15 printf("%s\n", str);
(gdb) x/s str
0x7fffffffefed: "/tmp/a.out"
(gdb)
When gdb runs your program, it does so by executing /tmp/a.out, having expanded the path from the ./a.out on the command line.
GDB has a habit of starting the program with $(realpath ./a.out) when ./a.out is given on the command line.
I've tried to set exec-wrapper as a way to avoid this, but was not successful -- even when setting exec-wrapper wrapper.sh with this contents:
#!/bin/bash
exec -a "./a.out" "$#"
the AT_EXECFN remains /tmp/a.out.
This answer shows how to pause the program after main() to make it easy to attach GDB from "outside". AT_EXECFN will be set to ./a.out as expected, and you can continue debugging as you normally would.

gdb watchpoint not triggering on memory address

Recently, I tried to debug a memory corruption bug using gdb's watchpoint feature on a memory address which falsely got overwritten by some piece of code.
Surprisingly, this did not work. I ended up fixing my problem but without gdb's help. Here is a small code example which demonstrates how the watchpoint does not trigger:
void main() {
unsigned char data[] = {
0x12, 0x34, 0x56, 0x78
};
data[4] = 0x89;
}
This code declares an array with size 4 and writes to the 4th index. Oops, we corrupted a byte of memory.
Using gdb, I acquired the address of data[4] before the assignment was executed and set a watchpoint on the address:
(gdb) p/x &data[4]
$1 = 0x7ffffffee950
(gdb) watch *0x7ffffffee950
Hardware watchpoint 2: *0x7ffffffee950
(gdb) continue
Continuing.
[Inferior 1 (process 14543) exited normally]
As you can see, the application continues as normal and exits. No reaction from gdb. Is this a bug or am I doing something wrong here? I would expect to get something from gdb if the address is modified but nothing happens.
My version of gdb is:
GNU gdb (Ubuntu 8.1-0ubuntu3)
Strangely enough, this seems to be linked to the fact that your example lies in the main() function. I tried with the following example:
void foo() {
unsigned char data[] = {
0x12, 0x34, 0x56, 0x78
};
data[4] = 0x89;
}
void main() {
foo();
}
I compiled it and ran gdb on it:
$> gcc -g3 -fno-stack-protector -o sample sample.c
$> gdb -q ./sample
Reading symbols from ./sample...done.
(gdb) b foo
Breakpoint 1 at 0x1129: file sample.c, line 2.
(gdb) r
Starting program: /tmp/sample
Breakpoint 1, foo () at sample.c:2
2 unsigned char data[] = {
(gdb) p /x &data[4]
$1 = 0x7fffffffe150
(gdb) watch *0x7fffffffe150
Hardware watchpoint 2: *0x7fffffffe150
(gdb) c
Continuing.
Hardware watchpoint 2: *0x7fffffffe150
Old value = -7840
New value = -7799
foo () at sample.c:7
7
So, it seems to work fine in foo() (but, I can also say it won't work in main()). I will take a look why...
EDIT
It seems I had a glitch (or I did something different but I cannot remember what). It works perfectly on my system (Debian unstable with gdb 8.1). Here is the code I used:
void main() {
unsigned char data[] = {
0x12, 0x34, 0x56, 0x78
};
data[4] = 0x89;
}
Compiling and running gdb on it:
$> gcc -Wall -Wextra -fno-stack-protector -g3 -o sample sample.c
$> gdb -q ./sample
Reading symbols from ./sample...done.
(gdb) start
Temporary breakpoint 1 at 0x1129: file sample.c, line 2.
Starting program: /tmp/sample
Temporary breakpoint 1, main () at sample.c:2
2 unsigned char data[] = {
(gdb) p /x &data[4]
$1 = 0x7fffffffe160
(gdb) watch *0x7fffffffe160
Hardware watchpoint 2: *0x7fffffffe160
(gdb) c
Continuing.
Hardware watchpoint 2: *0x7fffffffe160
Old value = 1431654720
New value = 1431654793
main () at sample.c:6
6 }
Nothing strange... The watchpoint worked as expected. But, this is strange because it did not work at first... I might have done something slightly different... Maybe, I did put the watchpoint before starting the program. It might have some role in this.

gdb optimized out values when using __thread

All my static __thread values shown as <optimized out> when, in debugging, I want to watch the value of a variable; even with -o0 and/or volatile.
Static Variables without __thread are shown correctly.
Is there anyway to show the values of the variable even though I'm working with threads?
Using Win10 (CreateThread), eclipse CDT, c11, mingw64-w64 and gdb 7.11.1
A workaround may be: add some printers of thread local variables in your code, and let gdb call them. (Or if you are familiar with x86 assembly, write some hackish plugin to modify the executable memory to read out fs:offset/gs:offset (thread local variable value) and recover the memory & register)
To be more specific, add a function to the C code that does nothing but return the interesting __thread variable, and when you break the program using gdb, you can always make gdb call that function for you (assume that the function is not optimized) without corrupting the stack frame of the original program. it should be as easy as:
(gdb) p rand()
$1 = 1804289383
(gdb) p rand()
$2 = 846930886
(gdb) p rand()
$3 = 1681692777
although rand is not a good example since it has side effect. TLS variable read does not have side effect.
Example: (under Ubuntu 16.04, but things shouldn't have much difference since the functionality is very basic)
tls.cpp:
#include <stdio.h>
__thread long thread_cand;
long what_is_thread_cand()
{
return thread_cand;
}
int main()
{
while ( !feof ( stdin ) )
{
scanf ( "%ld", &thread_cand );
printf ( "%p : %ld\n", &thread_cand, thread_cand );
}
return 0;
}
terminal:
$ g++ -O2 -g3 tls.cpp -o tls
tls.cpp: In function ‘int main()’:
tls.cpp:14:38: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
scanf ( "%ld", &thread_cand );
^
$ gdb tls --nh
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from tls...done.
(gdb) r
Starting program: /home/ubuntu/tls
123
0x7ffff7fcb6f8 : 123
432
0x7ffff7fcb6f8 : 432
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7b04230 in __read_nocancel ()
at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) p thread_cand
Cannot find thread-local storage for process 6472, executable file /home/ubuntu/tls:
Cannot find thread-local variables on this target
(gdb) p what_is_thread_cand()
$1 = 432
(gdb)

gdb "watch" can not variable modified by glibc(read) function?

I want to break whenchmodified.I usedwatch chin gdb,it does not work.
Something like ch=1;will break.Why read()not?
Is is right use watch command like this. Or the read()function is Special?
Sorry for my English, Code say all things.
file 1.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
const char *const filename = "/etc/passwd";
int main(void)
{
int fd;
int ch;
fd = open(filename, O_RDONLY);
read(fd, &ch, sizeof(int));
printf ("%d\n", ch);
close (fd);
return 0;
}
gcc -g 1.c
debugging:
$ gdb a.out
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zodiac1111/tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x80484b5: file 1.c, line 11.
(gdb) r
Starting program: /home/zodiac1111/tmp/a.out
Breakpoint 1, main () at 1.c:11
11 fd = open(filename, O_RDONLY);
(gdb) watch ch
Hardware watchpoint 2: ch
(gdb) c
Continuing.
1953460082
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
__libc_start_main (main=0x80484ac <main>, argc=1, ubp_av=0xbffff4c4,
init=0x8048530 <__libc_csu_init>, fini=0x8048520 <__libc_csu_fini>,
rtld_fini=0xb7ff0590, stack_end=0xbffff4bc) at libc-start.c:260
260 libc-start.c: No such dir...
(gdb) c
Continuing.
[Inferior 1 (process 9513) exited normally]
For a normal implementation of read(), the write to the memory will be performed directly by the kernel, not by any userspace code. The debugger does not have the mechanisms to put a breakpoint in the kernel, and even if it did, it wouldn't have permission to do so.

gdb prints wrong values when modifying arguments

System
Fresh install of codeblocks 12.11 + mingw pack.
win7 64
gcc 4.7.1
gdb 7.5
Example code
Compiled with -g and no optimization.
#include <stdio.h>
void foo(int a, int b);
int main() {
foo(400, 42);
return 0;
}
void foo(int a, int b) {
a = a - 10;
b = a + 1;
printf("y2 %d\n", b);
}
Problem
I put a breakpoint on "void foo(int a, int b)" and I look value of b as I step through the 3 lines.
Either with the codeblocks debugging features or with the gdb command line, the value of b is 42 instead of being 391.
The console output is correct, 391.
GDB commands
C:\DebugTest>"C:\Program Files (x86)\CodeBlocks\MinGW\bin\gdb.exe"
GNU gdb (GDB) 7.5
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) file bin/Debug/DebugTest.exe
Reading symbols from C:\DebugTest\bin\Debug\DebugTest.exe...done.
(gdb) break foo
Breakpoint 1 at 0x401363: file C:\DebugTest\main.c, line 14.
(gdb) run
Starting program: C:\DebugTest\bin\Debug\DebugTest.exe
[New Thread 3596.0x658]
Breakpoint 1, foo (a=400, b=42) at C:\DebugTest\main.c:14
14 a = a - 10;
(gdb) print b
$1 = 42
(gdb) step
15 b = a + 1;
(gdb) print b
$2 = 42
(gdb) step
17 printf("y2 %d\n", b);
(gdb) print b
$3 = 42
(gdb)
Remarks
When the same operations are done without a function, with a and b as local variables inside main, the debug output is correct.
When compiled with gcc 4.4.1, the debug output is correct.
Any idea what could be wrong ? =)
I searched on gcc bugzilla and found this bug report :
Bug 54218 - Debug info for function parameters is incorrect when compiled with -O0"
Althoug the report is about gcc 4.8 and I'm using 4.7, I tried the proposed workaround and it works !
Compiling with -fvar-tracking allows GDB to print the correct value for b after assignment.
gcc does not generate debugging info correctly for values that are in registers -- either values that have been put in registers or values that start there due to the calling conventions. This is a long-standing problem with gcc since at least 4.0, and makes it tricky to debug things.
Sometimes the optimizer is smarter than the debugger. Try debugging unoptimized code, or step through disassembly and watch the HW registers directly rather than stepping through C source lines and watching the debugger's idea of what the variables are.

Resources