First a little preface: I'm using the Windows Subsystem for Linux and the Gaisler BCC version of GCC for cross-compiling (aka "machine-gcc" where the machine is sparc-gaisler-elf in this case).
I compile a simple hello world program for debugging like this
$ sparc-gaisler-elf-gcc -g hello.c -o hello
Then I open the simulator for the particular processor with the GNU debugger (GDB) as a server
$ tsim-leon3 -gdb
...
gdb interface: using port 1234
Starting GDB server. Use Ctrl-C to stop waiting for connection.
In another bash session I start a remote GDB and connect to the server
$ sparc-gaisler-elf-gdb -ex "target extended-remote localhost:1234"
...
Remote debugging using localhost:1234
This works fine. But if I try to load the hello executable I get a problem
$ sparc-gaisler-elf-gdb -ex "target extended-remote localhost:1234" hello
...
Remote debugging using localhost:1234
__text_start () at /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S:167
167 /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S: No such file or directory.
in /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S
Current language: auto; currently asm
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /mnt/c/Users/<username>/bcc-2.0.4-gcc/src/examples/hello/hello
Program received signal SIGSEGV, Segmentation fault.
__text_start () at /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S:167
167 in /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S
Now, with my Windows Subsystem for Linux setup I have the particular file it's looking for at
/mnt/c/Users/<username>/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S
instead of in /opt/bcc-2.0.4-gcc/...
How can I tell it where to find this file?
Update
I tried setting dir as per Employed Russian's answer
(gdb) dir /mnt/c/Users/<user>/bcc-2.0.4-gcc/src/libbcc/shared/trap
Source directories searched: /mnt/c/Users/<user>/bcc-2.0.4-gcc/src/libbcc/shared/trap:$cdir:$cwd
(gdb) list
162 BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B undefined
163 BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F undefined
164
165 /* trap_instruction 0x80 - 0xFF */
166 /* NOTE: "ta 5" can be generated by compiler. */
167 SOFT_TRAP; ! 0 System calls
168 SOFT_TRAP; ! 1 Breakpoints
169 SOFT_TRAP; ! 2 Division by zero
170 FLW_TRAP; ! 3 Flush windows
171 SOFT_TRAP; ! 4 Clean windows
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /mnt/c/Users/<user>/bcc-2.0.4-gcc/src/examples/hello/hello
Program received signal SIGSEGV, Segmentation fault.
__text_start () at /opt/bcc-2.0.4-gcc/src/libbcc/shared/trap/trap_table_mvt.S:167
167 SOFT_TRAP; ! 0 System calls
Even though it's still saying /opt/... it seems to have found the right file now. However, I don't know why it's giving a segmentation fault.
How can I tell it where to find this file?
With the directory command.
(gdb) dir /mnt/c/Users/<username>/bcc-2.0.4-gcc/src/libbcc/shared/trap
(gdb) list # should find the file in the new location
See also source path and set substitite-path.
Related
First I find the process' pid with ps:
% ps -a | grep 'a.out'
output:
36296 pts/0 00:00:07 a.out
Then I get an image of this process with gcore:
% sudo gcore 36296
output:
0x0000558eab27d131 in main ()
warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
Saved corefile core.36296
[Inferior 1 (process 36296) detached]
Then, hex dump object:
% hd core.36296 | grep 'HOME'
output:
001f4a90 3d 32 00 48 4f 4d 45 3d 2f 68 6f 6d 65 2f 63 61 |=2.HOME=/home/ca|
Now, I'm trying to find the section where environment variables is loaded. How can I do this ?
You should use a debugger!
For linux, gcc and gdb you can do:
> gdb <executable> <core-file>
Within gdb you now can examine the environment from the core file:
(gdb) print ((char**)__environ)[0]
$1 = 0x7ffc6aba0a58 "SHELL=/bin/bash"
(gdb) print ((char**)__environ)[1]
$2 = 0x7ffc6aba0a68 "SESSION_MANAGER=local/unix:#/tmp/.ICE-unix/1873,unix/unix:/tmp/.ICE-unix/1873"
unless you get a string with length 0.
If you do not have an executable with debug infos, you also can try to find the text with:
strings –a <core-file>
But before you write a core file and try to search in it, you simply can get the environment from a process by using ps if your program is still running:
ps eww <pid>
I'm troubleshooting a hung self test for the upcoming OpenSSL 1.1.0 on a particular machine. I've tried to debug this issue twice, and it resulted in two unresponsive GDB's and two hung processes:
$ ps -A | grep afalgtest
1030 pts/0 00:00:00 afalgtest
1196 pts/0 00:00:00 afalgtest
I was able to kill GDB, but I was not able to kill the hung processes.
According to /proc/<pid>/syscall, both are in syscall 248:
via:test$ sudo cat /proc/1030/syscall
248 0xb7fd6000 0x1 0xbfff98d4 0xb7fb9270 0xbfff98e0 0xb7ec45f7 0xbfff986c 0xb7fdbbe8
via:test$ sudo cat /proc/1196/syscall
248 0xb7fd6000 0x1 0xbfff98d4 0xb7fb9270 0xbfff98e0 0xb7ec45f7 0xbfff986c 0xb7fdbbe8
I'm running a machine with the VIA C7-D processor, and it needs Lubuntu 15 because its one of the few distros to support VIA's PM400 graphics chipset. Lubuntu 15 uses the 4.2 kernel:
$ uname -a
Linux via 4.2.0-30-generic #36-Ubuntu SMP Fri Feb 26 00:57:19 UTC 2016 i686 i686 i686 GNU/Linux
The next step is:
$ cat /usr/include/asm-generic/unistd.h | grep 248
$
Which returns nothing. Next, cat'ing unistd.h:
...
/*
* Architectures may provide up to 16 syscalls of their own
* starting with this value.
*/
#define __NR_arch_specific_syscall 244
#define __NR_wait4 260
__SC_COMP(__NR_wait4, sys_wait4, compat_sys_wait4)
#define __NR_prlimit64 261
__SYSCALL(__NR_prlimit64, sys_prlimit64)
#define __NR_fanotify_init 262
__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
#define __NR_fanotify_mark 263
...
Just in case 248 is 0x248:
$ cat /usr/include/asm-generic/unistd.h | grep 584
$
So my question is, how can I determine which syscall the process is hung in?
It appears I have the latest kernel headers:
$ sudo apt-get install linux-headers-$(uname -r)
Reading package lists... Done
Building dependency tree
Reading state information... Done
linux-headers-4.2.0-30-generic is already the newest version.
linux-headers-4.2.0-30-generic set to manually installed.
The syscall number is decimal. Syscall table you are looking for can be found in arch/x86/entry/syscalls/syscall_32.tbl. Regardless, you are inspecting the wrong file. What you want to see is the entire backtrace provided in /stack file. The kernel is nice enough to not only unwind the stack but also resolve all symbols. Alternatively you can use a debugger (named crash) to inspect the live kernel.
on FreeBSD I started to play around with LLDB, but it crashes right at the start.
user#host ~/sandbox % rake hello
cc -I/usr/local/include -g -O0 -o hello.o -c hello.c
cc -Wl,-L/usr/local/lib -o hello hello.o
user#host ~/sandbox % lldb
(lldb) target create hello
Current executable set to 'hello' (i386).
(lldb) source list
8 {
9 printf( "Hello, world!\n");
10 return 0;
11 }
12
(lldb) breakpoint set -f hello.c -l 9
Breakpoint 1: where = hello`main + 31 at hello.c:9, address = 0x080485af
(lldb) process launch
Process 2409 launching
Process 2409 stopped
(lldb) Process 2409 launched: '/usr/home/user/sandbox/hello' (i386)
Process 2409 stopped
* thread #1: tid = 100224, 0x0818188f, stop reason = hardware error
frame #0: 0x0818188f
-> 0x818188f: addb %al, (%eax)
0x8181891: addb %al, (%eax)
0x8181893: addb %al, (%eax)
0x8181895: addb %al, (%eax)
(lldb)
It is the same on three machines.
I have also tried Gdb on Linux. There, everything worked fine.
What did I do wrong?
Thanks in advance,
Bertram
LLDB doesn't support FreeBSD/i386 host for now. Use recent gdb from ports or switch to amd64.
I'm trying to learn about ARM assembler programming using the GNU assembler. I've setup my PC with QEmu and have a Debian ARM-HF chroot environment.
If I assemble and link my test program:
.text
.global _start
_start:
mov r0, #6
bx lr
with:
as test.s -o test.o
ld test.o -o test
Then load the file into gdb and set a breakpoint on _start:
root#Latitude-E6420:/root# gdb test
GNU gdb (GDB) 7.6.1 (Debian 7.6.1-1)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
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 "arm-linux-gnueabihf".
For bug reporting instructions, please see:
...
Reading symbols from /root/test...(no debugging symbols found)...done.
(gdb) break _start
Breakpoint 1 at 0x8054
(gdb)
How do I single step the code, display the assembler source code and monitor the registers?
I tried some basic commands and they did not work:
(gdb) break _start
Breakpoint 1 at 0x8054
(gdb) info regi
The program has no registers now.
(gdb) stepi
The program is not being run.
(gdb) disas
No frame selected.
(gdb) r
Starting program: /root/test
qemu: Unsupported syscall: 26
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
qemu: Unsupported syscall: 26
During startup program terminated with signal SIGSEGV, Segmentation fault.
(gdb)
Your problem here is that you're trying to run an ARM gdb under QEMU's user-mode emulation. QEMU doesn't support the ptrace syscall (that's what syscall number 26 is), so this is never going to work.
What you need to do is run your test binary under QEMU with the QEMU options to enable QEMU's own builtin gdb stub which will listen on a TCP port. Then you can run a gdb compiled to run on your host system but with support for ARM targets, and tell that to connect to the TCP port.
(Emulating ptrace within QEMU is technically very tricky, and it would not provide much extra functionality that you can't already achieve via the QEMU builtin gdbstub. It's very unlikely it'll ever be implemented.)
Minimal working QEMU user mode example
I was missing the -fno-pie -no-pie options:
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 -fno-pie -ggdb3 -no-pie -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 \
-ex 'layout split'
;
This leaves us at main, in a split code / disassembly view due to layout split. You will also interested in:
layout regs
which shows the registers.
At the end of the day however, GDB Dashboard is more flexible and reliable: gdb split view with code
-fno-pie -no-pie is required because the packaged Ubuntu GCC uses -fpie -pie by default, and those fail due to a QEMU bug: How to GDB step debug a dynamically linked executable in QEMU user mode?
There was no gdbserver --multi-like functionality for the QEMU GDB stub on QEMU 2.11: How to restart QEMU user mode programs from the GDB stub as in gdbserver --multi?
For those learning ARM assembly, I am starting some runnable examples with assertions and using the C standard library for IO at: https://github.com/cirosantilli/arm-assembly-cheat
Tested on Ubuntu 18.04, gdb-multiarch 8.1, gcc-arm-linux-gnueabihf 7.3.0, qemu-user 2.11.
Freestanding QEMU user mode example
This analogous procedure also works on an ARM freestanding (no standard library) example:
printf '
.data
msg:
.ascii "hello world\\n"
len = . - msg
.text
.global _start
_start:
/* write syscall */
mov r0, #1 /* stdout */
ldr r1, =msg /* buffer */
ldr r2, =len /* len */
mov r7, #4 /* Syscall ID. */
swi #0
/* exit syscall */
mov r0, #0 /* Status. */
mov r7, #1 /* Syscall ID. */
swi #0
' > hello_world.S
arm-linux-gnueabihf-gcc -ggdb3 -nostdlib -o hello_world -static hello_world.S
qemu-arm -g 1234 ./hello_world
On another terminal:
gdb-multiarch -q --nh \
-ex 'set architecture arm' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'layout split' \
;
We are now left at the first instruction of the program.
QEMU full system examples
Linux kernel: How to debug the Linux kernel with GDB and QEMU?
Bare metal: https://github.com/cirosantilli/newlib-examples/tree/f70f8a33f8b727422bd6f0b2975c4455d0b33efa#gdb
Single step of an assembly instruction is done with stepi. disas will disassemble around the current PC. info regi will display the current register state. There are some examples for various processors on my blog for my ELLCC cross development tool chain project.
You should add the -g option too to the assembling. Otherwise the codeline info is not included.
That crash probably comes from running some garbage after the code lines.
Maybe you should add the exit system call:
mov eax, 1 ; exit
mov ebx, 0 ; returm value
int 0x80 ; system call
I try to open a network connection through a pair of pseudo tty's on linux os.
# slattach -v /dev/ptmx
cslip started on /dev/ptmx interface sl0
OK, this was the "creating side" for the pseudo tty.
I can look in /dev/pts and find the new pty there.
If I now try to use slattach also on this side I got:
slattach -v /dev/pts/3
slattach: tty_open(/dev/pts/3, RW): Input/output error
I traced with strace:
28 5505 write(1, "slattach: tty_open: trying to op"..., 46) = 46
29 5505 open("/dev/pts/3", O_RDWR|O_NONBLOCK) = -1 EIO (Input/output error)
30 5505 write(2, "slattach: tty_open(/dev/pts/3, R"..., 55) = 55
31 5505 exit_group(3)
All this happens on different distros of ubuntu, tested on 10.04 and 11.04, both are failing.
What I'm doing wrong?
You may want to take a look at the man page pty(7).
Basically, /dev/ptmx uses the Unix 98 pseudo-terminal interface and requires that your program uses grantpt(3) and unlockpt(3). Here, slattach (the one that opens /dev/ptmx, not the other one) doesn't do so, and any program that tries to open the slave pseudo-terminal associated to the master will fail, as you experienced.
You can force slattach to do grantpt() and unlockpt() by overloading the open() call with an external
routine, see this example