Debugging code through KGDB - remote-debugging

I want to debug my code which has some kernel module also. I am able to set breakpoints in kernel as well as in my code. Performing operation hits breakpoints set in kernel code but doesn't hit the breakpoints in my code.
target machine : Machine on which code is to be debugged
host machine : Machine which is used to debug the code
Steps followed:
on host :
$ gdb vmlinux
(vmlinux copied from target machine )
$ gdb> target remote /dev/ttyS1
$ cont
continuing
on target :
$ insmod mymodule.ko
$ cd /sys/module/mymodule/sections/
$ cat .data
$ cat .rodata
$ cat .bss
$ cat .text
$ echo "g" > /proc/sysrq-trigger
on host :
$ add-symbol-file <module_name> <address> \
-s .bss <address> \
-s .rodata <address> \
-s .data <address>
$ b file_name //set break points
$ c
continuing
on target:
execute the command(program) .....but it does not hit the breakpoints......finishes the execution without hitting breakpoints.
But when I tried to set breakpoints to some kernel function like vfs_read(), break-point is being hit.

Related

Is there a simple way to dump the export object value from a shared library?

For example, there is a symbol named country, I can get its information (type, address, and length) by nm -D -S
$ nm -D libs_ma.so -S
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w __cxa_finalize
w __gmon_start__
0000000000004028 0000000000000008 D country
But how can I dump the address (4028) with length (8) by some Linux command (just like dlsym() and printf() worked in c program)?
how can I dump the address (4028) with length (8) by some Linux command
Your best bet is probably to use a debugger, such as radare2 or GDB.
This question shows how to do that in radare2.
Here is how you could do this using GDB:
// foo.c
long country = 0xABCDEF0123456789;
gcc -shared -fPIC -o foo.so foo.c
nm -D foo.so | grep country
0000000000004020 D country
gdb -q --batch -ex 'x/gx 0x4020' foo.so
0x4020 <country>: 0xabcdef0123456789
It is also rather easy to write a program in a language of your choice to do this. Your program would have to:
iterate over LOAD segments until it finds one with .p_vaddr <= $address < .p_vaddr + .p_memsz
mmap or read that segment, seek to $address - .p_vaddr offset, and dump $length bytes from there.

gdb fails to insert a breakpoint even if compiled with -no-pie

I'm trying to get gdb working with C++ programs on Ubuntu 20.04. What I need is to be able to set a breakpoint (for example, break main.cpp:3 gdb command) and then run until the breakpoint, but at the moment both start and run fail because they "Cannot insert breakpoint" and "Cannot access memory". For me gdb fails even with very simple examples. This is main.cpp content:
#include <iostream>
int main() {
std::cout << "Hello World!";
return 0;
}
I found somewhere that using -no-pie might help to get gdb working (with breakpoints), so I compile the program by running g++ -ggdb3 -no-pie -o main main.cpp (I also tried -g instead of -ggdb3, and -fno-PIE in addition to -no-pie). When I try to use gdb, it complains "Cannot insert breakpoint 1":
gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.
Starting program: /tmp/main
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x1189
Without -no-pie result is the same. Only thing that changes with or without -no-pie is the hexadecimal address, without -no-pie it is low like 0x1189 (as shown above), with -no-pie it can be 0x401176, but everything else exactly the same, I keep getting the "Cannot access memory at address" warning in both cases.
If I use starti instead of start, it works at first, but after a few nexti iterations it prints usual message "Cannot insteart breakpoint":
gdb -q main
Reading symbols from main...
(gdb) starti
Starting program: /tmp/main
Program stopped.
0x00007ffff7fd0100 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) nexti
0x00007ffff7fd0103 in ?? () from /lib64/ld-linux-x86-64.so.2
...
(gdb) nexti
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x4
0x00007ffff7fd0119 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) nexti
0x00007ffff7fd011c in ?? () from /lib64/ld-linux-x86-64.so.2
...
(gdb) nexti
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x1c
0x000055555556ca22 in ?? ()
(gdb) nexti
[Detaching after fork from child process 3829827]
...
[Detaching after fork from child process 3829840]
Hello World![Inferior 1 (process 3819010) exited normally]
So I can use nexti, but cannot use next and obviously cannot insert breakpoints.
I tried -Wl,-no-pie (by running g++ -Wl,-no-pie -ggdb3 -o main main.cpp; adding -no-pie does not change anything) but this option causes a strange linker error:
/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
When I google the error, I only found advice to try -no-pie instead of -Wl,-no-pie, and no other solutions. Since debugging C++ programs is very common activity, I feel like I'm missing something obvious but I found no solution so far.
To make it easier to understand what exact commands I use and to make it clear I'm not mixing up directories and to show what versions of g++ and gdb I'm using, here is full terminal log:
$ ls
main.cpp
$ g++ --version | grep Ubuntu
g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0
$ g++ -ggdb3 -no-pie -o main main.cpp
$ ls
main main.cpp
$ gdb --version | grep Ubuntu
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
$ readelf -h main | grep 'Type: .*EXEC'
Type: EXEC (Executable file)
$ gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x401176: file main.cpp, line 3.
Starting program: /tmp/main/main
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x401176
For completeness, I tried the same without -no-pie:
$ rm main
$ g++ -ggdb3 -o main main.cpp
$ readelf -h main | grep 'Type: .*'
Type: DYN (Shared object file)
$ gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.
Starting program: /tmp/main/main
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x1189
As you can see the only difference with or without -no-pie is the memory address, but the issue and warnings are the same. Without -no-pie this may be expected, but I do not understand why this is happening if I compiled with -no-pie and what else I can try to solve the issue.
This:
g++ -ggdb3 -no-pie -o main main.cpp
should produce a non-PIE executable. You should be able to verify that it non-PIE by looking at readelf -h main | grep 'Type: .*EXEC' (PIE binaries have ET_DYN type).
This:
Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.
is unambiguously a PIE binary (a non-PIE binary will not have any code below 0x40000 on x86_64 Linux).
Conclusion: you are either debugging the wrong binary (e.g. you are compiling main in a different directory from the one in which you are debugging), or you are not telling is the whole story.

