Suppose I wanted a program written in C++ read its own eh_frame, in order to get information required for stack unwinding and exception handling. How to find out where it begins?
Suppose I wanted a program written in C++ read its own eh_frame
The .eh_frame_hdr is linked into its own GNU_EH_FRAME program header, precisely so it's easy for runtime libraries to locate .eh_frame at runtime.
Here is a typical layout:
readelf -Wl /bin/date
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x3cd0
There are 11 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R 0x8
INTERP 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x002790 0x002790 R 0x1000
LOAD 0x003000 0x0000000000003000 0x0000000000003000 0x010139 0x010139 R E 0x1000
LOAD 0x014000 0x0000000000014000 0x0000000000014000 0x005ad8 0x005ad8 R 0x1000
LOAD 0x01a250 0x000000000001b250 0x000000000001b250 0x001090 0x001248 RW 0x1000
DYNAMIC 0x01adf8 0x000000000001bdf8 0x000000000001bdf8 0x0001e0 0x0001e0 RW 0x8
NOTE 0x0002c4 0x00000000000002c4 0x00000000000002c4 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x017fe0 0x0000000000017fe0 0x0000000000017fe0 0x00040c 0x00040c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x01a250 0x000000000001b250 0x000000000001b250 0x000db0 0x000db0 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .data.rel.ro .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.gnu.build-id .note.ABI-tag
08 .eh_frame_hdr
09
10 .init_array .fini_array .data.rel.ro .dynamic .got
So start with GNU_EH_FRAME segment, and follow the links.
You could use (like RefPerSys and GCC do) Ian Lance Taylor's libbacktrace for that purpose.
(but you'll better compile your C++ code with DWARF debug information, so g++ -Wall -g -O ...)
Related
Can someone explain me what _IO_stdin_used is in the following line:
114a: 48 8d 3d b3 0e 00 00 lea rdi,[rip+0xeb3] # 2004 <_IO_stdin_used+0x4>
Sorry for the noob question.
Expanding on https://stackoverflow.com/users/224132/peter-cordes 's comment (What is _IO_stdin_used ), some tools can help make sense of this. Starting with burt.c:
#include <stdio.h>
void main (void) {
puts("hello!");
}
built like so: LDFLAGS=-Wl,-Map=burt.map make burt
We will look at the map file in a moment, first inspect the executable:
$ objdump -xsd -M intel burt
...
0000000000002000 g O .rodata 0000000000000004 _IO_stdin_used
...
Contents of section .rodata:
2000 01000200 68656c6c 6f2100 ....hello!.
...
1148: 48 8d 05 b5 0e 00 00 lea rax,[rip+0xeb5] # 2004 <_IO_stdin_used+0x4>
114f: 48 89 c7 mov rdi,rax
1152: e8 d9 fe ff ff call 1030 <puts#plt>
...
Note, the string's location (2004h) does not have an entry in the symbol table (where the 2000h entry _IO_stdin_used occurs). So, objdump's disassembly comments mention it relative to another symbol it knows about.
But why does it know about _IO_stdin_used, or, why does is that symbol included and why does it have a name? burt.map shows it came from Scrt1.o:
...
.rodata 0x0000000000002000 0xb
*(.rodata .rodata.* .gnu.linkonce.r.*)
.rodata.cst4 0x0000000000002000 0x4 /usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../lib/Scrt1.o
.rodata 0x0000000000002004 0x7 /tmp/ccYG1XvK.o
...
On my computer, Scrt1.o belongs to glibc, and the symbol can be traced back here: https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/init.c;h=c2f978f3da565590bcab355fefa3d81cf211cb36;hb=63fb8f9aa9d19f85599afe4b849b567aefd70a36.
To show that this is displayed in the objdump disassembly because there is no name for the address, we can give our string a name to add it to the symbol table, so that objdump will show it instead. To do this let's modify burt.c like so:
#include <stdio.h>
const char greeting[] = "hello!";
void main (void) {
puts(greeting);
}
Build, then inspect:
...
0000000000002004 g O .rodata 0000000000000007 greeting
...
0000000000002000 g O .rodata 0000000000000004 _IO_stdin_used
...
Contents of section .rodata:
2000 01000200 68656c6c 6f2100 ....hello!.
...
113d: 48 8d 05 c0 0e 00 00 lea rax,[rip+0xec0] # 2004 <greeting>
1144: 48 89 c7 mov rdi,rax
1147: e8 e4 fe ff ff call 1030 <puts#plt>
The offset relative to rip has changed a little bit, because the .text and .rodata sections are now a little bit further apart, although the .rodata contents remain the same, because the source modification was chosen to avoid modifying .rodata -- if greetings were not const, it would be located in .data instead. The map file below now shows burt.c's temporary object files's contribution to .rodata defining the greeting symbol, as compared to the previous map file where the same data had no name:
.rodata 0x0000000000002000 0xb
*(.rodata .rodata.* .gnu.linkonce.r.*)
.rodata.cst4 0x0000000000002000 0x4 /usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../..
/lib/Scrt1.o
0x0000000000002000 _IO_stdin_used
.rodata 0x0000000000002004 0x7 /tmp/ccDnWXjG.o
0x0000000000002004 greeting
Even though I have scrolled through another similar post regarding this topic, I have not yet managed to solve my issue.
I'm working on a bare metal development approach for stm32f411RE and I just got through the need of using embedded standard libraries (newlib nano) so then I proceeded to linking it to my project as well as as calling __libc_init_array() before main() in my Reset_Handler for the propper initialization of the standard library functions and here is where the problem arises.
Roughly speaking(pseudocode you might think) my startup file is as follows:
//Function prototypes
//main and Reset_Handler need to be inside extern
//in order to be recognized at the vector table
extern "C"{
int main(void);
void Reset_Handler(void);
void __libc_init_array(void);
}
vector_table={
(first address)STACK_POINTER,
(second address)Reset_Handler,
...
ISR routines
}
void Reset_Handler(void){
//call to __libc_init_array in order to initialize standard libraries functions
__libc_init_array();
//starting point of the program
main();
}
I get through the compilation and linking process successfully (no warnings, errors or anything) but the program fails to get to the main() function when I try to run it, in other words, it gets stuck at __libc_init_array();
When I run a debug session and look at the call stack this is what I get:
??#0xfffffce0 (Unknown Source:0)
<signal handler called>#0xfffffff9 (Unknown Source:0)
??#0x00000024 (Unknown Source:0)
And the program has not even reached main(). I guess it is obvious to say that setting a breakpoint is useless since the program does not even reaches main().
If I take __libc_init_array() out of the extern "C" I get the "__libc_init_array undefined reference" compilation error.
It is worth to say that my linker script as well as the startup and makefile were working like a charm on the bare metal approach, so the problem is not there, I mean, I just need to consider the appropriated flags for the linking process.
My project's structure is as following:
/My_project
-main.cpp
-file1.cpp
-file2.cpp
-startup_file.cpp
-linker_script.ld
-Makefile
-syscalls.c (requiered for newlib nano)
I'm building the object files with:
arm-none-eabi-g++ -c -mcpu=cortex-m4 -std=c++11 -o0 -fno-exceptions
with the exception of building syscall.c with:
arm-none-eabi-gcc -c -mcpu=cortex-m4 -std=c11 -o0 -fno-exceptions
then linking all the object files with:
-T stm32_ls.ld --specs=nano.specs -Wl, -Map=final.map
Here is the map after the linking:
Archive member included to satisfy reference by file (symbol)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-errno.o)
syscalls.o (__errno)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o (exit)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o) (_global_impure_ptr)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-init.o)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o (__libc_init_array)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-memset.o)
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o (memset)
Memory Configuration
Name Origin Length Attributes
FLASH 0x0000000008000000 0x0000000000080000 xr
SRAM 0x0000000020000000 0x0000000000020000 xrw
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
LOAD stm32_startup.o
LOAD main.o
LOAD CONFIG.o
LOAD GPIO.o
LOAD LCD_16x2.o
LOAD USER_FUNCTIONS.o
LOAD syscalls.o
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libstdc++_nano.a
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libm.a
START GROUP
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/libgcc.a
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a
END GROUP
START GROUP
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/libgcc.a
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a
END GROUP
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
LOAD /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
.text 0x0000000008000000 0x1008
*(.isr_vector)
.isr_vector 0x0000000008000000 0x198 stm32_startup.o
*(.text)
.text 0x0000000008000198 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
.text 0x0000000008000198 0x70 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.text 0x0000000008000208 0x138 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
0x0000000008000208 _stack_init
0x0000000008000290 _mainCRTStartup
0x0000000008000290 _start
.text 0x0000000008000340 0x90 stm32_startup.o
0x0000000008000340 Reset_Handler
0x00000000080003c8 Default_Handler
0x00000000080003c8 EXTI0_IRQHandler()
.text 0x00000000080003d0 0x124 main.o
0x00000000080003d0 enable_interrupt(IRQn_Struct)
0x0000000008000400 disable_interrupt(IRQn_Struct)
0x0000000008000434 EXTI15_10_IRQHandler()
0x0000000008000468 main
0x00000000080004a8 adc1_read()
0x00000000080004d8 adc1_start_convertion()
.text 0x00000000080004f4 0x24c CONFIG.o
0x00000000080004f4 system_clock_settings(char, boolean)
0x0000000008000630 EXTI_C13_config()
0x0000000008000684 ADC_PA1_Config()
0x00000000080006d8 HighSpeedConfig()
0x0000000008000704 TIM10_config_init()
.text 0x0000000008000740 0x56c GPIO.o
0x0000000008000740 GPIO_PORT::GPIO_PORT(char, int, int)
0x0000000008000740 GPIO_PORT::GPIO_PORT(char, int, int)
0x0000000008000778 GPIO_PORT::GPIO_PORT(char, int, int, int)
0x0000000008000778 GPIO_PORT::GPIO_PORT(char, int, int, int)
0x00000000080007b0 GPIO_PORT::set_pin_status(int)
0x0000000008000812 GPIO_PORT::read_pin_status()
0x0000000008000856 GPIO_PORT::toggle_pin_status()
0x0000000008000882 GPIO_PORT::pupd_selection(int)
0x0000000008000950 GPIO_PORT::pin_mode_input()
0x00000000080009aa GPIO_PORT::pin_mode_output()
0x0000000008000a04 GPIO_PORT::set_config()
0x0000000008000b3a GPIO_PORT::voltage_regulator_config()
0x0000000008000b5c GPIO_PORT::AHB1_clock_enable()
0x0000000008000bf4 GPIO_PORT::gpio_register_selector()
.text 0x0000000008000cac 0x0 LCD_16x2.o
.text 0x0000000008000cac 0x110 USER_FUNCTIONS.o
0x0000000008000cac delay_ms(int)
0x0000000008000d10 delay_us(int)
0x0000000008000d70 power(int, int)
.text 0x0000000008000dbc 0x202 syscalls.o
0x0000000008000dbc initialise_monitor_handles
0x0000000008000dc8 _getpid
0x0000000008000dd6 _kill
0x0000000008000df6 _exit
0x0000000008000e0a _read
0x0000000008000e44 _write
0x0000000008000e7c _close
0x0000000008000e92 _fstat
0x0000000008000eb0 _isatty
0x0000000008000ec4 _lseek
0x0000000008000edc _open
0x0000000008000ef6 _wait
0x0000000008000f14 _unlink
0x0000000008000f32 _times
0x0000000008000f48 _stat
0x0000000008000f66 _link
0x0000000008000f86 _fork
0x0000000008000f9c _execve
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-errno.o)
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o)
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-init.o)
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-memset.o)
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
.text 0x0000000008000fbe 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
*(.rodata)
*fill* 0x0000000008000fbe 0x2
.rodata 0x0000000008000fc0 0x24 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.rodata 0x0000000008000fe4 0x24 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
0x0000000008001008 . = ALIGN (0x4)
0x0000000008001008 _etext = .
.glue_7 0x0000000008001008 0x0
.glue_7 0x0000000008001008 0x0 linker stubs
.glue_7t 0x0000000008001008 0x0
.glue_7t 0x0000000008001008 0x0 linker stubs
.vfp11_veneer 0x0000000008001008 0x0
.vfp11_veneer 0x0000000008001008 0x0 linker stubs
.v4_bx 0x0000000008001008 0x0
.v4_bx 0x0000000008001008 0x0 linker stubs
.init 0x0000000008001008 0x18
.init 0x0000000008001008 0xc /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
0x0000000008001008 _init
.init 0x0000000008001014 0xc /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
.fini 0x0000000008001020 0x18
.fini 0x0000000008001020 0xc /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
0x0000000008001020 _fini
.fini 0x000000000800102c 0xc /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
.iplt 0x0000000008001038 0x0
.iplt 0x0000000008001038 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.text.__errno 0x0000000008001038 0x10
.text.__errno 0x0000000008001038 0x10 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-errno.o)
0x0000000008001038 __errno
.text.exit 0x0000000008001048 0x40
.text.exit 0x0000000008001048 0x40 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o)
0x0000000008001048 exit
.text.__libc_init_array
0x0000000008001088 0x80
.text.__libc_init_array
0x0000000008001088 0x80 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-init.o)
0x0000000008001088 __libc_init_array
.text.memset 0x0000000008001108 0x18
.text.memset 0x0000000008001108 0x18 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-memset.o)
0x0000000008001108 memset
.eh_frame 0x0000000008001120 0x4
.eh_frame 0x0000000008001120 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.eh_frame 0x0000000008001120 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
.ARM.extab 0x0000000008001124 0x0
.ARM.extab 0x0000000008001124 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
.ARM.exidx 0x0000000008001124 0x8
.ARM.exidx 0x0000000008001124 0x8 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
0x10 (size before relaxing)
.rodata._global_impure_ptr
0x000000000800112c 0x4
.rodata._global_impure_ptr
0x000000000800112c 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
0x000000000800112c _global_impure_ptr
.rel.dyn 0x0000000008001130 0x0
.rel.iplt 0x0000000008001130 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.data 0x0000000020000000 0x8 load address 0x0000000008001130
0x0000000020000000 _sdata = .
*(.data)
.data 0x0000000020000000 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
.data 0x0000000020000000 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
0x0000000020000000 __dso_handle
.data 0x0000000020000004 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
.data 0x0000000020000004 0x0 stm32_startup.o
.data 0x0000000020000004 0x0 main.o
.data 0x0000000020000004 0x0 CONFIG.o
.data 0x0000000020000004 0x0 GPIO.o
.data 0x0000000020000004 0x0 LCD_16x2.o
.data 0x0000000020000004 0x0 USER_FUNCTIONS.o
.data 0x0000000020000004 0x4 syscalls.o
0x0000000020000004 environ
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-errno.o)
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o)
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-init.o)
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-memset.o)
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
.data 0x0000000020000008 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
0x0000000020000008 . = ALIGN (0x4)
0x0000000020000008 _edata = .
.init_array 0x0000000020000008 0x4 load address 0x0000000008001138
.init_array 0x0000000020000008 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.fini_array 0x000000002000000c 0x4 load address 0x000000000800113c
.fini_array 0x000000002000000c 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.igot.plt 0x0000000020000010 0x0 load address 0x0000000008001140
.igot.plt 0x0000000020000010 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.data._impure_ptr
0x0000000020000010 0x4 load address 0x0000000008001140
.data._impure_ptr
0x0000000020000010 0x4 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
0x0000000020000010 _impure_ptr
.data.impure_data
0x0000000020000014 0x60 load address 0x0000000008001144
.data.impure_data
0x0000000020000014 0x60 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
.bss 0x0000000020000074 0x24 load address 0x00000000080011a4
0x0000000020000074 _sbss = .
0x0000000020000074 __bss_start__ = _sbss
*(.bss)
.bss 0x0000000020000074 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crti.o
.bss 0x0000000020000074 0x1c /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtbegin.o
.bss 0x0000000020000090 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o
.bss 0x0000000020000090 0x0 stm32_startup.o
.bss 0x0000000020000090 0x2 main.o
0x0000000020000090 sensor_value
.bss 0x0000000020000092 0x0 CONFIG.o
.bss 0x0000000020000092 0x0 GPIO.o
.bss 0x0000000020000092 0x0 LCD_16x2.o
.bss 0x0000000020000092 0x0 USER_FUNCTIONS.o
*fill* 0x0000000020000092 0x2
.bss 0x0000000020000094 0x4 syscalls.o
0x0000000020000094 __env
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-errno.o)
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-exit.o)
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-impure.o)
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-init.o)
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc_nano.a(lib_a-memset.o)
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtend.o
.bss 0x0000000020000098 0x0 /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/crtn.o
0x0000000020000098 _ebss = .
0x0000000020000098 __bss_end__ = _ebss
0x0000000020000098 . = ALIGN (0x4)
0x0000000020000098 end = .
OUTPUT(final.elf elf32-littlearm)
LOAD linker stubs
I'm guessing, out of my ignorace, that name mangling is not the problem since __libc_init_array() is defined inside extern "C". Also, in the map file, I see only one symbol with the name __libc_init_array and it seems to be at the correct flash address.
Comments are valuable. Thanks for reading such a long post.
PD: linker script for whoever wants to read it:
ENTRY(Reset_Handler)
MEMORY
{
FLASH(rx):ORIGIN =0x08000000,LENGTH =512K
SRAM(rwx):ORIGIN =0x20000000,LENGTH =128K
}
SECTIONS
{
.text :
{
*(.isr_vector)
*(.text)
*(.rodata)
. = ALIGN(4);
_etext = .; /*end of section .text address*/
}>FLASH
.data :
{
_sdata = .;
*(.data)
. = ALIGN(4);
_edata = .;
}>SRAM AT> FLASH
.bss :
{
_sbss = .;
__bss_start__ = _sbss;
*(.bss)
_ebss = .;
__bss_end__ = _ebss;
. = ALIGN(4);
end = .;
}>SRAM
}
startup file:
#include <stdint.h>
/**aliased and external defined functions get their names mangled
*so one needs to avoid name mangling by treating those functions
*as if they were compiled in C.Thats done by extern **/
extern "C"{
int main(void);
void Reset_Handler(void);
void Default_Handler(void);
void __libc_init_array(void);
}
#define SRAM_START 0x20000000
#define SRAM_SIZE (128U*1024U) //128*1Kb
#define SRAM_END ((SRAM_START) + (SRAM_SIZE))
#define STACK_START SRAM_END
extern uint32_t _etext;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
//function prototyping
//function prototyping
__attribute__((weak, alias("Default_Handler")))void EXTI0_IRQHandler(void);
__attribute__((weak, alias("Default_Handler")))void EXTI15_10_IRQHandler(void);
uint32_t(* const vectors[]) __attribute__((section(".isr_vector"))) ={
(uint32_t*)STACK_START, /* 0x000 Stack Pointer */
(uint32_t*)Reset_Handler, /* 0x004 Reset */
};
void Reset_Handler(void)
{
//copy .data section to SRAM
uint32_t size = (uint32_t)&_edata - (uint32_t)&_sdata;
uint8_t *pDst = (uint8_t*)&_sdata; //sram
uint8_t *pSrc = (uint8_t*)&_etext; //source point comes from flash memory that is end of flash
for(uint32_t i =0 ; i < size ; i++)
{
*pDst++ = *pSrc++;
}
//copy .bss section to SRAM
size = (uint32_t)&_ebss - (uint32_t)&_sbss;
pDst = (uint8_t*)&_sbss; //sram
for(uint32_t i =0 ; i < size ; i++)
{
*pDst++ = 0;
}
__libc_init_array();
main();
}
void Default_Handler(void)
{
while(1);
}
First of all, __libc_init_array() belongs inside extern "C". The map file you have above has it correct: it gets pulled in from libc_nano.a(lib_a-init.o).
This is not really the problem though. In your vector table, you have Reset_Handler where you should have the initial value of the stack pointer, and main where you should have the reset handler. main should never be in the vector, it is called by the reset handler as a normal function, not through the vector.
The crash you are having is most likely because you don't have a correct stack pointer, and the code is trying to use the stack.
Also, the first thing you do in your reset handler is call __libc_init_array. This is wrong. You need to (at least) copy the initialized data and zero the bss section first. If you are following the CMSIS pattern then you also need to call SystemInit. See the sample startup code and linker scripts in the STM32CubeF4 package.
EDIT: The above problems are in your pseudocode; the code doesn't match the pseudocode and doesn't have the above problems.
The next problem is that you have deleted half of the standard linker script. Try looking at the source of __libc_init_array to see what it needs. It needs the init array sections etc.
Here is an example with them in:
.init :
{
KEEP (*(SORT_NONE(.init)))
}
>FLASH
.text :
{
*(.text .text.* .stub .gnu.linkonce.t.*)
}
>FLASH
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
>FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
>FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
>FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
>FLASH
.ctors :
{
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
>FLASH
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
>FLASH
I am trying to link my C++ executable against a shared C library (also written by me / my colleagues).
The C++ executable just contains a main that prints "Hello World" to stdout and returns 0.
It runs fine. But as soon as I dynamic link against my C library (I am not even calling into this lib) my C++ executable fails at startup:
/opt/av-server # strace ./program
execve("./program", ["./program"], [/* 10 vars */]) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV +++
Segmentation fault
I did some research and found out that as soon as I link against the C library my ELF header starts looking very strange. The entry point address is suspiciously low and the addresses of the first LOAD are all zero:
Corrupt Header
Elf file type is DYN (Shared object file)
Entry point 0x6d8
There are 6 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x000960 0x00000960 0x00000960 0x00010 0x00010 R 0x4
LOAD 0x000000 0x00000000 0x00000000 0x00974 0x00974 R E 0x10000
LOAD 0x000ee0 0x00010ee0 0x00010ee0 0x0015c 0x00164 RW 0x10000
DYNAMIC 0x000ef0 0x00010ef0 0x00010ef0 0x00110 0x00110 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x000ee0 0x00010ee0 0x00010ee0 0x00120 0x00120 R 0x1
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01 .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.extab .ARM.exidx .eh_frame
02 .init_array .fini_array .jcr .dynamic .got .data .bss
03 .dynamic
04
05 .init_array .fini_array .jcr .dynamic
I guess this explains why the program is segfaulting: It jumps to 0 :/ As comparison this is the header that is generated when I don't link against the lib:
Good Header
Elf file type is EXEC (Executable file)
Entry point 0x10588
There are 9 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x0007fc 0x000107fc 0x000107fc 0x00018 0x00018 R 0x4
PHDR 0x000034 0x00010034 0x00010034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x00010154 0x00010154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.3]
LOAD 0x000000 0x00010000 0x00010000 0x00818 0x00818 R E 0x10000
LOAD 0x000ef0 0x00020ef0 0x00020ef0 0x00148 0x001dc RW 0x10000
DYNAMIC 0x000f00 0x00020f00 0x00020f00 0x00100 0x00100 RW 0x4
NOTE 0x000168 0x00010168 0x00010168 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x000ef0 0x00020ef0 0x00020ef0 0x00110 0x00110 R 0x1
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01
02 .interp
03 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.extab .ARM.exidx .eh_frame
04 .init_array .fini_array .jcr .dynamic .got .data .bss
05 .dynamic
06 .note.ABI-tag
07
08 .init_array .fini_array .jcr .dynamic
I understand why it must segfault. But the real question is: What inside the C library could possibly be responsible for corrupting the ELF header in that way?
I want to know that to look for. My suspicion is that somewhere in the lib some compiler intrinsics are used that go wrong. Just a wild guess.
I cross compile for Linux bha-1CCAE370CE47 3.4.35 #1 Thu Mar 9 11:20:13 HKT 2017 armv5tejl GNU/Linux with a GCC6.3. The toolchain was build with crosstool-ng. Build system is macOS.
I have an application that have openssl statically linked elf binary and i'm about to hook some of it's openssl function to get pre-master key thus allow me to decrypt the connections using wireshark.
I'm aware and know how to LD_PRELOAD or LD_LIBRARY_PATH hooking shared library, but this is statically linked binary.
Fortunately, the static elf didn't strip their debug symbol, so all named function i'm to hooking to are identified.
How do I have todo to hook this statically linked elf ?
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x80ceae0
Start of program headers: 52 (bytes into file)
Start of section headers: 3285112 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 27
Program Headers:
Elf file type is EXEC (Executable file)
Entry point 0x80ceae0
There are 8 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x309507 0x309507 R E 0x1000
LOAD 0x309520 0x08352520 0x08352520 0x13168 0x29934 RW 0x1000
DYNAMIC 0x31c0fc 0x083650fc 0x083650fc 0x00100 0x00100 RW 0x4
NOTE 0x000148 0x08048148 0x08048148 0x00020 0x00020 R 0x4
GNU_EH_FRAME 0x2ccc30 0x08314c30 0x08314c30 0x0a06c 0x0a06c R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .gcc_except_table
03 .data .dynamic .ctors .dtors .jcr .got .bss
04 .dynamic
05 .note.ABI-tag
06 .eh_frame_hdr
07
Symbol Table:
...
8627: 081ddbb0 408 FUNC GLOBAL DEFAULT 12 SSL_free
8629: 081de360 190 FUNC GLOBAL DEFAULT 12 SSL_copy_session_id
8665: 081deba0 148 FUNC GLOBAL DEFAULT 12 SSL_get_shared_ciphers
8848: 081df2f0 17 FUNC GLOBAL DEFAULT 12 SSL_CTX_set_default_passw
8927: 081e03a0 42 FUNC GLOBAL DEFAULT 12 SSL_CTX_set_cert_store
8996: 081de2d0 94 FUNC GLOBAL DEFAULT 12 SSL_get_peer_certificate
9079: 081e0250 14 FUNC GLOBAL DEFAULT 12 SSL_get_verify_result
9130: 081e52e0 269 FUNC GLOBAL DEFAULT 12 SSL_CTX_use_RSAPrivateKey
9193: 081e0f70 20 FUNC GLOBAL DEFAULT 12 SSL_SESSION_get_ex_data
9266: 081e0230 17 FUNC GLOBAL DEFAULT 12 SSL_set_verify_result
9305: 081df350 17 FUNC GLOBAL DEFAULT 12 SSL_CTX_set_verify_depth
9394: 081de230 14 FUNC GLOBAL DEFAULT 12 SSL_CTX_get_verify_depth
9409: 081e1840 36 FUNC GLOBAL DEFAULT 12 SSL_CTX_remove_session
9590: 081e3390 63 FUNC GLOBAL DEFAULT 12 SSL_rstate_string
9655: 081df8c0 122 FUNC GLOBAL DEFAULT 12 SSL_set_ssl_method
9662: 081e0360 20 FUNC GLOBAL DEFAULT 12 SSL_CTX_get_ex_data
9691: 081de330 38 FUNC GLOBAL DEFAULT 12 SSL_get_peer_cert_chain
9696: 081e0d20 20 FUNC GLOBAL DEFAULT 12 SSL_CTX_set_client_CA_lis
9798: 081e0d50 68 FUNC GLOBAL DEFAULT 12 SSL_get_client_CA_list
9810: 081de6f0 138 FUNC GLOBAL DEFAULT 12 SSL_write
...
You'll have to use GDB with a breakpoint command (perhaps involving Python scripting), or Systemtap. There is no direct way to interpose functions which are not listed in the .dynsym section (which is of course missing due to static linking).
I'm debugging a boot loader (syslinux) with gdb and the gdb-stub of qemu. At some point the main file load a shared object ldlinux.elf.
I would like to add the symbols in gdb for that file. The command add-symbol-file seems like the way to go. However, as a relocatable file, I have to specify the memory address it has been loaded at. And here comes the problem.
Although I know the base address at which the LOAD segment has been loaded at, add-symbol-file works section-wise and want me to specify the address at which each section has been loaded.
Can I tell gdb to load all the symbols of all the sections provided that I specify the base address of the file in memory?
Does the behavior of gdb make sens? The section headers aren't used for running an ELF and are even optional. I can't see a use case where specifying the load address of the sections would be useful.
Example
Here are the program headers and section headers of the shared object.
Elf file type is DYN (Shared object file)
Entry point 0x4c60
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x00000000 0x00000000 0x1db10 0x20bfc RWE 0x1000
DYNAMIC 0x01d618 0x0001d618 0x0001d618 0x00098 0x00098 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
Section to Segment mapping:
Segment Sections...
00 .gnu.hash .dynsym .dynstr .rel.dyn .rel.plt .plt .text .rodata .ctors .dtors .data.rel.ro .dynamic .got .got.plt .data .bss
01 .dynamic
02
There are 29 section headers, starting at offset 0x78618:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .gnu.hash GNU_HASH 00000094 000094 0007e0 04 A 2 0 4
[ 2] .dynsym DYNSYM 00000874 000874 0015c0 10 A 3 1 4
[ 3] .dynstr STRTAB 00001e34 001e34 0010f4 00 A 0 0 1
[ 4] .rel.dyn REL 00002f28 002f28 000ce8 08 A 2 0 4
[ 5] .rel.plt REL 00003c10 003c10 000568 08 AI 2 6 4
[ 6] .plt PROGBITS 00004180 004180 000ae0 04 AX 0 0 16
[ 7] .text PROGBITS 00004c60 004c60 013816 00 AX 0 0 4
[ 8] .rodata PROGBITS 00018480 018480 00462f 00 A 0 0 32
[ 9] .ctors INIT_ARRAY 0001cab0 01cab0 000010 00 WA 0 0 4
[10] .dtors FINI_ARRAY 0001cac0 01cac0 000004 00 WA 0 0 4
[11] .data.rel.ro PROGBITS 0001cae0 01cae0 000b38 00 WA 0 0 32
[12] .dynamic DYNAMIC 0001d618 01d618 000098 08 WA 3 0 4
[13] .got PROGBITS 0001d6b0 01d6b0 0000d0 04 WA 0 0 4
[14] .got.plt PROGBITS 0001d780 01d780 0002c0 04 WA 0 0 4
[15] .data PROGBITS 0001da40 01da40 0000d0 00 WA 0 0 32
[16] .bss NOBITS 0001db20 01db10 0030dc 00 WA 0 0 32
[17] .comment PROGBITS 00000000 01db10 000026 01 MS 0 0 1
[18] .debug_aranges PROGBITS 00000000 01db38 0010c0 00 0 0 8
[19] .debug_info PROGBITS 00000000 01ebf8 021ada 00 0 0 1
[20] .debug_abbrev PROGBITS 00000000 0406d2 009647 00 0 0 1
[21] .debug_line PROGBITS 00000000 049d19 00bd3a 00 0 0 1
[22] .debug_frame PROGBITS 00000000 055a54 004574 00 0 0 4
[23] .debug_str PROGBITS 00000000 059fc8 00538c 01 MS 0 0 1
[24] .debug_loc PROGBITS 00000000 05f354 01312d 00 0 0 1
[25] .debug_ranges PROGBITS 00000000 072481 0005d0 00 0 0 1
[26] .shstrtab STRTAB 00000000 072a51 000101 00 0 0 1
[27] .symtab SYMTAB 00000000 072b54 003530 10 28 504 4
[28] .strtab STRTAB 00000000 076084 002593 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
If I try to load the file at the address 0x7fab000 then it will relocate the symbols so that the .text section starts at 0x7fab000.
(gdb) add-symbol-file bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000
add symbol table from file "bios/com32/elflink/ldlinux/ldlinux.elf" at
.text_addr = 0x7fab000
(y or n) y
Reading symbols from bios/com32/elflink/ldlinux/ldlinux.elf...done.
And then all the symbols are off by 0x4c60 bytes.
So, finally, I made my own command with python and the readelf tool. It's not very clean since it runs readelf in a subprocess and parse its output instead of parsing the ELF file directly, but it works (for 32 bits ELF only).
It uses the section headers to generate and run an add-symbol-file command with all the sections correctly relocated. The usage is pretty simple, you give it the elf file and the base address of the file. And since the remove-symbol-file wasn't working properly by just giving it the filename, I made a remove-symbol-file-all that generate and run the right remove-symbol-file -a address command.
(gdb) add-symbol-file-all bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000
add symbol table from file "bios/com32/elflink/ldlinux/ldlinux.elf" at
.text_addr = 0x7fafc50
.gnu.hash_addr = 0x7fab094
.dynsym_addr = 0x7fab874
.dynstr_addr = 0x7face34
.rel.dyn_addr = 0x7fadf28
.rel.plt_addr = 0x7faec08
.plt_addr = 0x7faf170
.rodata_addr = 0x7fc34e0
.ctors_addr = 0x7fc7af0
.dtors_addr = 0x7fc7b00
.data.rel.ro_addr = 0x7fc7b20
.dynamic_addr = 0x7fc8658
.got_addr = 0x7fc86f0
.got.plt_addr = 0x7fc87bc
.data_addr = 0x7fc8a80
.bss_addr = 0x7fc8b60
(gdb) remove-symbol-file-all bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000
Here is the code to be added in the .gdbinit file.
python
import subprocess
import re
def relocatesections(filename, addr):
p = subprocess.Popen(["readelf", "-S", filename], stdout = subprocess.PIPE)
sections = []
textaddr = '0'
for line in p.stdout.readlines():
line = line.decode("utf-8").strip()
if not line.startswith('[') or line.startswith('[Nr]'):
continue
line = re.sub(r' +', ' ', line)
line = re.sub(r'\[ *(\d+)\]', '\g<1>', line)
fieldsvalue = line.split(' ')
fieldsname = ['number', 'name', 'type', 'addr', 'offset', 'size', 'entsize', 'flags', 'link', 'info', 'addralign']
sec = dict(zip(fieldsname, fieldsvalue))
if sec['number'] == '0':
continue
sections.append(sec)
if sec['name'] == '.text':
textaddr = sec['addr']
return (textaddr, sections)
class AddSymbolFileAll(gdb.Command):
"""The right version for add-symbol-file"""
def __init__(self):
super(AddSymbolFileAll, self).__init__("add-symbol-file-all", gdb.COMMAND_USER)
self.dont_repeat()
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
filename = argv[0]
if len(argv) > 1:
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
else:
offset = 0
(textaddr, sections) = relocatesections(filename, offset)
cmd = "add-symbol-file %s 0x%08x" % (filename, int(textaddr, 16) + offset)
for s in sections:
addr = int(s['addr'], 16)
if s['name'] == '.text' or addr == 0:
continue
cmd += " -s %s 0x%08x" % (s['name'], addr + offset)
gdb.execute(cmd)
class RemoveSymbolFileAll(gdb.Command):
"""The right version for remove-symbol-file"""
def __init__(self):
super(RemoveSymbolFileAll, self).__init__("remove-symbol-file-all", gdb.COMMAND_USER)
self.dont_repeat()
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
filename = argv[0]
if len(argv) > 1:
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
else:
offset = 0
(textaddr, _) = relocatesections(filename, offset)
cmd = "remove-symbol-file -a 0x%08x" % (int(textaddr, 16) + offset)
gdb.execute(cmd)
AddSymbolFileAll()
RemoveSymbolFileAll()
end
Can I tell gdb to load all the symbols of all the sections provided that I specify the base address of the file in memory?
Yes, but you need to provide the address of .text section, i.e. 0x7fab000+0x00004c60 here. I agree: it's quite annoying to have to fish out address of .text, and I wanted to fix it many times, so that e.g.
(gdb) add-symbol-file foo.so #0x7abc0000
just works. Feel free to file a feature request in GDB bugzilla.
Does the behavior of gdb make sens?
I am guessing that this is rooted in how GDB was used to debug embedded ROMs, where each section can be at arbitrary memory address.