mapfile_parser 2.12.2__tar.gz → 2.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/CHANGELOG.md +22 -1
  2. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/Cargo.lock +1 -1
  3. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/Cargo.toml +1 -1
  4. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/PKG-INFO +2 -2
  5. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/README.md +1 -1
  6. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/pyproject.toml +1 -1
  7. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/__init__.py +1 -1
  8. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/sym_info.py +36 -19
  9. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/mapfile.py +175 -43
  10. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/mapfile_parser.pyi +6 -0
  11. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/found_symbol_info.rs +33 -21
  12. mapfile_parser-2.13.0/src/rs/iterators/iter_mapfile_syms_by_name.rs +58 -0
  13. mapfile_parser-2.13.0/src/rs/iterators/iter_mapfile_syms_by_vram.rs +50 -0
  14. mapfile_parser-2.13.0/src/rs/iterators/iter_mapfile_syms_by_vrom.rs +50 -0
  15. mapfile_parser-2.13.0/src/rs/iterators/iter_segment_syms_by_name.rs +55 -0
  16. mapfile_parser-2.13.0/src/rs/iterators/mod.rs +12 -0
  17. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/lib.rs +3 -0
  18. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/mapfile.rs +19 -2
  19. mapfile_parser-2.13.0/src/rs/maybe_found_symbol_info.rs +66 -0
  20. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/parser.rs +1 -1
  21. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/section.rs +74 -45
  22. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/segment.rs +55 -2
  23. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/symbol.rs +28 -4
  24. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/symbol_decomp_state.rs +1 -1
  25. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/.gitattributes +0 -0
  26. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/.gitignore +0 -0
  27. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/LICENSE +0 -0
  28. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/__main__.py +0 -0
  29. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/__init__.py +0 -0
  30. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/bss_check.py +0 -0
  31. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/first_diff.py +0 -0
  32. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/jsonify.py +0 -0
  33. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/objdiff_report.py +0 -0
  34. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/pj64_syms.py +0 -0
  35. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/progress.py +0 -0
  36. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/symbol_sizes_csv.py +0 -0
  37. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/frontends/upload_frogress.py +0 -0
  38. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/internals/__init__.py +0 -0
  39. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/internals/objdiff_report.py +0 -0
  40. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/mapfile_rs.py +0 -0
  41. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/progress_stats.py +0 -0
  42. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/progress_stats_rs.py +0 -0
  43. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/mapfile_parser/utils.py +0 -0
  44. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/maps_comparison_info.rs +0 -0
  45. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/progress_stats.rs +0 -0
  46. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/report.rs +0 -0
  47. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/symbol_comparison_info.rs +0 -0
  48. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/src/rs/utils.rs +0 -0
  49. {mapfile_parser-2.12.2 → mapfile_parser-2.13.0}/uv.lock +0 -0
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.13.0] - 2026-06-28
11
+
12
+ ### Added
13
+
14
+ - `findPossibleSymbolsByVram`, `findPossibleSymbolsByVrom`, and
15
+ `findPossibleSymbolsByName` for `MapFile` and `findPossibleSymbolByVram`,
16
+ `findPossibleSymbolByVrom`, and `findPossibleSymbolsByName` for `Segment`.
17
+ - Allow iterating over the mapfile looking for multiple symbols that could
18
+ match either the vram, vrom or name given instead of stopping at the first
19
+ one that matches the criteria.
20
+ - `Symbol::isNonmatching`: If true, the current symbol is a `.NON_MATCHING`
21
+ marker symbol.
22
+ - `Section::containsVram`, `Section::containsVrom`, `Segment::containsVram`,
23
+ `Segment::containsVrom`.
24
+
25
+ ### Changed
26
+
27
+ - `sym_info` now iterates over every possible vram/vrom address for every
28
+ segment instead of only printing the first found one.
29
+
10
30
  ## [2.12.2] - 2026-05-30
11
31
 
12
32
  ### Fixed
@@ -708,8 +728,9 @@ Full changes: <https://github.com/Decompollaborate/mapfile_parser/compare/702a73
708
728
 