How to GDB step debug a dynamically linked executable in QEMU user mode?

For example for ARM, if I compile statically, all works fine:
sudo apt-get install gdb-multiarch gcc-arm-linux-gnueabihf qemu-user
printf '
#include <stdio.h>
#include <stdlib.h>
int main() {
puts("hello world");
return EXIT_SUCCESS;
}
' > hello_world.c
arm-linux-gnueabihf-gcc -ggdb3 -static -o hello_world hello_world.c
qemu-arm -L /usr/arm-linux-gnueabihf -g 1234 ./hello_world
On another terminal:
gdb-multiarch -q --nh \
-ex 'set architecture arm' \
-ex 'set sysroot /usr/arm-linux-gnueabihf' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'break main' \
-ex continue \
;
This leaves me at main, and I can see the source and step debug as usual.
However, if I remove the -static, and keep everything else unchanged, my breakpoint never gets hit, and the program runs until completion:
The target architecture is assumed to be arm
Reading symbols from hello_world...done.
Remote debugging using localhost:1234
Reading symbols from /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3...(no debugging symbols found)...done.
0xff7b3b80 in ?? () from /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3
Breakpoint 1 at 0x50c: file hello_world.c, line 5.
Continuing.
[Inferior 1 (Remote target) exited normally]
The executable itself does work fine however:
qemu-arm -L /usr/arm-linux-gnueabihf ./hello_world
prints:
hello world
I have seen: How to single step ARM assembler in GDB on Qemu? but it didn't cover the case of dynamically linked executables specifically.
Tested on Ubuntu 18.04, gdb-multiarch 8.1-0ubuntu3, gcc-arm-linux-gnueabihf 4:7.3.0-3ubuntu2, qemu-user 1:2.11+dfsg-1ubuntu7.3.
Edit: working pristine crosstool-ng setup
As a sanity check, I tried to get a clean toolchain with crosstool-ng, and it worked:
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout d5900debd397b8909d9cafeb9a1093fb7a5dc6e6
export CT_PREFIX="$(pwd)/.build/ct_prefix"
./bootstrap
./configure --enable-local
./ct-ng arm-cortex_a15-linux-gnueabihf
# Has to be older than host kernel, which is 4.15.
printf "
CT_LINUX_V_4_14=y
CT_LINUX_VERSION=\"4.14.0\"
" >> .config
./ct-ng oldconfig
env -u LD_LIBRARY_PATH time ./ct-ng build -j`nproc`
cd ..
crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/bin/arm-cortex_a15-linux-gnueabihf-gcc -ggdb3 -o hello_world hello_world.c -ggdb3 -static -o hello_world hello_world.c
qemu-arm -L crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/arm-cortex_a15-linux-gnueabihf/sysroot -g 1234 ./hello_world
And on another shell:
./.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/bin/arm-cortex_a15-linux-gnueabihf-gdb \
-q --nh \
-ex 'set architecture arm' \
-ex 'set sysroot crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/arm-cortex_a15-linux-gnueabihf/sysroot' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'break main' \
-ex continue \
;
And it also works with the distro provided gdb-multiarch.
The failure is due to -pie -fpie, and there is a bug report for it at: https://bugs.launchpad.net/qemu/+bug/1528239
Explicitly setting -no-pie -fno-pie makes it work on both crosstool-ng and Ubuntu host.
The difference is that the Ubuntu one has GCC built to use -fpie by default, while my crosstool-ng build did not.
This can be checked with:
gcc -v
which on the host GCC contains:
--enable-default-pie
but not in the crosstool-ng build.
How I found this out: the other day I was playing around with -fpie and I noticed that the .text addresses were really small in that case: What is the -fPIE option for position-independent executables in gcc and ld?
Then I saw that the break address was very small with the packaged toolchain, and made the link.

