Skip to content

Commit

Permalink
sym_info: detect addresses on files with no symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
AngheloAlf committed Sep 25, 2024
1 parent 337b15d commit f791d0e
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 57 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `--vram`, `--vrom` and `--name` arguments to `sym_info` frontend.
- Allow to tell to `sym_info` exactly how to treat the argument instead of
trying to guess how to use it.
- `sym_info` can now detect that an address may belong to a file even when the
symbol itself may not exist on the mapfile.
- This can happen for local symbols, for example for rodata literals.

### Deprecated

Expand Down
21 changes: 16 additions & 5 deletions src/mapfile_parser/frontends/first_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ def doFirstDiff(mapPath: Path, expectedMapPath: Path, romPath: Path, expectedRom
or builtRom[i + 3] != expectedRom[i + 3]
):
if diffs == 0:
vromInfo = builtMapFile.findSymbolByVrom(i)
vromInfo, possibleFiles = builtMapFile.findSymbolByVrom(i)
extraMessage = ""
if vromInfo is not None:
extraMessage = f", {vromInfo.getAsStrPlusOffset()}"
elif len(possibleFiles) > 0:
extraMessage = f", in file {possibleFiles[0].asStr()}"
print(f"First difference at ROM addr 0x{i:X}{extraMessage}")
builtBytes = builtRom[i : i + 4]
expectedBytes = expectedRom[i : i + 4]
Expand All @@ -80,15 +82,13 @@ def doFirstDiff(mapPath: Path, expectedMapPath: Path, romPath: Path, expectedRom
len(map_search_diff) < diffCount
and builtRom[i+endian_diff] >> 2 != expectedRom[i+endian_diff] >> 2
):
vromInfo = builtMapFile.findSymbolByVrom(i)
vromInfo, possibleFiles = builtMapFile.findSymbolByVrom(i)
if vromInfo is not None:
vromMessage = vromInfo.getAsStr()
if vromMessage not in map_search_diff:
map_search_diff.add(vromMessage)

