Files
oot-gc/tools/objdump_wrapper.py
T
Tharo d3eefae631 Remove dependence on devkitpro, download compilers on setup (#38)
* Remove dependence on devkitpro, download compilers on setup

* Update objdump_wrapper.py, gitignore changes
2024-02-23 21:29:22 -08:00

123 lines
3.8 KiB
Python
Executable File

#!/usr/bin/env python3
# Adds line numbers from SIM_original.elf to objdump output for diff.py
from __future__ import annotations
from pathlib import Path
import re
import subprocess
import sys
from typing import BinaryIO
MAP_FILE = "expected/build/SIM/SIM.map"
ORIGINAL_ELF_FILE = "SIM_original.elf"
OBJDUMP_EXECUTABLE = "tools/binutils/powerpc-eabi-objdump"
def find_start_address_from_map_file(object_name: str) -> int | None:
pattern = re.compile(r" \S+ \S+ (\S+) +\S+ .text \t" + re.escape(object_name))
with open(MAP_FILE, "r") as f:
for line in f:
match = pattern.match(line)
if match:
return int(match[1], 16)
return None
def find_elf_section(f: BinaryIO, section_name: str) -> tuple[int, int] | None:
f.seek(0)
elf_header = f.read(64)
e_shoff = int.from_bytes(elf_header[0x20:0x24], byteorder="big")
e_shentsize = int.from_bytes(elf_header[0x2E:0x30], byteorder="big")
e_shnum = int.from_bytes(elf_header[0x30:0x32], byteorder="big")
e_shstrndx = int.from_bytes(elf_header[0x32:0x34], byteorder="big")
# find string table
f.seek(e_shoff + e_shstrndx * e_shentsize)
entry = f.read(e_shentsize)
strtab_offset = int.from_bytes(entry[0x10:0x14], byteorder="big")
# find section
for i in range(e_shnum):
f.seek(e_shoff + i * e_shentsize)
entry = f.read(e_shentsize)
sh_name = int.from_bytes(entry[0x00:0x04], byteorder="big")
f.seek(strtab_offset + sh_name)
current_name = bytearray()
while c := f.read(1)[0]:
current_name.append(c)
if current_name.decode("utf-8") == section_name:
sh_offset = int.from_bytes(entry[0x10:0x14], byteorder="big")
sh_size = int.from_bytes(entry[0x14:0x18], byteorder="big")
return sh_offset, sh_size
return None
def read_line_numbers(elf_file: Path, start_address) -> list[tuple[int, int]]:
line_numbers = []
with open(elf_file, "rb") as f:
section = find_elf_section(f, ".line")
if section is None:
return []
offset, size = section
f.seek(offset)
while f.tell() < offset + size:
start = f.tell()
length = int.from_bytes(f.read(4), byteorder="big")
address = int.from_bytes(f.read(4), byteorder="big")
if address != start_address:
f.seek(start + length)
continue
while f.tell() < start + length:
line_info = f.read(10)
line = int.from_bytes(line_info[0:4], byteorder="big")
delta = int.from_bytes(line_info[6:10], byteorder="big")
line_numbers.append((delta, line))
return line_numbers
def main(objdump_args: list[str]):
object_file = Path(objdump_args[-1])
c_file = object_file.with_suffix(".c").name
line_numbers = []
if object_file.parts[0] == "expected":
start_address = find_start_address_from_map_file(object_file.name)
if start_address is not None:
line_numbers = read_line_numbers(Path(ORIGINAL_ELF_FILE), start_address)
else:
line_numbers = read_line_numbers(object_file, 0)
p = subprocess.Popen(
[OBJDUMP_EXECUTABLE] + objdump_args, stdout=subprocess.PIPE, encoding="utf-8"
)
assert p.stdout is not None
next_entry = 0
pattern = re.compile(r"^\s+([0-9a-f]+):")
for line in p.stdout:
match = pattern.match(line)
if match:
delta = int(match[1], 16)
if next_entry < len(line_numbers) and line_numbers[next_entry][0] == delta:
print(f"{c_file}:{line_numbers[next_entry][1]}")
next_entry += 1
print(line, end="")
p.wait()
sys.exit(p.returncode)
if __name__ == "__main__":
objdump_args = sys.argv[1:]
main(objdump_args)