mirror of
https://github.com/encounter/oot-gc.git
synced 2026-07-10 12:18:42 -07:00
* Remove dependence on devkitpro, download compilers on setup * Update objdump_wrapper.py, gitignore changes
123 lines
3.8 KiB
Python
Executable File
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)
|