From e7f9d8f1d7525d446a9d1db2b9976169c65dcf6e Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 6 Aug 2020 21:11:19 -0700 Subject: [PATCH] [scripts] Add symbol table building script Create a script that builds a simple-to-read symbol table from the output of `nm`. Include running that script over the kernel in the build, and including that output in the initrd. Tags: callstack debugging --- assets/initrd.toml | 4 ++ scripts/build_symbol_table.py | 71 ++++++++++++++++++++++++++++++++ scripts/templates/build.ninja.j2 | 10 ++++- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100755 scripts/build_symbol_table.py diff --git a/assets/initrd.toml b/assets/initrd.toml index 499a5c1..2289e7b 100644 --- a/assets/initrd.toml +++ b/assets/initrd.toml @@ -12,6 +12,10 @@ dest = "screenfont.psf" source = "../assets/fonts/tamsyn8x16r.psf" +[[files]] +dest = "symbol_table.dat" +source = "symbol_table.dat" + [[files]] dest = "nulldrv1" source = "user/nulldrv" diff --git a/scripts/build_symbol_table.py b/scripts/build_symbol_table.py new file mode 100755 index 0000000..2095d34 --- /dev/null +++ b/scripts/build_symbol_table.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Generate the jsix style symbol table. The format in memory of this table +# is as follows: +# +# : 8 bytes +# : 16 * N bytes +# : variable +# +# Each index entry has the format +# : 8 bytes +# : 8 bytes +# +# Name offsets are from the start of the symbol table as a whole. (ie, +# where is located.) + +def parse_syms(infile): + """Take the output of the `nm` command, and parse it into a tuple + representing the symbols in the text segment of the binary. Returns + a list of (address, symbol_name).""" + + from cxxfilt import demangle + + syms = [] + for line in sys.stdin: + addr, t, mangled = line.split() + if t not in "tTvVwW": continue + + addr = int(addr, base=16) + name = demangle(mangled) + syms.append((addr, name)) + + return sorted(syms) + + +def write_table(syms, outfile): + """Write the given symbol table as generated by parse_syms() + to the outfile, index first, and then name character data.""" + + import struct + + outfile.write(struct.pack("@Q", len(syms))) + index_pos = outfile.tell() + + outfile.seek(struct.calcsize("@QQ") * len(syms), 1) + nul = b'\0' + + positions = {} + for s in syms: + addr, name = s + positions[addr] = outfile.tell() + + data = name.encode('utf-8') + outfile.write(name.encode('utf-8')) + outfile.write(nul) + + outfile.seek(index_pos) + for s in syms: + addr = s[0] + pos = positions[addr] + outfile.write(struct.pack("@QQ", addr, pos)) + + +if __name__ == "__main__": + import sys + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + outfile = open(sys.argv[1], "wb") + write_table(parse_syms(sys.stdin), outfile) diff --git a/scripts/templates/build.ninja.j2 b/scripts/templates/build.ninja.j2 index 8646e28..85456b7 100644 --- a/scripts/templates/build.ninja.j2 +++ b/scripts/templates/build.ninja.j2 @@ -122,6 +122,10 @@ rule makerd description = Making init ramdisk command = $builddir/native/makerd $in $out +rule makest + description = Making symbol table + command = nm $in | ${srcroot}/scripts/build_symbol_table.py $out + rule makeefi description = Converting $name command = objcopy $ @@ -186,9 +190,13 @@ build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi name = bootloader to FAT image +build ${builddir}/symbol_table.dat : makest ${builddir}/jsix.elf | $ + ${builddir}/native/makest + build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $ ${builddir}/native/makerd $ - ${builddir}/user/nulldrv + ${builddir}/user/nulldrv $ + ${builddir}/symbol_table.dat build $builddir/jsix.img : makefat | $ $builddir/fatroot/initrd.img $