Is it possible to read the symbol table of a vmlinux file? - linux-kernel

I'm trying to read the symbol table of linux kernel, vmlinux file, so far I tried readelf,
readelf -s vmlinux
But nothing got printed.
Listing all strings stored inside, with strings command, I could find symbol names like sys_close, so I guess there should be a solution that works.
UPDATE
I don't have the System.map, I think it's inside the vmlinux, otherwise how could you build the kernel module with exported names like sys_close ?

The kernel binary is a little bit different. Its symbols are located inside the System.map file, which sould be inside the same directory than the kernel (/boot).
Wikipedia will give you more information about System.map.

Try to do
objdump -t vmlinux
objdump -t vmlinux
Its same as readelf
Check your make file and look how vmlinux is prepared.
I am sure there are flags there.
Or post your makefile here

Related

Reading memory with GDB vmlinux /proc/kcore

I am trying to use gdb to read memory from vmlinux. The exact syntax is
sudo gdb vmlinux-4.18.0-rc1+ /proc/kcore
I use this file because vmlinux is a symlink to this file.
The result is the following
Reading symbols from vmlinux-4.18.0-rc1+...(no debugging symbols found)...done.
warning: core file may not match specified executable file.
[New process 1]
Core was generated by `root=/dev/mapper/rcs--power9--talos--vg-root ro console=hvc0 quiet'.
#0 0x0000000000000000 in ?? ()
(gdb) x/4xb 0xfffffff0
0xfffffff0: Cannot access memory at address 0xfffffff0
(gdb) print &sys_call_table
No symbol table is loaded. Use the "file" command.
(gdb)
The file vmlinux-4.18.0-rc1+ is in /boot. The file type is as follows:
root#rcs-power9-talos:/boot# file vmlinux-4.18.0-rc1+
vmlinux-4.18.0-rc1+: ELF 64-bit LSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, BuildID[sha1]=a1c9f3fe22ff5cbf419787657c878c8a07e559b2, stripped
I modified the config-4.18.0-rc1+ file such that every CONFIG_DEBUG option is set to yes. I then rebooted the system. My questions are:
Do I need to do anything else for the changes I made to /boot/config-4.18.0-rc1+ to take effect?
Based on the file type of vmlinux-4.18.0-rc1+, does it seem that this file should work for debugging?
I did not build the kernel myself. It is a custom build from Raptor Computer Systems.
The config-* file you've modified is just for reference - all these options have already been compiled into the kernel, so changing them will not have any effect.
However, you can get any symbol you want in two steps:
consult /proc/kallsyms (e.g. grep sys_call_table /proc/kallsyms). Get the address. Note, that this might appear as 0x00000000 - which can be fixed by setting /proc/sys/kernel/kptr_restrict to 0
Then use above address as direct argument. You will still run into minor issues (e.g. "print" won't know what datatype it is, but x/20x for example will work) , but these can be resolved with a bit of gdb scripting, or providing an external dwarf file.

Dynamically load code on embedded target

I have an application which runs on bare metal target and has the following structure
main.c
service.c/.h
It's compiled to ELF executable (system.elf) using standard gcc -c, ld sequence. I use linker to generate a map file showing adresses of all symbols.
Now, without re-flashing my system I need to add an extra functionality with a custom run-time loader. Remember, this is a bare-metal with no OS.
I'd like to
compile extra.c which uses APIs defined in service.h (and somehow link against existing service.o/system.elf)
copy the resulting executable to my SDRAM at runtime and jump to it
loaded code should be able to run and accesses the exported symbols from service.c as expected
I thought I'd be able to to reuse map file to link the extra.o against system.elf but this didn't work:
ld -o extraExe extra.o system.map
Does gcc or ld have some mode to make this late linking procedure? If not, how can I achieve dynamic code loading which I outlined above?
You can use the '-R filename' or '--just-symbols=filename' command options in ld. It reads symbol names and their addresses from filename, but does not relocate it or include it in the output. This allows your output file to refer symbolically to absolute locations of memory defined in your system.elf program.
(refer to ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html).
So here filename will be 'system.elf'. You can compile extra.c with GCC normally including services.h but without linking and generate 'extra.o' then call ld as below:
ld -R"system.elf" -o"extra.out" extra.o
The 'extra.out' shall have your symbols linked. You can use objdump to compare contents of both 'extra.out' and 'extra.o'.
Note that you can always pass the start address of your program to the ld (e.g. -defsym _TEXT_START_ADDR=0xAAAA0123) as well as start address of other memory sections like bss,data. (i.e. -Tbss, -Tdata)
Be careful to use a valid address that does not conflict with your 'system.elf' as ld will not generate error for that. You can define new areas for the loaded code+data+bss in your original linker script and re-compile the system.elf then point the start addresses to your defined areas while linking 'extra.o'.

no symbols in vmlinux

I need oprofile to display detailed information about what happens inside the kernel instead of labeling it as /no-vmlinux.
To be able to provide oprofile with kernel symbols, I used the script extract_vmlinux available in /usr/src/linux-headers-3.9.7/scripts to obtain vmlinux from the compressed version vmlinuz.
Then I called operf with the option --vmlinux path_to_vmlinux.
However, operf displays the following error message:
Unable to obtain vmlinux end address The specified vmlinux file
(/tmp/vmlinux) does not seem to be valid. Make sure you are using a
non-compressed image file (e.g. vmlinux not vmlinuz)
By following this error message in the code of operf, I figured out that it occurs most likely after calling objdump -t (option -t is to "Print the symbol table entries of the file." according to the manpage of objdump)
And when I run: "objdump -t vmlinux", I get the following output:
vmlinux: file format elf64-x86-64
SYMBOL TABLE:
no symbols
Could you please help me?

How to generate symbol table with arm gcc

I would like to create a symbol definition table to be used in a separate application during linking. ARM's armlink linker has the following flag but I'm using arm-eabi:
--symdefs=filename
The GNU objcopy utility has an option --extract-symbol that may do what you want. It generates an object file with only symbol data - no actual code or data.
It is specifically intended to generate a .sym file for use in the VxWorks RTOS which has a command shell and dynamic linker/loader that uses this information. It is also used by the VxWorks host shell and source-level debugger.
The binutils nm utility on the other hand generates output very similar to armlink's --symdefs which you might easily post-process into exactly the form you need.
-Wl,-Map -Wl,mapfile -Wl,--cref
added to the final gcc (link) command line should do the trick.
This the correct answer from arm gnu launchpad:
Do you intend to load the symdef file with the GNU toolchain or with armcc one? If the former I think using nm on the object file and then linking with -R <filename> would work. So you would do arm-none-eabi-nm -D ./prog > ./prog.defsym after linking prog and then arm-none-eabi-gcc -Wl,-R,./prog.defsym when you want to use this.

Determine load address and entry point of stripped Linux Kernel image

I have a crosscompiling toolchain for an embedded system (mipsel) on my x86 Linux. I know how to build a custom kernel (let's call the image "vmlinux") for it and how to strip that image via
objcopy -S -O binary vmlinux vmlinux.bin
For further processing I also need the load address and entry point of the image. Before stripping it is no problem to determine them via scripts/mksysmap or, more explicitly, via
nm -n vmlinux | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > System.map
Then I can determine the load address and entry point via
awk '/A _text/ { print "0x"$1; }' < _System.map
awk '/T kernel_entry/ { print "0x"$1; }' < System.map
Now the challenge is that sometimes I do not build the kernel by myself, but get a pre-built kernel after it has already been stripped of its symbols via objcopy. Can anybody tell me how to do this? I am not very proficient in kernel building and toolchain usage. Both nm and objdump do not like the stripped image, saying
vmlinux.bin: File format not recognized
From the objcopy manual page
objcopy can be used to generate a raw binary file by using an output target of binary (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the virtual address of the lowest section copied into the output file.
Here is an example that could be used on the PowerPC architecture:
original vmlinux
bash-3.2$ file vmlinux
vmlinux: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, not stripped
stripped vmlinux is considered a "data" file
bash-3.2$ file vmlinux.bin
vmlinux.bin: data
convert binary to ELF format for the PowerPC
bash-3.2$ powerpc-440fp-linux-objcopy -I binary vmlinux.bin -B powerpc -O elf32-powerpc vmlinux.bin.x
output of vmlinux is now considered an ELF file
bash-3.2$ file vmlinux.bin.x
vmlinux.bin.x: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), not stripped
You must pass the -I, -B and -O parameter. You can get this parameters from your objcopy documentation.
But since your binary is stripped already trying to decompile it might not be worthwhile since the section information is not available. All of the data in the file will be dumped into the .data secion.

Resources