I have two source files:
main3.asm
prt_dec.asm
I compile and link the files with the following commands:
nasm -f elf -g -F stabs main3.asm
nasm -f elf -g -F stabs prt_dec.asm
ld -m elf_i386 main3.o prt_dec.o
I run gdb with the following command:
gdb ./a.out
All is well. There are no compilation or linking errors and the program returns the desired results. However, I would like to step through the program with gdb to better understand the internals and the debugging tool itself. The problem I run into is this:
Although gdb calls the externally defined subroutine prt_dec, it doesn't appear to have access to the source code in which it was defined. For example, if use the following command in gdb:
(gdb) list main3.asm:1
I get the first 10 lines of the main3.asm source code file. However, when I try to use the same command on the other source code file:
(gdb) list prt_dec.asm:1
I get the error "No source file named prt_dec.asm"
What's going on here? Why can't gdb see the source code for the other file that was linked?
If it helps, I've include the source code files below (both files have been shortened and irrelevant code removed):
main3.nasm:
SECTION .data ; initialized data section
lf: db 10 ; just a linefeed
SECTION .text ; Code section.
global _start ; let loader see entry point
extern prt_dec
_start:
push dword 42
call prt_dec
add esp, 4
mov eax, 4 ; write message
mov ebx, 1
mov ecx, lf
mov edx, 1 ; LF is a single character
int 080h
exit: mov eax, 1 ; exit function
mov ebx, 0 ; exit code, 0=normal
int 080h ; ask kernel to take over
prt_dec.asm:
[section .data]
digits: db "0123456789" ; decimal digits lookup table
[section .bss]
outputBuffer: resb 10 ; largest 32-bit value represented in decimal
; is 10 digits (2^32)
[section .txt]
global prt_dec
prt_dec:
; code here takes 32-bit value on stack when
; subroutine was called, converts and stores the decimal
; representation of the 32-bit value in outputBuffer,
; and writes the result to stdout
ret
Related
When writing assembly manually with GNU GAS, within a function, I want to set a label such that:
GDB won't treat that label as the function name
I can use b mylabel to break on the label
A similar question for nasm has been asked at: Break at local label using GDB for NASM assembly but I wanted to make it more precise here that I want GNU GAS and ELF output.
E.g. if I defined a normal label mylabel as in:
main.S
.text
.global _start
_start:
/* exit */
mov $60, %rax
mylabel:
mov $0, %rdi
syscall
that does not satisfy me because when GDB reaches the mov $0, %rdi, bt shows mylabel as the function name, and I would like it to be _start instead. In particular, this can break backtraces because GDB can't find the stack frame: How gdb reconstructs stacktrace for C++?
However, if I replace mylabel with .Lmylabel as explained at: Local labels in GNU assembler; gdb printing backtrace as though labels are functions then _start is the function name as desired, but b .Lmylabel fails. nm does not show the symbol at all either.
Does the ELF / DWARF formats support anything that could be used, and is there any way to expose that though GNU GAS?
Tested in Ubuntu 18.10, GDB 8.2, GNU GAS 2.31.1.
I'm not sure if this fits your needs, but you can do this (for a non-PIE binary, so link with -no-pie):
.text
.global _start
_start:
/* exit */
mov $60, %rax
.Lmylabel:
mov $0, %rdi
syscall
.section .rodata
mylabel:
.long .Lmylabel
Then, you can set a breakpoint using break *mylabel (note the *):
(gdb) break *mylabel
Breakpoint 2 at 0x401007: file t.S, line 7.
Since mylabel is more or less a function pointer, GDB does not know anything about it and will ignore it:
Breakpoint 1, _start () at t.S:5
5 mov $60, %rax
(gdb) si
7 mov $0, %rdi
With a linker script, it should be possible to put the mylabel symbol into a section which is not loaded, to reduce run-time overhead.
I have an executable running on some client. He reports a crash at mymodule.dll!0xaddr.
Given that I have the executable, a symbol server, a properly set up WinDbg, is there any way to see the code at location 0xaddr without loading a dump or attaching to a running process?
It depends a bit on what "code" is for you...
Start WinDbg
Choose "Open crash dump ...", not "Open executable ..."
Select the EXE or DLL file of your choice, not a DMP file
Set up your symbols
Type ln mymodule.dll!0xaddr to see what symbol is near that address
Type u mymodule.dll!0xaddr to see the assembler code
If the EXE or DLL has PDB information and WinDbg was able to find the PDB, and if the PDB refers to source (e.g. private symbols), you'll get something useful:
0:000> ln 00412510
[...\addressdemo\addressdemo.cpp # 8] (00412510) AddressDemo!main | (00412575) AddressDemo!std::uncaught_exception
Exact matches:
0:000> u 00412510
AddressDemo!main [...\projects\addressdemo\addressdemo.cpp # 8]:
00412510 55 push ebp
00412511 8bec mov ebp,esp
00412513 81ecc0000000 sub esp,0C0h
00412519 53 push ebx
0041251a 56 push esi
0041251b 57 push edi
I'm following these lessons from OpenSecurityTraining.
I've reached the lab part where I've to train myself on a CMU Bomb. They provide a x86_64 compiled CMU Bomb that you can find here to train on : CMU Bomb x86-64 originally from a 32-bit bomb from CMU Labs for
Computer Systems: A Programmer's Perspective (CS:APP) 1st edition.
I had a virtualized 64 bits Elementary OS distribution where I disassembled the CMU Bomb without problems using GDB. Now, I've a 64 bits Ubuntu 14.04 LTS (not virtualized) and when I try to reproduce why I did on my Elementary OS, I get the famous error.
I run these commands :
gdb ./bomb-x64
(gdb) b main
Breakpoint 1 at 0x400dbd: file bomb.c, line 37. -- why bomb.c ?
(gdb) r
...
bomb.c: no such file or directory
Edit : I can create breakpoints on others functions of the CMU Bomb and it works as expected.
Example :
(gdb) b phase_1
Breakpoint 3 at 0x400f00
(gdb) r
Breakpoint 1, 0x0000000000400f00 in phase_1 ()
(gdb) disas
Dump of assembler code for function phase_1:
=> 0x0000000000400f00 <+0>: sub $0x8,%rsp
0x0000000000400f04 <+4>: mov $0x4023b0,%esi
0x0000000000400f09 <+9>: callq 0x401308 <strings_not_equal>
0x0000000000400f0e <+14>: test %eax,%eax
0x0000000000400f10 <+16>: je 0x400f17 <phase_1+23>
0x0000000000400f12 <+18>: callq 0x40140a <explode_bomb>
0x0000000000400f17 <+23>: add $0x8,%rsp
0x0000000000400f1b <+27>: retq
End of assembler dump.
I've heard of ia32-libs but this doesn't do anything more since I'm on 64bits Ubuntu and run a 64bits compiled CMU Bomb, am I wrong ?
Use dir command to set source path
dir /usr/src/debug
in above path. Your code should present.
The executable contains debugging symbols, which indicate the file (and particular line in the file) corresponding to each bit of assembled code. This is what allows you to step through C code in the debugger. The debugging symbols are put there by the compiler (e.g. by using the -g argument to gcc).
If you don't have the C files that were used to compile the executable, the debugger won't be able to show you the C, and you'll be limited to looking at assembly.
(gdb) list
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c: No such file or directory.
(gdb) set substitute-path /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/ C:/Espressif/frameworks/esp-idf-v4.4/
My test case is so simple that I must be doing something very stupid. I wrote a simple source file test.c:
#include<stdio.h>
int main(int argc,char* argv[]){
printf("1\n");
printf("2\n");
printf("3\n");
return 0;
}
I compiled it with gcc -g test.c and started GDB with gdb a.out. Then I created a breakpoint in main with break main and ran it with run(also tried with start) - but GDB simply ignored my breakpoint!
This is the shell session of me trying to compile test.c and run GDB:
[idanarye#idanarye_lg gdbtest]$ gcc -g test.c
[idanarye#idanarye_lg gdbtest]$ gdb a.out
GNU gdb (GDB) 7.6.1
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/idanarye/gdbtest/a.out...done.
(gdb) break main
Breakpoint 1 at 0x40050f: file test.c, line 4.
(gdb) run
Starting program: /home/idanarye/gdbtest/a.out
1
2
3
During startup program exited normally.
(gdb)
What in the world am I doing wrong here?
I'm running a 64bit Arch Linux. My GCC version is 4.8.2.
UPDATE
Here is the result of disas main:
Dump of assembler code for function main:
0x0000000000400500 <+0>: push %rbp
0x0000000000400501 <+1>: mov %rsp,%rbp
0x0000000000400504 <+4>: sub $0x10,%rsp
0x0000000000400508 <+8>: mov %edi,-0x4(%rbp)
0x000000000040050b <+11>: mov %rsi,-0x10(%rbp)
0x000000000040050f <+15>: mov $0x4005c4,%edi
0x0000000000400514 <+20>: callq 0x4003e0 <puts#plt>
0x0000000000400519 <+25>: mov $0x4005c6,%edi
0x000000000040051e <+30>: callq 0x4003e0 <puts#plt>
0x0000000000400523 <+35>: mov $0x4005c8,%edi
0x0000000000400528 <+40>: callq 0x4003e0 <puts#plt>
0x000000000040052d <+45>: mov $0x0,%eax
0x0000000000400532 <+50>: leaveq
0x0000000000400533 <+51>: retq
End of assembler dump.
UPDATE
No idea how or why, but it works now. Probably a system update fixed it...
(curated from comments)
You do not appear do be doing anything wrong; It appears to be GDB's fault.
The message During startup program exited normally. is anomalous, the correct one being Program exited normally.. It suggests GDB failed to insert a breakpoint in main() or the traced program's call to ptrace(PT_TRACE_ME, 0, 0, 0) failed. The program thus ran without being stopped, and it exited while GDB was only expecting it to start up and stop at exec(). Can you run gdb under strace while doing your example and grep strace's log for any failed ptrace calls?
You would do so with strace -f -o syscall.txt gdb ./a.out.
As of right now a stop-gap measure appears to be to run GDB as root.
I encountered a similar problem and in my case the thing was that my program was forking itself. So basically, my code looked like this:
#include <string>
#include <iostream>
#include "func.hpp"
using namespace std;
int main(int argc, char **argv)
{
if(argc <3)
{
printf("\n %s IP PORT\n",argv[0]);
printf("e.g. %s 10.32.129.77 6379\n",argv[0]);
printf("\n Going to run on the default server and port\n");
string command{argv[0]};
command+=" 10.32.129.77 6379";
printf("\nCommand: %s\n",command.c_str());
system(command.c_str());
exit(0);
}
func();
}
I was creating a breakpoint where "func" function was being called. However, I unknowingly wasn't passing the correct arguments and as a result my program forked itself with correct arguments. So basically "func" was now being called from the child process and as it turns out gdb doesn't set the breakpoints at the child process and that's why the breakpoint was not being hit.
I had this same problem. It was intermittent and drove me nuts.
Then I found I did a dumb thing. I had been running the program from the command line, and it had a bunch of arguments.
So, I copied the command line with the mouse-copy-paste buffer.
Then started: gdb Program
Then did: break man
Then did: -PASTE-FROM-MOUSE-
It never stopped, until I realized that I had pasted too much of the command line:
"--option=c ... |& tee LOG"
It looked like an intermittent problem, until I realized it was a brain bug.
Hope this helps someone. The command line redirect - did something in GDB, no clue what (other than ignore breakpoints).
I'm trying to disassemble a program to see a syscall assembly instruction (the INT instruction, I believe) and the handler with GDB and have written a little program (see below) for it that opens and closes a file.
I was able to follow the call to fopen with GDB until it executed a call.
When I tried to tell GDB "disassemble 0x...." (address of call) it responded with 'No function contains specified address.'
Is it possible to force GDB to disassemble (or display it in assembler as good as possible) that memory address? If so, how?
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE* f;
f = fopen("main.c", "r");
if (!f) {
perror("open");
return -1;
}
fclose(f);
return 0;
}
Yeah, disassemble is not the best command to use here.
The command you want is "x/i" (examine as instructions):
(gdb) x/i 0xdeadbeef
Do you only want to disassemble your actual main? If so try this:
(gdb) info line main
(gdb) disas STARTADDRESS ENDADDRESS
Like so:
USER#MACHINE /cygdrive/c/prog/dsa
$ gcc-3.exe -g main.c
USER#MACHINE /cygdrive/c/prog/dsa
$ gdb a.exe
GNU gdb 6.8.0.20080328-cvs (cygwin-special)
...
(gdb) info line main
Line 3 of "main.c" starts at address 0x401050 <main> and ends at 0x401075 <main+
(gdb) disas 0x401050 0x401075
Dump of assembler code from 0x401050 to 0x401075:
0x00401050 <main+0>: push %ebp
0x00401051 <main+1>: mov %esp,%ebp
0x00401053 <main+3>: sub $0x18,%esp
0x00401056 <main+6>: and $0xfffffff0,%esp
0x00401059 <main+9>: mov $0x0,%eax
0x0040105e <main+14>: add $0xf,%eax
0x00401061 <main+17>: add $0xf,%eax
0x00401064 <main+20>: shr $0x4,%eax
0x00401067 <main+23>: shl $0x4,%eax
0x0040106a <main+26>: mov %eax,-0xc(%ebp)
0x0040106d <main+29>: mov -0xc(%ebp),%eax
0x00401070 <main+32>: call 0x4010c4 <_alloca>
End of assembler dump.
I don't see your system interrupt call however. (its been a while since I last tried to make a system call in assembly. INT 21h though, last I recall
This isn't the direct answer to your question, but since you seem to just want to disassemble the binary, perhaps you could just use objdump:
objdump -d program
This should give you its dissassembly. You can add -S if you want it source-annotated.
You can force gcc to output directly to assembly code by adding the -S switch
gcc -S hello.c
fopen() is a C library function and so you won't see any syscall instructions in your code, just a regular function call. At some point, it does call open(2), but it does that via a trampoline. There is simply a jump to the VDSO page, which is provided by the kernel to every process. The VDSO then provides code to make the system call. On modern processors, the SYSCALL or SYSENTER instructions will be used, but you can also use INT 80h on x86 processors.
If all that you want is to see the disassembly with the INTC call, use objdump -d as someone mentioned but use the -static option when compiling. Otherwise the fopen function is not compiled into the elf and is linked at runtime.
gdb disassemble has a /m to include source code alongside the instructions. This is equivalent of objdump -S, with the extra benefit of confining to just the one function (or address-range) of interest.
You don't have to use gdb. GCC will do it.
gcc -S foo.c
This will create foo.s which is the assembly.
gcc -m32 -c -g -Wa,-a,-ad foo.c > foo.lst
The above version will create a listing file that has both the C and the assembly generated by it. GCC FAQ
full example for disassembling a memory range to C
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb
(gdb)file /root/ncs/zephyr/samples/hello_world/build_nrf9160dk_nrf9160ns/zephyr/zephyr.elf
(gdb) directory /root/ncs/zephyr/samples/hello_world/src
#here you want 1
(gdb) info line* 0x000328C0
#here you want 2, -0x04 ~ +0x04 is your range size
(gdb) disassemble /m 0x000328C0-0x04, 0x000328C0+0x04
#here with binary code
(gdb) disassemble /r 0x000328C0-0x04, 0x000328C0+0x04
(gdb) info thread
(gdb) interpreter-exec mi -thread-info
The accepted is not really correct. It does work in some circumstances.
(gdb) disas STARTADDRESS ENDADDRESS
The highest upvoted answer is correct. Read no further is you don't wish to understand why it is correct.
(gdb) x/i 0xdeadbeef
With an appropriately meaningless hex address.
I have an STM32 and I have relocated the code with PIC. The normal boot address is 0x8000000, with a 0x200 vector table. So a normal entry is 0x8000200. However, I have programmed the binary to 0x80040200 (two NOR flash sectors away) and wish to debug there.
The issue gdb has with this is 'file foo.elf' is showing that code is in the first range. Special command like 'disassemble' will actually look at the binary on the host. For the cross debug case, gdb would have to look at memory on the remote which could be expensive. So, it appears that the 'x /i' (examine as code) is the best option. The debug information that gdb depends on (where routines start/end) is not present in a random binary chunk.
To combine the answers above for PIC code on an embedded cross system,
You need to create multiple elf files, one for each possible target location. Use the GDB's file command to select the one with proper symbol locations.
This will NOT work for Cross development
You can use generating gcc debug symbols. The steps are,
Build normal link address.
Extract symbols.
Use symbol-file with an offset for the runtime address.
(gdb) help symbol-file
Load symbol table from executable file FILE.
Usage: symbol-file [-readnow | -readnever] [-o OFF] FILE
OFF is an optional offset which is added to each section address.
You can then switch symbol files to a relocated run address to use the first answer.
If you have a case where the code is relocated, but data is absolute, you need to link twice and choose the relocated elf files (symbols only are relocated and code is the same). This is desirable with NOR flash that is XIP (execute-in-place) as the memory devices for .text and .rodata are different from .data and .bss. Ie, many lower-to-middle scale embedded devices. However, gcc does not support this code generation option (at least on ARM). You must use a 'static base' register (for example, r9 as u-boot does).
There is another way which I wanted to presetn using gdb on top of the suggestions above:
Launch your program with gdb, and set a break point on main break *main and run
The you can use info proc mappings.