709
729
  - Initial release
710
730
 
711
- [unreleased]: https://github.com/Decompollaborate/mapfile_parser/compare/2.12.2...HEAD
731
+ [unreleased]: https://github.com/Decompollaborate/mapfile_parser/compare/2.13.0...HEAD
712
732
 
733
+ [2.13.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.21.2...2.13.0
713
734
  [2.12.2]: https://github.com/Decompollaborate/mapfile_parser/compare/2.21.1...2.12.2
714
735
  [2.12.1]: https://github.com/Decompollaborate/mapfile_parser/compare/2.21.0...2.12.1
715
736
  [2.12.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.11.0...2.12.0
@@ -171,7 +171,7 @@ checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
171
171
 
172
172
  [[package]]
173
173
  name = "mapfile_parser"
174
- version = "2.12.2"
174
+ version = "2.13.0"
175
175
  dependencies = [
176
176
  "lazy_static",
177
177
  "objdiff-core",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "mapfile_parser"
6
- version = "2.12.2"
6
+ version = "2.13.0"
7
7
  edition = "2021"
8
8
  rust-version = "1.74.0"
9
9
  authors = ["Anghelo Carvajal <angheloalf95@gmail.com>"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapfile_parser
3
- Version: 2.12.2
3
+ Version: 2.13.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -90,7 +90,7 @@ cargo add mapfile_parser
90
90
  Or add the following line manually to your `Cargo.toml` file:
91
91
 
92
92
  ```toml
93
- mapfile_parser = "2.12"
93
+ mapfile_parser = "2.13"
94
94
  ```
95
95
 
96
96
  ## Versioning and changelog
@@ -75,7 +75,7 @@ cargo add mapfile_parser
75
75
  Or add the following line manually to your `Cargo.toml` file:
76
76
 
77
77
  ```toml
78
- mapfile_parser = "2.12"
78
+ mapfile_parser = "2.13"
79
79
  ```
80
80
 
81
81
  ## Versioning and changelog
@@ -3,7 +3,7 @@
3
3
 
4
4
  [project]
5
5
  name = "mapfile_parser"
6
- version = "2.12.2"
6
+ version = "2.13.0"
7
7
  description = "Map file parser library focusing decompilation projects"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.8"
@@ -5,7 +5,7 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- __version_info__ = (2, 12, 2)
8
+ __version_info__ = (2, 13, 0)
9
9
  __version__ = ".".join(map(str, __version_info__)) # + "-dev0"
10
10
  __author__ = "Decompollaborate"
11
11
 
@@ -9,6 +9,7 @@ import argparse
9
9
  from collections.abc import Callable
10
10
  import decomp_settings
11
11
  from pathlib import Path
12
+ from typing import Generator
12
13
 
13
14
  from .. import mapfile
14
15
  from .. import utils
@@ -31,36 +32,52 @@ def doSymInfo(
31
32
  if plfResolver is not None:
32
33
  mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
33
34
 
34
- possibleFiles: list[mapfile.Section] = []
35
+ count = 0
36
+ for info in iterateSymbols(
37
+ mapFile,
38
+ symName,
39
+ as_vram,
40
+ as_vrom,
41
+ as_name,
42
+ ):
43
+ print(info.getAsStrPlusOffset(symName))
44
+ count += 1
45
+
46
+ if count == 0:
47
+ print(f"'{symName}' not found in map file '{mapPath}'")
48
+ return 1
49
+ return 0
50
+
35
51
 
52
+ def iterateSymbols(
53
+ mapFile: mapfile.MapFile,
54
+ symName: str,
55
+ as_vram: bool,
56
+ as_vrom: bool,
57
+ as_name: bool,
58
+ ) -> Generator[mapfile.MaybeFoundSymbolInfo]:
36
59
  if as_vram:
37
60
  address = int(symName, 0)
38
- info, possibleFiles = mapFile.findSymbolByVram(address)
61
+ for info in mapFile.findPossibleSymbolsByVram(address):
62
+ yield info
39
63
  elif as_vrom:
40
64
  address = int(symName, 0)
41
- info, possibleFiles = mapFile.findSymbolByVrom(address)
65
+ for info in mapFile.findPossibleSymbolsByVrom(address):
66
+ yield info
42
67
  elif as_name:
43
- info = mapFile.findSymbolByName(symName)
68
+ for info in mapFile.findPossibleSymbolsByName(symName):
69
+ yield info
44
70
 
45
71
  # Start the guessing game
46
72
  elif utils.convertibleToInt(symName, 0):
47
73
  address = int(symName, 0)
48
- info, possibleFiles = mapFile.findSymbolByVram(address)
49
- if info is None:
50
- info, possibleFiles2 = mapFile.findSymbolByVrom(address)
51
- possibleFiles.extend(possibleFiles2)
74
+ for info in mapFile.findPossibleSymbolsByVram(address):
75
+ yield info
76
+ for info in mapFile.findPossibleSymbolsByVrom(address):
77
+ yield info
52
78
  else:
53
- info = mapFile.findSymbolByName(symName)
54
-
55
- if info is not None:
56
- print(info.getAsStrPlusOffset(symName))
57
- return 0
58
- print(f"'{symName}' not found in map file '{mapPath}'")
59
- if len(possibleFiles) > 0:
60
- print("But it may be a local symbol of either of the following files:")
61
- for f in possibleFiles:
62
- print(f" {f.asStr()})")
63
- return 1
79
+ for info in mapFile.findPossibleSymbolsByName(symName):
80
+ yield info
64
81
 
65
82
 
66
83
  def processArguments(
@@ -40,10 +40,10 @@ class FoundSymbolInfo:
40
40
  symbol: Symbol
41
41
  offset: int = 0
42
42
 
43
- def getAsStr(self) -> str:
44
- return f"'{self.symbol.name}' (VRAM: {self.symbol.getVramStr()}, VROM: {self.symbol.getVromStr()}, SIZE: {self.symbol.getSizeStr()}, {self.section.filepath})"
43
+ def getAsStr(self, *, extra: str = "") -> str:
44
+ return f"'{self.symbol.name}' (VRAM: {self.symbol.getVramStr()}, VROM: {self.symbol.getVromStr()}, SIZE: {self.symbol.getSizeStr()}, {self.section.filepath}{extra})"
45
45
 
46
- def getAsStrPlusOffset(self, symName: str | None = None) -> str:
46
+ def getAsStrPlusOffset(self, symName: str | None = None, *, extra: str = "") -> str:
47
47
  if self.offset != 0:
48
48
  if symName is not None:
49
49
  message = symName
@@ -52,7 +52,29 @@ class FoundSymbolInfo:
52
52
  message += f" is at 0x{self.offset:X} bytes inside"
53
53
  else:
54
54
  message = "Symbol"
55
- return f"{message} {self.getAsStr()}"
55
+ return f"{message} {self.getAsStr(extra=extra)}"
56
+
57
+
58
+ @dataclasses.dataclass
59
+ class MaybeFoundSymbolInfo:
60
+ segment: Segment
61
+ section: Section
62
+ symbol: Symbol | None
63
+ offset: int
64
+
65
+ def getAsStrPlusOffset(self, symName: str) -> str:
66
+ if self.symbol is not None:
67
+ info = FoundSymbolInfo(
68
+ self.section,
69
+ self.symbol,
70
+ self.offset,
71
+ )
72
+ return info.getAsStrPlusOffset(symName, extra=f", SEG: {self.segment.name}")
73
+
74
+ extra = ""
75
+ if self.offset != 0:
76
+ extra = f" at offset 0x{self.offset:X}"
77
+ return f"{symName} may be part of section {self.section.filepath} (segment {self.segment.name}){extra}, but it isn't globally visible."
56
78
 
57
79
 
58
80
  @dataclasses.dataclass
@@ -107,6 +129,12 @@ class Symbol:
107
129
  Note the symbol with the actual `.NON_MATCHING` will have this member
108
130
  set to `false`.
109
131
  """
132
+ isNonmatching: bool = False
133
+ """
134
+ `true` if this symbol has a `.NON_MATCHING` suffix.
135
+
136
+ Note `.NON_MATCHING` marker symbols have size 0.
137
+ """
110
138
  inferredStatic: bool = False
111
139
 
112
140
  def getVramStr(self) -> str:
@@ -173,6 +201,7 @@ class Symbol:
173
201
  self.vrom,
174
202
  self.align,
175
203
  self.nonmatchingSymExists,
204
+ self.isNonmatching,
176
205
  self.inferredStatic,
177
206
  )
178
207
 
@@ -201,6 +230,14 @@ class Section:
201
230
  def isNoloadSection(self) -> bool:
202
231
  return self.sectionType in {".bss", ".sbss", "COMMON", ".scommon"}
203
232
 
233
+ def containsVram(self, address: int) -> bool:
234
+ return address >= self.vram and address < self.vram + self.size
235
+
236
+ def containsVrom(self, address: int) -> bool | None:
237
+ if self.vrom is None:
238
+ return None
239
+ return address >= self.vrom and address < self.vrom + self.size
240
+
204
241
  def serializeVram(self, humanReadable: bool = True) -> str | int | None:
205
242
  if humanReadable:
206
243
  return f"0x{self.vram:08X}"
@@ -281,60 +318,76 @@ class Section:
281
318
  return None
282
319
 
283
320
  def findSymbolByVram(self, address: int) -> tuple[Symbol, int] | None:
284
- prevSym: Symbol | None = None
321
+ nonMatchingSym: Symbol | None = None
285
322
 
286
323
  for sym in self._symbols:
287
324
  if sym.vram == address:
325
+ # Matching address
326
+ if sym.isNonmatching:
327
+ # Try to avoid non matching marker symbols
328
+ nonMatchingSym = sym
329
+ continue
288
330
  return sym, 0
289
331
 
290
- if prevSym is not None:
291
- if sym.vram > address:
292
- offset = address - prevSym.vram
293
- if offset < 0:
294
- return None
295
- return prevSym, offset
332
+ if sym.vram > address:
333
+ # We somehow go through the symbol without seeing it?
334
+ break
296
335
 
297
- prevSym = sym
336
+ if sym.size == 0:
337
+ # The only way for a symbol to have size zero is to be a
338
+ # nonmatching marker, usually at least.
339
+ if sym.isNonmatching:
340
+ # Try to avoid non matching marker symbols
341
+ nonMatchingSym = sym
342
+ continue
298
343
 
299
- if prevSym is not None:
300
- if prevSym.size is not None and prevSym.vram + prevSym.size > address:
301
- offset = address - prevSym.vram
302
- if offset < 0:
303
- return None
304
- return prevSym, offset
344
+ if sym.vram < address and address < sym.vram + sym.size:
345
+ if sym.isNonmatching:
346
+ # Try to avoid non matching marker symbols
347
+ nonMatchingSym = sym
348
+ continue
349
+ return sym, address - sym.vram
305
350
 
351
+ if nonMatchingSym is not None:
352
+ return nonMatchingSym, address - nonMatchingSym.vram
306
353
  return None
307
354
 
308
355
  def findSymbolByVrom(self, address: int) -> tuple[Symbol, int] | None:
309
- prevVrom = self.vrom if self.vrom is not None else 0
310
- prevSym: Symbol | None = None
356
+ nonMatchingSym: Symbol | None = None
311
357
 
312
358
  for sym in self._symbols:
359
+ if sym.vrom is None:
360
+ continue
361
+
313
362
  if sym.vrom == address:
363
+ # Matching address
364
+ if sym.isNonmatching:
365
+ # Try to avoid non matching marker symbols
366
+ nonMatchingSym = sym
367
+ continue
314
368
  return sym, 0
315
369
 
316
- if prevSym is not None:
317
- if sym.vrom is not None and sym.vrom > address:
318
- offset = address - prevVrom
319
- if offset < 0:
320
- return None
321
- return prevSym, offset
370
+ if sym.vrom > address:
371
+ # We somehow go through the symbol without seeing it?
372
+ break
322
373
 
323
- if sym.vrom is not None:
324
- prevVrom = sym.vrom
325
- prevSym = sym
374
+ if sym.size == 0:
375
+ # The only way for a symbol to have size zero is to be a
376
+ # nonmatching marker, usually at least.
377
+ if sym.isNonmatching:
378
+ # Try to avoid non matching marker symbols
379
+ nonMatchingSym = sym
380
+ continue
326
381
 
327
- if prevSym is not None:
328
- if (
329
- prevSym.vrom is not None
330
- and prevSym.size is not None
331
- and prevSym.vrom + prevSym.size > address
332
- ):
333
- offset = address - prevVrom
334
- if offset < 0:
335
- return None
336
- return prevSym, offset
382
+ if sym.vrom < address and address < sym.vrom + sym.size:
383
+ if sym.isNonmatching:
384
+ # Try to avoid non matching marker symbols
385
+ nonMatchingSym = sym
386
+ continue
387
+ return sym, address - sym.vrom
337
388
 
389
+ if nonMatchingSym is not None and nonMatchingSym.vrom is not None:
390
+ return nonMatchingSym, address - nonMatchingSym.vrom
338
391
  return None
339
392
 
340
393
  @staticmethod
@@ -444,6 +497,14 @@ class Segment:
444
497
  align: int | None = None
445
498
  _sectionsList: list[Section] = dataclasses.field(default_factory=list)
446
499
 
500
+ def containsVram(self, address: int) -> bool:
501
+ return address >= self.vram and address < self.vram + self.size
502
+
503
+ def containsVrom(self, address: int) -> bool | None:
504
+ if self.vrom is None:
505
+ return None
506
+ return address >= self.vrom and address < self.vrom + self.size
507
+
447
508
  def serializeVram(self, humanReadable: bool = True) -> str | int | None:
448
509
  if humanReadable:
449
510
  return f"0x{self.vram:08X}"
@@ -498,7 +559,8 @@ class Segment:
498
559
  return None
499
560
 
500
561
  def findSymbolByVram(
501
- self, address: int
562
+ self,
563
+ address: int,
502
564
  ) -> tuple[FoundSymbolInfo | None, list[Section]]:
503
565
  possibleFiles: list[Section] = []
504
566
  for section in self._sectionsList:
@@ -506,12 +568,13 @@ class Segment:
506
568
  if pair is not None:
507
569
  sym, offset = pair
508
570
  return FoundSymbolInfo(section, sym, offset), []
509
- if address >= section.vram and address < section.vram + section.size:
571
+ if section.containsVram(address):
510
572
  possibleFiles.append(section)
511
573
  return None, possibleFiles
512
574
 
513
575
  def findSymbolByVrom(
514
- self, address: int
576
+ self,
577
+ address: int,
515
578
  ) -> tuple[FoundSymbolInfo | None, list[Section]]:
516
579
  possibleFiles: list[Section] = []
517
580
  for section in self._sectionsList:
@@ -521,10 +584,51 @@ class Segment:
521
584
  if pair is not None:
522
585
  sym, offset = pair
523
586
  return FoundSymbolInfo(section, sym, offset), []
524
- if address >= section.vrom and address < section.vrom + section.size:
587
+ if section.containsVrom(address):
525
588
  possibleFiles.append(section)
526
589
  return None, possibleFiles
527
590
 
591
+ def findPossibleSymbolByVram(
592
+ self,
593
+ address: int,
594
+ ) -> MaybeFoundSymbolInfo | None:
595
+ for section in self._sectionsList:
596
+ if section.containsVram(address):
597
+ pair = section.findSymbolByVram(address)
598
+ if pair is not None:
599
+ sym, offset = pair
600
+ else:
601
+ sym = None
602
+ offset = address - section.vram
603
+ return MaybeFoundSymbolInfo(self, section, sym, offset)
604
+ return None
605
+
606
+ def findPossibleSymbolByVrom(
607
+ self,
608
+ address: int,
609
+ ) -> MaybeFoundSymbolInfo | None:
610
+ for section in self._sectionsList:
611
+ if section.vrom is not None and section.containsVrom(address):
612
+ pair = section.findSymbolByVrom(address)
613
+ if pair is not None:
614
+ sym, offset = pair
615
+ else:
616
+ sym = None
617
+ offset = address - section.vram
618
+ return MaybeFoundSymbolInfo(self, section, sym, offset)
619
+ return None
620
+
621
+ def findPossibleSymbolsByName(
622
+ self,
623
+ symName: str,
624
+ ) -> Generator[MaybeFoundSymbolInfo]:
625
+ # There may be multiple symbols with the same name in the same segment,
626
+ # so this function iterate over them and yields them all.
627
+ for section in self._sectionsList:
628
+ sym = section.findSymbolByName(symName)
629
+ if sym is not None:
630
+ yield MaybeFoundSymbolInfo(self, section, sym, 0)
631
+
528
632
  def mixFolders(self) -> Segment:
529
633
  newSegment = Segment(self.name, self.vram, self.size, self.vrom)
530
634
 
@@ -735,6 +839,7 @@ class MapFile:
735
839
  symbol.vrom,
736
840
  symbol.align,
737
841
  symbol.nonmatchingSymExists,
842
+ symbol.isNonmatching,
738
843
  symbol.inferredStatic,
739
844
  )
740
845
 
@@ -768,6 +873,7 @@ class MapFile:
768
873
  symbol.vrom,
769
874
  symbol.align,
770
875
  symbol.nonmatchingSymExists,
876
+ symbol.isNonmatching,
771
877
  symbol.inferredStatic,
772
878
  )
773
879
 
@@ -914,6 +1020,32 @@ class MapFile:
914
1020
  possibleFiles.extend(possibleFilesAux)
915
1021
  return None, possibleFiles
916
1022
 
1023
+ def findPossibleSymbolsByVram(
1024
+ self,
1025
+ address: int,
1026
+ ) -> Generator[MaybeFoundSymbolInfo]:
1027
+ for segment in self._segmentsList:
1028
+ info = segment.findPossibleSymbolByVram(address)
1029
+ if info is not None:
1030
+ yield info
1031
+
1032
+ def findPossibleSymbolsByVrom(
1033
+ self,
1034
+ address: int,
1035
+ ) -> Generator[MaybeFoundSymbolInfo]:
1036
+ for segment in self._segmentsList:
1037
+ info = segment.findPossibleSymbolByVrom(address)
1038
+ if info is not None:
1039
+ yield info
1040
+
1041
+ def findPossibleSymbolsByName(
1042
+ self,
1043
+ symName: str,
1044
+ ) -> Generator[MaybeFoundSymbolInfo]:
1045
+ for segment in self._segmentsList:
1046
+ for info in segment.findPossibleSymbolsByName(symName):
1047
+ yield info
1048
+
917
1049
  def findLowestDifferingSymbol(
918
1050
  self, otherMapFile: MapFile
919
1051
  ) -> tuple[Symbol, Section, Symbol | None] | None:
@@ -71,6 +71,7 @@ class Symbol:
71
71
  vrom: int | None
72
72
  align: int | None
73
73
  nonmatchingSymExists: bool
74
+ isNonmatching: bool
74
75
  inferredStatic: bool
75
76
 
76
77
  def __init__(
@@ -81,6 +82,7 @@ class Symbol:
81
82
  vrom: int | None = None,
82
83
  align: int | None = None,
83
84
  nonmatchingSymExists: bool = False,
85
+ isNonmatching: bool = False,
84
86
  inferredStatic: bool = False,
85
87
  ): ...
86
88
  def getVramStr(self) -> str: ...
@@ -123,6 +125,8 @@ class Section:
123
125
  ) -> None: ...
124
126
  @property
125
127
  def isNoloadSection(self) -> bool: ...
128
+ def containsVram(self, address: int) -> bool: ...
129
+ def containsVrom(self, address: int) -> bool | None: ...
126
130
  def serializeVram(self, humanReadable: bool = True) -> str | int | None: ...
127
131
  def serializeSize(self, humanReadable: bool = True) -> str | int | None: ...
128
132
  def serializeVrom(self, humanReadable: bool = True) -> str | int | None: ...
@@ -172,6 +176,8 @@ class Segment:
172
176
  vrom: int | None,
173
177
  align: int | None = None,
174
178
  ): ...
179
+ def containsVram(self, address: int) -> bool: ...
180
+ def containsVrom(self, address: int) -> bool | None: ...
175
181
  def serializeVram(self, humanReadable: bool = True) -> str | int | None: ...
176
182
  def serializeSize(self, humanReadable: bool = True) -> str | int | None: ...
177
183
  def serializeVrom(self, humanReadable: bool = True) -> str | int | None: ...
@@ -1,7 +1,7 @@
1
1
  /* SPDX-FileCopyrightText: © 2023-2025 Decompollaborate */
2
2
  /* SPDX-License-Identifier: MIT */
3
3
 
4
- use std::fmt::Write;
4
+ use std::borrow::Cow;
5
5
 
6
6
  use crate::{section, symbol};
7
7
 
@@ -32,31 +32,43 @@ impl<'a> FoundSymbolInfo<'a> {
32
32
  }
33
33
 
34
34
  pub fn get_as_str(&self) -> String {
35
- format!(
36
- "'{0}' (VRAM: {1}, VROM: {2}, SIZE: {3}, {4})",
37
- self.symbol.name,
38
- self.symbol.get_vram_str(),
39
- self.symbol.get_vrom_str(),
40
- self.symbol.get_size_str(),
41
- self.section.filepath.to_string_lossy()
42
- )
35
+ self.get_as_str_impl(Cow::from(""))
36
+ }
37
+
38
+ pub(crate) fn get_as_str_impl(&self, extra: Cow<'_, str>) -> String {
39
+ let name = &self.symbol.name;
40
+ let vram = self.symbol.get_vram_str();
41
+ let vrom = self.symbol.get_vrom_str();
42
+ let size = self.symbol.get_size_str();
43
+ let section_path = self.section.filepath.to_string_lossy();
44
+
45
+ format!("'{name}' (VRAM: {vram}, VROM: {vrom}, SIZE: {size}, {section_path}{extra})")
43
46
  }
44
47
 
45
48
  pub fn get_as_str_plus_offset(&self, sym_name: Option<String>) -> String {
46
- let mut message;
49
+ self.get_as_str_plus_offset_impl(sym_name.map(Cow::from), Cow::from(""))
50
+ }
47
51
 
48
- if self.offset != 0 {
49
- if let Some(name) = sym_name {
50
- message = name;
51
- } else {
52
- message = format!("0x{0:X}", self.symbol.vram as i64 + self.offset);
53
- }
54
- write!(message, " is at 0x{0:X} bytes inside", self.offset).unwrap();
52
+ pub(crate) fn get_as_str_plus_offset_impl(
53
+ &self,
54
+ sym_name: Option<Cow<'_, str>>,
55
+ extra: Cow<'_, str>,
56
+ ) -> String {
57
+ let message = if self.offset == 0 {
58
+ Cow::from("Symbol")
55
59
  } else {
56
- message = "Symbol".to_string();
57
- }
58
-
59
- format!("{0} {1}", message, self.get_as_str())
60
+ let mes = if let Some(name) = sym_name {
61
+ name
62
+ } else {
63
+ Cow::from(format!(
64
+ "0x{0:X}",
65
+ self.symbol.vram.wrapping_add_signed(self.offset)
66
+ ))
67
+ };
68
+ Cow::from(format!("{} is at 0x{:X} bytes inside", mes, self.offset))
69
+ };
70
+
71
+ format!("{0} {1}", message, self.get_as_str_impl(extra))
60
72
  }
61
73
  }
62
74