mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-26 11:41:35 +01:00
get_elf_entry
trace2txt fully ported
This commit is contained in:
51
README.adoc
51
README.adoc
@@ -5288,9 +5288,9 @@ QEMU:
|
|||||||
sample output:
|
sample output:
|
||||||
|
|
||||||
....
|
....
|
||||||
instruction count all: 1833863
|
instructions 1833863
|
||||||
entry address: 0x1000000
|
entry_address 0x1000000
|
||||||
instruction count firmware: 20708
|
instructions_firmware 20708
|
||||||
....
|
....
|
||||||
|
|
||||||
gem5:
|
gem5:
|
||||||
@@ -5328,7 +5328,7 @@ It only appears once on every log I've seen so far, checked with `grep 0x1000000
|
|||||||
+
|
+
|
||||||
Then when we count the instructions that run before the kernel entry point, there is only about 100k instructions, which is insignificant compared to the kernel boot itself.
|
Then when we count the instructions that run before the kernel entry point, there is only about 100k instructions, which is insignificant compared to the kernel boot itself.
|
||||||
+
|
+
|
||||||
TODO `-a arm` and `-a aarch64` does not count firmware instructions properly because the entry point address of the ELF file does not show up on the trace at all.
|
TODO `-a arm` and `-a aarch64` does not count firmware instructions properly because the entry point address of the ELF file (`ffffff8008080000` for `aarch64`) does not show up on the trace at all. Tested on link:http://github.com/cirosantilli/linux-kernel-module-cheat/commit/f8c0502bb2680f2dbe7c1f3d7958f60265347005[f8c0502bb2680f2dbe7c1f3d7958f60265347005].
|
||||||
* We can also discount the instructions after `init` runs by using `readelf` to get the initial address of `init`. One easy way to do that now is to just run:
|
* We can also discount the instructions after `init` runs by using `readelf` to get the initial address of `init`. One easy way to do that now is to just run:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
@@ -9046,42 +9046,19 @@ So for example when you run:
|
|||||||
./run -a arm
|
./run -a arm
|
||||||
....
|
....
|
||||||
|
|
||||||
Stdout shows a line with the full command of type:
|
the very first stdout output of that script is the actual QEMU command that is being run.
|
||||||
|
|
||||||
....
|
The command is also saved to a file for convenience:
|
||||||
time \
|
|
||||||
/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build/host-qemu-custom.default/arm-softmmu/qemu-system-arm \
|
|
||||||
-device rtl8139,netdev=net0 \
|
|
||||||
-gdb 'tcp::45457' \
|
|
||||||
-kernel '/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build/linux-custom.default/arch/arm/boot/zImage' \
|
|
||||||
-m '256M' \
|
|
||||||
-monitor 'telnet::45454,server,nowait' \
|
|
||||||
-netdev 'user,hostfwd=tcp::45455-:45455,hostfwd=tcp::45456-:22,id=net0' \
|
|
||||||
-no-reboot \
|
|
||||||
-serial mon:stdio \
|
|
||||||
-smp '1' \
|
|
||||||
-trace 'enable=pr_manager_run,file=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/qemu/0/trace.bin' \
|
|
||||||
-virtfs 'local,path=/home/ciro/bak/git/linux-kernel-module-cheat/data/9p,mount_tag=host_scratch,security_model=mapped,id=host_scratch' \
|
|
||||||
-virtfs 'local,path=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build,mount_tag=host_out,security_model=mapped,id=host_out' \
|
|
||||||
-M virt,highmem=off \
|
|
||||||
-append 'root=/dev/vda console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y' \
|
|
||||||
-cpu cortex-a15 \
|
|
||||||
-device virtio-gpu-pci \
|
|
||||||
-nographic \
|
|
||||||
-drive 'file=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/images/rootfs.ext2.qcow2,format=qcow2,if=virtio,snapshot' \
|
|
||||||
|& tee >(ts -s %.s > /home/ciro/bak/git/linux-kernel-module-cheat/out/arm/qemu/0/termout.txt)
|
|
||||||
....
|
|
||||||
|
|
||||||
and this line is also saved to a file for convenience:
|
|
||||||
|
|
||||||
....
|
....
|
||||||
cat "$(./getvar -a arm run_cmd_file)"
|
cat "$(./getvar -a arm run_cmd_file)"
|
||||||
....
|
....
|
||||||
|
|
||||||
or for gem5:
|
which you can manually modify and execute during your experiments later:
|
||||||
|
|
||||||
....
|
....
|
||||||
cat "$(./getvar -a arm -g run_cmd_file)"
|
vim "$(./getvar -a arm run_cmd_file)"
|
||||||
|
./"$(./getvar -a arm run_cmd_file)"
|
||||||
....
|
....
|
||||||
|
|
||||||
Next, you will also want to give the relevant images to save them time. Zip the images with:
|
Next, you will also want to give the relevant images to save them time. Zip the images with:
|
||||||
@@ -9091,7 +9068,15 @@ Next, you will also want to give the relevant images to save them time. Zip the
|
|||||||
./zip-img
|
./zip-img
|
||||||
....
|
....
|
||||||
|
|
||||||
and then upload the `out/lkmc-*.zip` file somewhere, e.g. GitHub release assets as in https://github.com/cirosantilli/linux-kernel-module-cheat/releases/tag/test-replay-arm
|
Source: link:zip-img[]
|
||||||
|
|
||||||
|
This generates a zip file:
|
||||||
|
|
||||||
|
....
|
||||||
|
out/lkmc-*.zip
|
||||||
|
....
|
||||||
|
|
||||||
|
which you can then upload somewhere, e.g. GitHub release assets as in https://github.com/cirosantilli/linux-kernel-module-cheat/releases/tag/test-replay-arm
|
||||||
|
|
||||||
Finally, do a clone of the relevant repository out of tree and reproduce the bug there, to be 100% sure that it is an actual upstream bug, and to provide developers with the cleanest possible commands.
|
Finally, do a clone of the relevant repository out of tree and reproduce the bug there, to be 100% sure that it is an actual upstream bug, and to provide developers with the cleanest possible commands.
|
||||||
|
|
||||||
|
|||||||
14
common.py
14
common.py
@@ -133,6 +133,20 @@ around when you checkout between branches.
|
|||||||
parser.set_defaults(**defaults)
|
parser.set_defaults(**defaults)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
def get_elf_entry(elf_file_path):
|
||||||
|
global this
|
||||||
|
readelf_header = subprocess.check_output([
|
||||||
|
this.get_toolchain_tool('readelf'),
|
||||||
|
'-h',
|
||||||
|
elf_file_path
|
||||||
|
])
|
||||||
|
for line in readelf_header.decode().split('\n'):
|
||||||
|
split = line.split()
|
||||||
|
if line.startswith(' Entry point address:'):
|
||||||
|
addr = line.split()[-1]
|
||||||
|
break
|
||||||
|
return int(addr, 0)
|
||||||
|
|
||||||
def get_stats(stat_re=None, stats_file=None):
|
def get_stats(stat_re=None, stats_file=None):
|
||||||
global this
|
global this
|
||||||
if stat_re is None:
|
if stat_re is None:
|
||||||
|
|||||||
16
run
16
run
@@ -84,16 +84,20 @@ def main(args, extra_args=None):
|
|||||||
if kernel_cli_extra_after_dash:
|
if kernel_cli_extra_after_dash:
|
||||||
kernel_cli_extra += " -{}".format(kernel_cli_extra_after_dash)
|
kernel_cli_extra += " -{}".format(kernel_cli_extra_after_dash)
|
||||||
extra_env = {}
|
extra_env = {}
|
||||||
|
if args.trace is None:
|
||||||
# A dummy value that is already turned on by default and does not produce large output,
|
do_trace = False
|
||||||
# just to prevent QEMU from emitting a warning that '' is not valid.
|
# A dummy value that is already turned on by default and does not produce large output,
|
||||||
trace_type = 'pr_manager_run'
|
# just to prevent QEMU from emitting a warning that '' is not valid.
|
||||||
|
trace_type = 'pr_manager_run'
|
||||||
|
else:
|
||||||
|
do_trace = True
|
||||||
|
trace_type = args.trace
|
||||||
|
|
||||||
if args.gem5:
|
if args.gem5:
|
||||||
memory = '{}B'.format(args.memory)
|
memory = '{}B'.format(args.memory)
|
||||||
gem5_exe_args = shlex.split(args.gem5_exe_args)
|
gem5_exe_args = shlex.split(args.gem5_exe_args)
|
||||||
if args.trace is not None:
|
if do_trace:
|
||||||
gem5_exe_args.append('--debug-flags={}'.format(args.trace))
|
gem5_exe_args.append('--debug-flags={}'.format(trace_type))
|
||||||
extra_env['M5_PATH'] = common.gem5_system_dir
|
extra_env['M5_PATH'] = common.gem5_system_dir
|
||||||
cmd = (
|
cmd = (
|
||||||
debug_vm +
|
debug_vm +
|
||||||
|
|||||||
16
rungdb-user
16
rungdb-user
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import imp
|
import imp
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
|
|
||||||
import common
|
import common
|
||||||
rungdb = imp.load_source('rungdb', os.path.join(common.root_dir, 'rungdb'))
|
rungdb = imp.load_source('rungdb', os.path.join(common.root_dir, 'rungdb'))
|
||||||
@@ -25,19 +23,9 @@ parser.add_argument(
|
|||||||
nargs='?'
|
nargs='?'
|
||||||
)
|
)
|
||||||
args = common.setup(parser)
|
args = common.setup(parser)
|
||||||
readelf_header = subprocess.check_output([
|
addr = common.get_elf_entry(os.path.join(common.build_dir, args.executable))
|
||||||
common.get_toolchain_tool('readelf'),
|
|
||||||
'-h',
|
|
||||||
os.path.join(common.build_dir, args.executable),
|
|
||||||
])
|
|
||||||
for line in readelf_header.decode().split('\n'):
|
|
||||||
split = line.split()
|
|
||||||
if line.startswith(' Entry point address:'):
|
|
||||||
addr = line.split()[-1]
|
|
||||||
break
|
|
||||||
print(addr)
|
|
||||||
extra_args = {}
|
extra_args = {}
|
||||||
extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(args.executable, addr)
|
extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(args.executable, hex(addr))
|
||||||
# Or else lx-symbols throws for arm:
|
# Or else lx-symbols throws for arm:
|
||||||
# gdb.MemoryError: Cannot access memory at address 0xbf0040cc
|
# gdb.MemoryError: Cannot access memory at address 0xbf0040cc
|
||||||
# TODO understand better.
|
# TODO understand better.
|
||||||
|
|||||||
33
trace-boot
33
trace-boot
@@ -36,11 +36,28 @@ else:
|
|||||||
})
|
})
|
||||||
run.main(args, extra_args)
|
run.main(args, extra_args)
|
||||||
qemu_trace2txt.main()
|
qemu_trace2txt.main()
|
||||||
## Instruction count.
|
# Instruction count.
|
||||||
## We could put this on a separate script, but it just adds more arch boilerplate to a new script.
|
# We could put this on a separate script, but it just adds more arch boilerplate to a new script.
|
||||||
## So let's just leave it here for now since it did not add a significant processing time.
|
# So let's just leave it here for now since it did not add a significant processing time.
|
||||||
#echo "instructions $(wc -l "${common_trace_txt_file}" | cut -d' ' -f1)"
|
kernel_entry_addr = hex(common.get_elf_entry(common.vmlinux))
|
||||||
#entry_addr=$("${common_root_dir}/runtc" readelf -h "${common_build_dir}/linux-custom/vmlinux" | grep 'Entry point address' | sed -E 's/.*: *//')
|
nlines = 0
|
||||||
#echo "entry_address ${entry_addr}"
|
nlines_firmware = 0
|
||||||
#sed "/${entry_addr}/q" "${common_trace_txt_file}" >"${common_qemu_run_dir}/trace-boot.txt"
|
with open(common.qemu_trace_txt_file, 'r') as trace_file:
|
||||||
#echo "instructions_firmware $(wc -l "${common_qemu_run_dir}/trace-boot.txt" | cut -d' ' -f1)"
|
in_firmware = True
|
||||||
|
for line in trace_file:
|
||||||
|
line = line.rstrip()
|
||||||
|
nlines += 1
|
||||||
|
pc = line.split('=')[-1]
|
||||||
|
if pc == kernel_entry_addr:
|
||||||
|
in_firmware = False
|
||||||
|
if in_firmware:
|
||||||
|
nlines_firmware += 1
|
||||||
|
print('''\
|
||||||
|
instructions {}
|
||||||
|
entry_address {}
|
||||||
|
instructions_firmware {}\
|
||||||
|
'''.format(
|
||||||
|
nlines,
|
||||||
|
kernel_entry_addr,
|
||||||
|
nlines_firmware
|
||||||
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user