extraMessage = ""
if vromInfo is not None:
extraMessage = f", {vromInfo.getAsStrPlusOffset()}"
extraMessage = f", {vromInfo.getAsStrPlusOffset()}"
print(f"Instruction difference at ROM addr 0x{i:X}{extraMessage}")
builtBytes = builtRom[i : i + 4]
expectedBytes = expectedRom[i : i + 4]
Expand All @@ -98,6 +98,17 @@ def doFirstDiff(mapPath: Path, expectedMapPath: Path, romPath: Path, expectedRom
expectedConverted = bytesConverterCallback(expectedBytes, expectedMapFile)
if builtConverted is not None and expectedConverted is not None:
print(f"{builtConverted} vs {expectedConverted}")
elif len(possibleFiles) > 0:
extraMessage = f", in file {possibleFiles[0].asStr()}"
print(f"Instruction difference at ROM addr 0x{i:X}{extraMessage}")
builtBytes = builtRom[i : i + 4]
expectedBytes = expectedRom[i : i + 4]
print(f"Bytes: {utils.hexbytes(builtBytes, addColons=addColons)} vs {utils.hexbytes(expectedBytes, addColons=addColons)}")
if bytesConverterCallback is not None:
builtConverted = bytesConverterCallback(builtBytes, builtMapFile)
expectedConverted = bytesConverterCallback(expectedBytes, expectedMapFile)
if builtConverted is not None and expectedConverted is not None:
print(f"{builtConverted} vs {expectedConverted}")

if len(map_search_diff) >= diffCount and diffs > shift_cap:
break
Expand Down
25 changes: 16 additions & 9 deletions src/mapfile_parser/frontends/sym_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,36 @@ def doSymInfo(mapPath: Path, symName: str, *, as_vram: bool=False, as_vrom: bool
mapFile = mapfile.MapFile()
mapFile.readMapFile(mapPath)

possibleFiles: list[mapfile.File] = []

if as_vram:
address = int(symName, 0)
info = mapFile.findSymbolByVram(address)
info, possibleFiles = mapFile.findSymbolByVram(address)
elif as_vrom:
address = int(symName, 0)
info = mapFile.findSymbolByVrom(address)
info, possibleFiles = mapFile.findSymbolByVrom(address)
elif as_name:
info = mapFile.findSymbolByName(symName)

# Start the guessing game
elif utils.convertibleToInt(symName, 0):
address = int(symName, 0)
info = mapFile.findSymbolByVram(address)
info, possibleFiles = mapFile.findSymbolByVram(address)
if info is None:
info = mapFile.findSymbolByVrom(address)
info, possibleFiles2 = mapFile.findSymbolByVrom(address)
possibleFiles.extend(possibleFiles2)
else:
info = mapFile.findSymbolByName(symName)

if info is None:
print(f"'{symName}' not found in map file '{mapPath}'")
return 1
print(info.getAsStrPlusOffset(symName))
return 0
if info is not None:
print(info.getAsStrPlusOffset(symName))
return 0
print(f"'{symName}' not found in map file '{mapPath}'")
if len(possibleFiles) > 0:
print("But it may be a local symbol of either of the following files:")
for f in possibleFiles:
print(f" {f.asStr()})")
return 1


def processArguments(args: argparse.Namespace):
Expand Down
63 changes: 48 additions & 15 deletions src/mapfile_parser/mapfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def findSymbolByVram(self, address: int) -> tuple[Symbol, int]|None:

if prevSym is not None:
if sym.vram > address:
offset = address - sym.vram
offset = address - prevSym.vram
if offset < 0:
return None
return prevSym, offset
Expand Down Expand Up @@ -346,6 +346,9 @@ def toJson(self, humanReadable: bool=True) -> dict[str, Any]:
fileDict["symbols"] = symbolsList
return fileDict

def asStr(self) -> str:
return f"{self.filepath}({self.sectionType}) (VRAM: {self.serializeVram(True)}, VROM: {self.serializeVrom(True)}, SIZE: {self.serializeSize(humanReadable=True)})"


def copySymbolList(self) -> list[Symbol]:
"""Returns a copy (not a reference) of the internal symbol list"""
Expand Down Expand Up @@ -448,21 +451,29 @@ def findSymbolByVramOrVrom(self, address: int) -> FoundSymbolInfo|None:
return FoundSymbolInfo(file, sym, offset)
return None

def findSymbolByVram(self, address: int) -> FoundSymbolInfo|None:
def findSymbolByVram(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]:
possibleFiles: list[File] = []
for file in self._filesList:
pair = file.findSymbolByVram(address)
if pair is not None:
sym, offset = pair
return FoundSymbolInfo(file, sym, offset)
return None
return FoundSymbolInfo(file, sym, offset), []
if address >= file.vram and address < file.vram + file.size:
possibleFiles.append(file)
return None, possibleFiles

def findSymbolByVrom(self, address: int) -> FoundSymbolInfo|None:
def findSymbolByVrom(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]:
possibleFiles: list[File] = []
for file in self._filesList:
if file.vrom is None:
continue
pair = file.findSymbolByVrom(address)
if pair is not None:
sym, offset = pair
return FoundSymbolInfo(file, sym, offset)
return None
return FoundSymbolInfo(file, sym, offset), []
if address >= file.vrom and address < file.vrom + file.size:
possibleFiles.append(file)
return None, possibleFiles


def mixFolders(self) -> Segment:
Expand Down Expand Up @@ -701,19 +712,41 @@ def findSymbolByVramOrVrom(self, address: int) -> FoundSymbolInfo|None:
return info
return None

def findSymbolByVram(self, address: int) -> FoundSymbolInfo|None:
def findSymbolByVram(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]:
"""
Returns a symbol with the specified VRAM address (or with an addend) if
it exists on the mapfile.
If no symbol if found, then a list of possible files where this symbol
may belong to is returned. This may happen if the symbol is not
globally visible.
"""

possibleFiles: list[File] = []
for segment in self._segmentsList:
info = segment.findSymbolByVram(address)
info, possibleFilesAux = segment.findSymbolByVram(address)
if info is not None:
return info
return None
return info, []
possibleFiles.extend(possibleFilesAux)
return None, possibleFiles

def findSymbolByVrom(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]:
"""
Returns a symbol with the specified VRAM address (or with an addend) if
it exists on the mapfile.
def findSymbolByVrom(self, address: int) -> FoundSymbolInfo|None:
If no symbol if found, then a list of possible files where this symbol
may belong to is returned. This may happen if the symbol is not
globally visible.
"""

possibleFiles: list[File] = []
for segment in self._segmentsList:
info = segment.findSymbolByVrom(address)
info, possibleFilesAux = segment.findSymbolByVrom(address)
if info is not None:
return info
return None
return info, []
possibleFiles.extend(possibleFilesAux)
return None, possibleFiles

def findLowestDifferingSymbol(self, otherMapFile: MapFile) -> tuple[Symbol, File, Symbol|None]|None:
minVram = None
Expand Down
8 changes: 4 additions & 4 deletions src/mapfile_parser/mapfile_parser.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ class Segment:
def findSymbolByName(self, symName: str) -> FoundSymbolInfo|None: ...
#! @deprecated: Use either `findSymbolByVram` or `findSymbolByVrom` instead.
def findSymbolByVramOrVrom(self, address: int) -> FoundSymbolInfo|None: ...
def findSymbolByVram(self, address: int) -> tuple[Symbol, int]|None: ...
def findSymbolByVrom(self, address: int) -> tuple[Symbol, int]|None: ...
def findSymbolByVram(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]: ...
def findSymbolByVrom(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]: ...

def mixFolders(self) -> Segment: ...

Expand Down Expand Up @@ -231,8 +231,8 @@ class MapFile:
def findSymbolByName(self, symName: str) -> FoundSymbolInfo|None: ...
#! @deprecated: Use either `findSymbolByVram` or `findSymbolByVrom` instead.
def findSymbolByVramOrVrom(self, address: int) -> FoundSymbolInfo|None: ...
def findSymbolByVram(self, address: int) -> tuple[Symbol, int]|None: ...
def findSymbolByVrom(self, address: int) -> tuple[Symbol, int]|None: ...
def findSymbolByVram(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]: ...
def findSymbolByVrom(self, address: int) -> tuple[FoundSymbolInfo|None, list[File]]: ...

def findLowestDifferingSymbol(self, otherMapFile: MapFile) -> tuple[Symbol, File, Symbol|None]|None: ...

Expand Down
34 changes: 22 additions & 12 deletions src/rs/mapfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,24 +521,32 @@ impl MapFile {
None
}

pub fn find_symbol_by_vram(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
pub fn find_symbol_by_vram(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<&file::File>) {
let mut possible_files = Vec::new();

for segment in &self.segments_list {
if let Some(info) = segment.find_symbol_by_vram(address) {
return Some(info);
let (maybe_info, possible_files_aux) = segment.find_symbol_by_vram(address);
if let Some(info) = maybe_info {
return (Some(info), Vec::new());
}
possible_files.extend(possible_files_aux);
}

None
(None, possible_files)
}

pub fn find_symbol_by_vrom(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
pub fn find_symbol_by_vrom(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<&file::File>) {
let mut possible_files = Vec::new();

for segment in &self.segments_list {
if let Some(info) = segment.find_symbol_by_vrom(address) {
return Some(info);
let (maybe_info, possible_files_aux) = segment.find_symbol_by_vrom(address);
if let Some(info) = maybe_info {
return (Some(info), Vec::new());
}
possible_files.extend(possible_files_aux);
}

None
(None, possible_files)
}

pub fn find_lowest_differing_symbol(
Expand Down Expand Up @@ -899,12 +907,14 @@ pub(crate) mod python_bindings {
self.find_symbol_by_vram_or_vrom(address)
}

fn findSymbolByVram(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
self.find_symbol_by_vram(address)
fn findSymbolByVram(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<file::File>) {
let (info, possible_files) = self.find_symbol_by_vram(address);
(info, possible_files.into_iter().cloned().collect())
}

fn findSymbolByVrom(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
self.find_symbol_by_vrom(address)
fn findSymbolByVrom(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<file::File>) {
let (info, possible_files) = self.find_symbol_by_vrom(address);
(info, possible_files.into_iter().cloned().collect())
}

fn findLowestDifferingSymbol(
Expand Down
34 changes: 22 additions & 12 deletions src/rs/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,30 +105,38 @@ impl Segment {
None
}

pub fn find_symbol_by_vram(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
pub fn find_symbol_by_vram(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<&file::File>) {
let mut possible_files = Vec::new();
for file in &self.files_list {
if let Some((sym, offset)) = file.find_symbol_by_vram(address) {
return Some(found_symbol_info::FoundSymbolInfo::new(
return (Some(found_symbol_info::FoundSymbolInfo::new(
file.clone(),
sym.clone(),
offset,
));
)), Vec::new());
}
if address >= file.vram && address < file.vram + file.size {
possible_files.push(file);
}
}
None
(None, possible_files)
}

pub fn find_symbol_by_vrom(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
pub fn find_symbol_by_vrom(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<&file::File>) {
let mut possible_files = Vec::new();
for file in &self.files_list {
if let Some((sym, offset)) = file.find_symbol_by_vrom(address) {
return Some(found_symbol_info::FoundSymbolInfo::new(
return (Some(found_symbol_info::FoundSymbolInfo::new(
file.clone(),
sym.clone(),
offset,
));
)), Vec::new());
}
if address >= file.vram && address < file.vram + file.size {
possible_files.push(file);
}
}
None
(None, possible_files)
}

pub fn mix_folders(&self) -> Self {
Expand Down Expand Up @@ -419,12 +427,14 @@ pub(crate) mod python_bindings {
self.find_symbol_by_vram_or_vrom(address)
}

fn findSymbolByVram(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
self.find_symbol_by_vram(address)
fn findSymbolByVram(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<file::File>) {
let (info, possible_files) = self.find_symbol_by_vram(address);
(info, possible_files.into_iter().cloned().collect())
}

fn findSymbolByVrom(&self, address: u64) -> Option<found_symbol_info::FoundSymbolInfo> {
self.find_symbol_by_vrom(address)
fn findSymbolByVrom(&self, address: u64) -> (Option<found_symbol_info::FoundSymbolInfo>, Vec<file::File>) {
let (info, possible_files) = self.find_symbol_by_vrom(address);
(info, possible_files.into_iter().cloned().collect())
}

fn mixFolders(&self) -> Self {
Expand Down

0 comments on commit f791d0e

Please sign in to comment.