refactor: one more step towards arch-agnostic design
[lunaix-os.git] / lunaix-os / scripts / syms_export.py
1 import subprocess
2 import math
3 import re
4
5 sym_line = re.compile(r"^(?P<addr>[0-9a-f]+)\s[a-z]\s+F\s+\.[a-z._]+\s+[0-9a-f]+(?P<label>.+)$")
6
7 def main(kbin, sym_out, endianness='little', bits=32):
8     assert bits >= 32
9     assert (1 << int(math.log2(bits))) == bits
10
11     b_len = bits // 8
12     result = subprocess.run(["objdump", "--syms", kbin],stdout=subprocess.PIPE, stderr=subprocess.PIPE)
13     if result.returncode != 0:
14         print(result.stderr)
15         return
16     
17     def to_native(val: int):
18         return val.to_bytes(b_len, endianness, signed=False)
19     
20     output = result.stdout.split(b'\n')
21     functions = []
22     for l in output:
23         l = l.decode("ascii")
24         if not l:
25             continue
26         
27         mo = sym_line.match(l)
28         if not mo:
29             continue
30
31         mg = mo.groupdict()
32         addr = int(mg["addr"], 16)
33         label = mg["label"].strip() + '\0'
34
35         functions.append((addr, label))
36
37     functions = sorted(functions, key=lambda x: x[0])
38     
39     # struct {
40     #   ptr_t addr;
41     #   unsigned int label_off;
42     # }
43     sym_struct_sz = b_len * 2
44     meta_struct_sz = 4 * 2
45     label_off_base = sym_struct_sz * len(functions) + meta_struct_sz
46     alignment = bytearray([b'\0' for _ in range(b_len - 4)])
47
48     label_off = 0
49     bmask = b_len - 1   
50     text_region = bytearray()
51     null = bytearray(b'\0')
52     with open(sym_out, mode='wb') as f:
53         # struct {
54         #   unsigned int num_entry;
55         #   unsigned int label_off_base;
56         # }
57         f.write(to_native(len(functions)))
58         f.write(to_native(label_off_base))
59
60         for a, l in functions:
61             f.write(to_native(a))
62             f.write(to_native(label_off))
63             f.write(alignment)
64             
65             text_region += bytes(l, 'ascii')
66             aligned_len = (len(l) + bmask) & ~bmask
67             for i in range(aligned_len - len(l)):
68                 text_region.append(null[0])
69
70             label_off += aligned_len
71         
72         f.write(text_region)
73
74 import argparse
75 import sys
76 if __name__ == "__main__":
77     parser = argparse.ArgumentParser()
78     parser.add_argument('elf_exec')
79     parser.add_argument('-o', '--outfile', required=True)
80     parser.add_argument('--bits', default=32)
81     parser.add_argument('--order', default='little')
82
83     args = parser.parse_args()
84
85     main(args.elf_exec, args.outfile, endianness=args.order, bits=int(args.bits))
86