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

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.

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.

How can I pause the execution of a pthread program, so that I can check the pid and tgid of the threads?

I am trying with a small program from Distinction between processes and threads in Linux
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
void* threadMethod(void* arg)
{
int intArg = (int) *((int*) arg);
int32_t pid = getpid();
uint64_t pti = pthread_self();
printf("[Thread %d] getpid() = %d\n", intArg, pid);
printf("[Thread %d] pthread_self() = %lu\n", intArg, pti);
}
int main()
{
pthread_t threads[2];
int thread1 = 1;
if ((pthread_create(&threads[0], NULL, threadMethod, (void*) &thread1))
!= 0)
{
fprintf(stderr, "pthread_create: error\n");
exit(EXIT_FAILURE);
}
int thread2 = 2;
if ((pthread_create(&threads[1], NULL, threadMethod, (void*) &thread2))
!= 0)
{
fprintf(stderr, "pthread_create: error\n");
exit(EXIT_FAILURE);
}
int32_t pid = getpid();
uint64_t pti = pthread_self();
printf("[Process] getpid() = %d\n", pid);
printf("[Process] pthread_self() = %lu\n", pti);
if ((pthread_join(threads[0], NULL)) != 0)
{
fprintf(stderr, "Could not join thread 1\n");
exit(EXIT_FAILURE);
}
if ((pthread_join(threads[1], NULL)) != 0)
{
fprintf(stderr, "Could not join thread 2\n");
exit(EXIT_FAILURE);
}
return 0;
}
On 64 bit Lubuntu 18.04, I compile it by the same command from the post:
$ gcc -pthread -o thread_test thread_test.c
I also try to follow what the post says:
By using scheduler locking in gdb, I can keep the program and its threads alive so I can capture what top
but because I am not familiar with gdb, the program runs to finish without pausing (see below). I also tried to set up breakpoint by break 43, but gdb says No line 40 in the current file. What shall I do to pause the execution, so that I can use top or ps to examine the threads' pid and tgid?
$ gdb thread_test
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 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 thread_test...(no debugging symbols found)...done.
(gdb) set scheduler-locking
Requires an argument. Valid arguments are off, on, step, replay.
(gdb) set scheduler-locking on
Target 'exec' cannot support this command.
(gdb) run
Starting program: /tmp/test/pthreads/thread_test
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff77c4700 (LWP 4711)]
[New Thread 0x7ffff6fc3700 (LWP 4712)]
[Thread 1] getpid() = 4707
[Thread 1] pthread_self() = 140737345505024
[Process] getpid() = 4707
[Process] pthread_self() = 140737353951040
[Thread 0x7ffff77c4700 (LWP 4711) exited]
[Thread 2] getpid() = 4707
[Thread 2] pthread_self() = 140737337112320
[Thread 0x7ffff6fc3700 (LWP 4712) exited]
[Inferior 1 (process 4707) exited normally]
(gdb)
You have two problems:
you built your program without debugging info (add -g flag), and
you are trying to set scheduler-locking on before the program started (that doesn't work).
This should work:
gcc -g -pthread -o thread_test thread_test.c
gdb -q ./thread_test
(gdb) start
(gdb) set scheduler-locking on
However, you must be extra careful with this setting -- simply continuing from this point will get your program to block in pthread_join, as only the main thread will keep running.
the following is an example of using gdb with the posted code to pause everything:
note: this was compiled to find/fix compile problems via:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c untitled.c
this was finally compiled/linked via:
gcc -ggdb -Wall -o untitled untitled.c -lpthread
then using the debugger: gdb, thereby showing my inputs and the gdb outputs:
$ gdb untitled
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 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 untitled...done.
(gdb) br main
Breakpoint 1 at 0x9a5: file untitled.c, line 20.
(gdb) br threadMethod
Breakpoint 2 at 0x946: file untitled.c, line 9.
(gdb) r
Starting program: /home/richard/Documents/forum/untitled
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at untitled.c:20
20 {
(gdb) c
Continuing.
[New Thread 0x7ffff77c4700 (LWP 8645)]
[New Thread 0x7ffff6fc3700 (LWP 8646)]
[Switching to Thread 0x7ffff77c4700 (LWP 8645)]
Thread 2 "untitled" hit Breakpoint 2, threadMethod (arg=0x7fffffffdf4c)
at untitled.c:9
9 int intArg = (int) *((int*) arg);
(gdb)
then you can (in another terminal window) use ps etc to display info. However, the thread function will output (to stdout the information you might be interested in.
or you can (in gdb enter commands like:
(gdb) c
[Process] getpid() = 8641
[Process] pthread_self() = 140737353992000
[Switching to Thread 0x7ffff6fc3700 (LWP 8646)]
Thread 3 "untitled" hit Breakpoint 2, threadMethod (arg=0x7fffffffdf50)
at untitled.c:9
9 int intArg = (int) *((int*) arg);
(gdb) c
....
[Thread 1] getpid() = 8641
[Thread 1] pthread_self() = 140737345505024
....
[Thread 2] getpid() = 8641
[Thread 2] pthread_self() = 140737337112320

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

How to use regexec with memory mapped files?

I am trying to find a regular expression in a large memory mapped file
by using regexec() function. I discovered that the program crashes when the file size
is the multiple of the page size.
Is there a regexec() function that has the length of the string
as additional argument?
Or:
How to find a regex in a memory mapped file?
Here is the minimal example that ALWAYS crashes
(if I run less that 3 threads program doesn't crash):
ls -la ttt.txt
-rwx------ 1 bob bob 409600 Jun 14 18:16 ttt.txt
gcc -Wall mal.c -o mal -lpthread -g && ./mal
[1] 11364 segmentation fault (core dumped) ./mal
And the program is:
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <regex.h>
void* f(void*arg) {
int size = 409600;
int fd = open("ttt.txt", O_RDONLY);
char* text = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
fd = open("/dev/zero", O_RDONLY);
char* end = mmap(text + size, 4096, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
close(fd);
assert(text+size == end);
regex_t myre;
regcomp(&myre, "XXXXX", REG_EXTENDED);
regexec(&myre, text, 0, NULL, 0);
regfree(&myre);
return NULL;
}
int main(int argc, char* argv[]) {
int n = 10;
int i;
pthread_t t[n];
for (i = 0; i < n; ++i) {
pthread_create(&t[n], NULL, f, NULL);
}
for (i = 0; i < n; ++i) {
pthread_join(t[n], NULL);
}
return 0;
}
P.S.
This is the output from gdb:
gdb ./mal
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04
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 "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/bob/prog/c/mal...done.
(gdb) r
Starting program: /home/srdjan/prog/c/mal
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff77ff700 (LWP 11817)]
[New Thread 0x7ffff6ffe700 (LWP 11818)]
[New Thread 0x7ffff6799700 (LWP 11819)]
[New Thread 0x7fffeffff700 (LWP 11820)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6799700 (LWP 11819)]
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:72
72 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
(gdb) bt
#0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:72
#1 0x00007ffff78df254 in __regexec (preg=0x7ffff6798e80, string=0x7fffef79b000 'a' <repeats 200 times>..., nmatch=<optimized out>,
pmatch=0x0, eflags=<optimized out>) at regexec.c:245
#2 0x00000000004008e6 in f (arg=0x0) at mal.c:24
#3 0x00007ffff7bc4e9a in start_thread (arg=0x7ffff6799700) at pthread_create.c:308
#4 0x00007ffff78f24bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#5 0x0000000000000000 in ?? ()
(gdb)
Celada correctly identifies the problem - the file data does not necessarily include a null terminator.
You could fix the problem by mapping a page of zeroes immediately after the file:
int fd;
char *text;
fd = open("ttt.txt", O_RDONLY);
text = mmap(NULL, 409600, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
fd = open("/dev/zero", O_RDONLY);
mmap(text + 409600, 4096, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
close(fd);
(Note that you can close fd immediately after the mmap(), because mmap() adds a reference to the open file description).
You should of course add error-checking to the above. Also, many UNIX systems support a MAP_ANONYMOUS flag which you can use instead of opening /dev/zero (but this is not in POSIX).
The problem is that regexec() is used to match a null-terminated string against the precompiled pattern buffer, but an mmaped file is not necessarily (indeed not usually) null-terminated. Thus, it is looking beyond the end of the file to find a NUL character (0 byte).
You would need a version of regexec() that takes a buffer and a size argument instead of a null-terminated string, but there doesn't appear to be one.

Resources