Reading memory with GDB vmlinux /proc/kcore - linux-kernel

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.

Related

How can I convert only one file or one function of an elf file to assembly?

I have an elf file of a very big code base (kernel). I want to convert it to assembly code. I have base address of a function and offset of the instruction. Using this information, I want to get the specific instruction. I have used "objdump -b binary -m i386 -D file.elf" to get assembly code from elf file, but it is generating 4GB of data. I have also referred to this Can I give objdump an address and have it disassemble the containing function? but it is also not working for me.
You can limit objdump output with --start-address and --stop-address options.
For process code only for the single function, values for these options can be taken from readelf -s output, which contains start address of the function in the section and the function's size, and from readelf -S output, which contains address of the section with the function:
--start-address=<section_start + function_start>
--stop-address=<section_start + function_start + function_size>
I want to convert it to assembly code.
gdb -q ./elf_file
(gdb) set height 0 # prevent pagination
(gdb) set logging on # output will be mirrored in gdb.txt
(gdb) disassemble 0xffff000008081890 0xffff000008081bf5
(gdb) quit
Enjoy!

How to set breakpoint using GDB for x86 assembly when no symbol information is present? [duplicate]

This question already has answers here:
Stopping at the first machine code instruction in GDB
(5 answers)
Closed 4 years ago.
How do I set a breakpoint using GDB for x86 assembly code, when there is no symbol information, i.e. it is not possible to write b *_start.
I'd like to stop execution immediately, but writing b *0 isn't very useful, because this would stop execution at address 0, but I need to break execution at address x relative to the starting point (which is unknown when no symbol information is present).
Use something like objdump -f to show you the numeric value of the entry point address. Or inside gdb, info files will show you the entry point.
Copy/paste that value into a gdb command: b *0x... to break at the entry point. You can then single-step from there.
See also the bottom of the x86 tag wiki for some asm-debugging tips, like layout reg.
Sample output from objdump -f:
/bin/ls: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000404870 <<---- copy this address
Instead of finding the entry-point address
b *0 will cause an error when gdb tries to set the breakpoint. This results in stopping before any instructions execute, at the entry point. Delete the bogus breakpoint (or it will keep erroring when you try to single-step or continue).
Stopping at the first machine code instruction in GDB

init_task symbol not found in /proc/kallsyms (kernel 4.5.4-1-ARCH)

I am trying to locate the address of task_struct of a thread. First of all, I need to get the address of task_struct of the init_task, then I iterate the whole list and finally get the task_struct of a specific thread. The task_struct of the init_task can be easily obtained from /proc/kallsyms by the command
grep "\<init_task\>" /proc/kallsyms.
This worked when I use older kernel version (3.12). But when I switched to newer version (4.5), this idea failed at the very beginning. Because the symbol init_task disappears from /proc/kallsyms. But when I checked the source code, I can see that the symbol init_task is exported (http://lxr.free-electrons.com/source/init/init_task.c?v=4.5#L18). Why it doesn't show up in the /proc/kallsyms? Or is there any other approach to get the address of init_task from user space programs?
Try compiling with CONFIG_KALLSYMS_ALL option set. Without it kallsyms seems to include only symbols from .text and init.text sections: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/link-vmlinux.sh#n152, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/kallsyms.c#n250

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

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

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