How to run HelloWorld on ARM

I need to run HelloWorld on arm.
I launch:
$ arm-none-eabi-g++ -mthumb -mcpu=cortex-m3 -c test.cpp -o test
$ file test
test: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
$ qemu-arm test <br>
Error while loading test: Permission denied
qemu-system-arm -machine help
...
lm3s811evb Stellaris LM3S811EVB
...
From either the lm3s811 datasheet or looking at the source for the stellaris backend on qemu arm hardware. Uart0 base address is 0x4000C000, the data (rx and tx) register is offset 0x000. From experience the qemu backends tend not to bother with the tx buffer being busy...
flash.s
.cpu cortex-m0
.thumb
.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
uart01.c
void PUT32 ( unsigned int, unsigned int );
#define UART0BASE 0x4000C000
int notmain ( void )
{
unsigned int rx;
for(rx=0;rx<7;rx++)
{
PUT32(UART0BASE+0x00,0x30+rx);
}
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Yep, the stellaris was the first cortex-m3 in silicon that you could buy and I specified cortex-m0. Basically preventing the thumb2 extensions, or most of them. More portable, can easily change that if you want.
arm-none-eabi-as --warn -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c uart01.c -o uart01.o
arm-none-eabi-ld -o uart01.elf -T flash.ld flash.o uart01.o
arm-none-eabi-objdump -D uart01.elf > uart01.list
arm-none-eabi-objcopy uart01.elf uart01.bin -O binary
then
qemu-system-arm -M lm3s811evb -m 16K -nographic -kernel uart01.bin
and the output is
0123456
ctrl-a then press x to exit qemu. or
qemu-system-arm -M lm3s811evb -m 16K -kernel uart01.bin
then ctrl-alt-3 (3 not F3) and the serial console pops up with the serial output. when you close that serial console qemu closes.
I want to remember someone telling me that the qemu cortex-m3 support is not that good.
the normal arm cores should be well tested as they are used to cross compile for all kinds of arm target boards. not sure exactly which cores are well tested, but you could do thumb stuff if you booted like an arm but did the rest in thumb, boot with
.globl _start
_start:
b reset
b hang
b hang
b hang
reset:
mov sp,#0x20000
bl notmain
hang:
b hang
the machine
versatilepb ARM Versatile/PB (ARM926EJ-S)
has its uart at 0x101f1000, so
for(ra=0;;ra++)
{
ra&=7;
PUT32(0x101f1000,0x30+ra);
}
can build your app with
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=arm7tdmi -mthumb -c uart01.c -o uart01.o
change your linker script to be all ram based.
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
and then
qemu-system-arm -M versatilepb -m 128M -nographic -kernel hello.bin
(hmmm, does this load at 0x0000, or 0x8000?, shouldnt be too hard to figure out)
you can get mostly the thumb feel of a cortex-m (an m0 basically not an m3, you can find an armv7-a machine you can probably run thumb2 built code (still boots like an arm not a cortex-m)). for example
realview-pb-a8 ARM RealView Platform Baseboard for Cortex-A8
Can probably use newlib almost as is, need to change the crt0.s or whatever it is called these days to boot like an arm not a cortex-m. The rest can build using armv7m and in theory will work.
And or start with the stellaris and just make your own hw support for whatever your real target is and fix the cortex-m3 core if/when you find problems.

What is the lldb equivalent of gdb's --args?

I'm used to running gdb like so:
$ gdb --args exe --lots --of --flags -a -b -c d e
...
(gdb) r
Is there an equivalent for lldb?
Yes, it's just -- instead of --args. From the help:
lldb -v [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]
Thus:
$ lldb -- exe --lots --of --flags -a -b -c d e
You can also start lldb first and use:
(lldb) settings set target.run-args 1 2 3
(lldb) run
or:
(lldb) process launch -- <args>