mapfile-parser 2.9.4__tar.gz → 2.11.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 (42) hide show
  1. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/CHANGELOG.md +46 -0
  2. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/Cargo.lock +1 -1
  3. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/Cargo.toml +1 -1
  4. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/PKG-INFO +3 -7
  5. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/README.md +2 -2
  6. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/pyproject.toml +1 -1
  7. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/__init__.py +1 -1
  8. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/bss_check.py +40 -8
  9. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/first_diff.py +38 -7
  10. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/jsonify.py +26 -4
  11. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/objdiff_report.py +39 -4
  12. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/pj64_syms.py +25 -4
  13. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/progress.py +44 -11
  14. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/sym_info.py +28 -4
  15. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/symbol_sizes_csv.py +28 -4
  16. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/upload_frogress.py +31 -3
  17. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/mapfile.py +102 -21
  18. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/mapfile_parser.pyi +30 -3
  19. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/mapfile.rs +112 -9
  20. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/parser.rs +120 -20
  21. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/report.rs +25 -50
  22. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/section.rs +1 -1
  23. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/segment.rs +4 -4
  24. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/symbol.rs +36 -4
  25. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/symbol_decomp_state.rs +7 -1
  26. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/.gitattributes +0 -0
  27. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/.gitignore +0 -0
  28. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/LICENSE +0 -0
  29. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/__main__.py +0 -0
  30. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/frontends/__init__.py +0 -0
  31. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/internals/__init__.py +0 -0
  32. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/internals/objdiff_report.py +0 -0
  33. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/mapfile_rs.py +0 -0
  34. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/progress_stats.py +0 -0
  35. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/progress_stats_rs.py +0 -0
  36. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/mapfile_parser/utils.py +0 -0
  37. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/found_symbol_info.rs +0 -0
  38. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/lib.rs +0 -0
  39. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/maps_comparison_info.rs +0 -0
  40. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/progress_stats.rs +0 -0
  41. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/symbol_comparison_info.rs +0 -0
  42. {mapfile_parser-2.9.4 → mapfile_parser-2.11.0}/src/rs/utils.rs +0 -0
@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.11.0] - 2025-09-08
11
+
12
+ ### Added
13
+
14
+ - Progress reports using the objdiff's report format can now emit progress for
15
+ data symbols!
16
+ - Data progress reporting requires `.NON_MATCHING` markers for every data
17
+ symbol that is not considered matched yet (i.e. from an automatic disassembly).
18
+ - It is turned off by default in `objdiff_report`. To turn it on set
19
+ `report_data: True` on your `decomp.yaml` file.
20
+
21
+ ### Changed
22
+
23
+ - Mapfile parsing will now try to infer static symbols by analyzing mismatches
24
+ on section address and size vs the addresses and sizes of symbols within that
25
+ section.
26
+ - For every inferred static sym a corresponding symbol will be inserted into
27
+ the section. Its name will be prefixed with `$_static_symbol_`.
28
+ - It is possible to check if a symbol is an inferred static in the API by
29
+ checking `Symbol::inferred_static`.
30
+ - The `--emit-categories` flag of `objdiff_report` not sets
31
+ `check_asm_paths: False` and `report_data: True` by default.
32
+
33
+ ### Fixed
34
+
35
+ - Fix the vram address plf-resolved mapfiles when the sections of those plfs
36
+ were not relative to zero.
37
+
38
+ ## [2.10.0] - 2025-09-01
39
+
40
+ ### Added
41
+
42
+ - Support for partially linked objects (a.k.a. `plf`).
43
+ - This is done by calling a function with a user provided callback that
44
+ converts a given object path into the corresponding mapfile for that `plf`.
45
+ - Rust: `MapFile::resolve_partially_linked_files()`.
46
+ - Python: `MapFile::resolvePartiallyLinkedFiles()`.
47
+ - All the CLI utilities include basic support for `plf`s.
48
+ - Pass the flag `-x .extension` or `--plf-ext .extension` to specify the
49
+ extension of the partially linked objects files that should be replaced with
50
+ a `.map` extension.
51
+ - The frontends API allow to further customize this behavior by passing a
52
+ callback like the one used by `MapFile::resolvePartiallyLinkedFiles`.
53
+
10
54
  ## [2.9.4] - 2025-06-02
11
55
 
12
56
  ### Changed
@@ -620,6 +664,8 @@ Full changes: <https://github.com/Decompollaborate/mapfile_parser/compare/702a73
620
664
  - Initial release
621
665
 
622
666
  [unreleased]: https://github.com/Decompollaborate/mapfile_parser/compare/master...develop
667
+ [2.11.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.10.0...2.11.0
668
+ [2.10.0]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.4...2.10.0
623
669
  [2.9.4]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.3...2.9.4
624
670
  [2.9.3]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.2...2.9.3
625
671
  [2.9.2]: https://github.com/Decompollaborate/mapfile_parser/compare/2.9.1...2.9.2
@@ -171,7 +171,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
171
171
 
172
172
  [[package]]
173
173
  name = "mapfile_parser"
174
- version = "2.9.4"
174
+ version = "2.11.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.9.4"
6
+ version = "2.11.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.9.4
3
+ Version: 2.11.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -8,10 +8,6 @@ Requires-Dist: requests
8
8
  Requires-Dist: decomp-settings==0.0.9
9
9
  License-File: LICENSE
10
10
  Summary: Map file parser library focusing decompilation projects
11
- Keywords: mapfile,parser,decomp,decompilation
12
- Author: Anghelo Carvajal <angheloalf95@gmail.com>
13
- Author-email: Anghelo Carvajal <angheloalf95@gmail.com>
14
- License: MIT
15
11
  Requires-Python: >=3.9
16
12
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
13
  Project-URL: Homepage, https://github.com/Decompollaborate/mapfile_parser
@@ -55,7 +51,7 @@ If you use a `requirements.txt` file in your repository, then you can add
55
51
  this library with the following line:
56
52
 
57
53
  ```txt
58
- mapfile_parser>=2.9.4,<3.0.0
54
+ mapfile_parser>=2.11.0,<3.0.0
59
55
  ```
60
56
 
61
57
  #### Development version
@@ -94,7 +90,7 @@ cargo add mapfile_parser
94
90
  Or add the following line manually to your `Cargo.toml` file:
95
91
 
96
92
  ```toml
97
- mapfile_parser = "2.9.4"
93
+ mapfile_parser = "2.11.0"
98
94
  ```
99
95
 
100
96
  ## Versioning and changelog
@@ -36,7 +36,7 @@ If you use a `requirements.txt` file in your repository, then you can add
36
36
  this library with the following line:
37
37
 
38
38
  ```txt
39
- mapfile_parser>=2.9.4,<3.0.0
39
+ mapfile_parser>=2.11.0,<3.0.0
40
40
  ```
41
41
 
42
42
  #### Development version
@@ -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.9.4"
78
+ mapfile_parser = "2.11.0"
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.9.4"
6
+ version = "2.11.0"
7
7
  description = "Map file parser library focusing decompilation projects"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.9"
@@ -5,7 +5,7 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- __version_info__ = (2, 9, 4)
8
+ __version_info__ = (2, 11, 0)
9
9
  __version__ = ".".join(map(str, __version_info__)) # + "-dev0"
10
10
  __author__ = "Decompollaborate"
11
11
 
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
12
 
@@ -13,14 +14,23 @@ from .. import mapfile
13
14
  from .. import utils
14
15
 
15
16
 
16
- def getComparison(mapPath, expectedMapPath, *, reverseCheck: bool=True) -> mapfile.MapsComparisonInfo:
17
- buildMap = mapfile.MapFile()
18
- buildMap.readMapFile(mapPath)
17
+ def getComparison(
18
+ mapPath: Path,
19
+ expectedMapPath: Path,
20
+ *,
21
+ reverseCheck: bool=True,
22
+ plfResolver: Callable[[Path], Path|None]|None=None,
23
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
24
+ ) -> mapfile.MapsComparisonInfo:
25
+ buildMap = mapfile.MapFile.newFromMapFile(mapPath)
19
26
  buildMap = buildMap.filterBySectionType(".bss")
27
+ if plfResolver is not None:
28
+ buildMap = buildMap.resolvePartiallyLinkedFiles(plfResolver)
20
29
 
21
- expectedMap = mapfile.MapFile()
22
- expectedMap.readMapFile(expectedMapPath)
30
+ expectedMap = mapfile.MapFile.newFromMapFile(expectedMapPath)
23
31
  expectedMap = expectedMap.filterBySectionType(".bss")
32
+ if plfResolverExpected is not None:
33
+ expectedMap = expectedMap.resolvePartiallyLinkedFiles(plfResolverExpected)
24
34
 
25
35
  return buildMap.compareFilesAndSymbols(expectedMap, checkOtherOnSelf=reverseCheck)
26
36
 
@@ -126,7 +136,15 @@ def printFileComparison(comparisonInfo: mapfile.MapsComparisonInfo):
126
136
  utils.eprint("Some files appear to be missing symbols. Have they been renamed or declared as static? You may need to remake 'expected'")
127
137
 
128
138
 
129
- def doBssCheck(mapPath, expectedMapPath, *, printAll: bool=False, reverseCheck: bool=True) -> int:
139
+ def doBssCheck(
140
+ mapPath: Path,
141
+ expectedMapPath: Path,
142
+ *,
143
+ printAll: bool=False,
144
+ reverseCheck: bool=True,
145
+ plfResolver: Callable[[Path], Path|None]|None=None,
146
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
147
+ ) -> int:
130
148
  if not mapPath.exists():
131
149
  utils.eprint(f"{mapPath} must exist")
132
150
  return 1
@@ -134,7 +152,7 @@ def doBssCheck(mapPath, expectedMapPath, *, printAll: bool=False, reverseCheck:
134
152
  utils.eprint(f"{expectedMapPath} must exist")
135
153
  return 1
136
154
 
137
- comparisonInfo = getComparison(mapPath, expectedMapPath, reverseCheck=reverseCheck)
155
+ comparisonInfo = getComparison(mapPath, expectedMapPath, reverseCheck=reverseCheck, plfResolver=plfResolver, plfResolverExpected=plfResolverExpected)
138
156
  printSymbolComparison(comparisonInfo, printAll)
139
157
 
140
158
  if len(comparisonInfo.badFiles) + len(comparisonInfo.missingFiles) != 0:
@@ -165,8 +183,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
165
183
 
166
184
  printAll: bool = args.print_all
167
185
  reverseCheck: bool = not args.no_reverse_check
186
+ plfExt: list[str]|None = args.plf_ext
168
187
 
169
- exit(doBssCheck(mapPath, expectedMapPath, printAll=printAll, reverseCheck=reverseCheck))
188
+ plfResolver = None
189
+ if plfExt is not None:
190
+ def resolver(x: Path) -> Path|None:
191
+ if x.suffix in plfExt:
192
+ newPath = x.with_suffix(".map")
193
+ if newPath.exists():
194
+ return newPath
195
+ return None
196
+
197
+ plfResolver = resolver
198
+
199
+ exit(doBssCheck(mapPath, expectedMapPath, printAll=printAll, reverseCheck=reverseCheck, plfResolver=plfResolver))
170
200
 
171
201
 
172
202
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -193,4 +223,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
193
223
  parser.add_argument("-a", "--print-all", help="Print all bss, not just non-matching.", action="store_true")
194
224
  parser.add_argument("--no-reverse-check", help="Disable looking for symbols on the expected map that are missing on the built map file.", action="store_true")
195
225
 
226
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
227
+
196
228
  parser.set_defaults(func=processArguments)
@@ -6,15 +6,28 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
- from typing import Callable, Literal
12
+ from typing import Literal
12
13
 
13
14
  from .. import mapfile
14
15
  from .. import utils
15
16
 
16
17
 
17
- def doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount: int=5, mismatchSize: bool=False, addColons: bool=True, bytesConverterCallback:Callable[[bytes, mapfile.MapFile],str|None]|None=None, endian: Literal["big", "little"] ="big") -> int:
18
+ def doFirstDiff(
19
+ mapPath: Path,
20
+ expectedMapPath: Path,
21
+ romPath: Path,
22
+ expectedRomPath: Path,
23
+ diffCount: int=5,
24
+ mismatchSize: bool=False,
25
+ addColons: bool=True,
26
+ bytesConverterCallback: Callable[[bytes, mapfile.MapFile],str|None]|None=None,
27
+ endian: Literal["big", "little"] ="big",
28
+ plfResolver: Callable[[Path], Path|None]|None=None,
29
+ plfResolverExpected: Callable[[Path], Path|None]|None=None,
30
+ ) -> int:
18
31
  if not mapPath.exists():
19
32
  print(f"{mapPath} must exist")
20
33
  return 1
@@ -41,10 +54,13 @@ def doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount: i
41
54
  print("No differences!")
42
55
  return 0
43
56
 
44
- builtMapFile = mapfile.MapFile()
45
- builtMapFile.readMapFile(mapPath)
46
- expectedMapFile = mapfile.MapFile()
47
- expectedMapFile.readMapFile(expectedMapPath)
57
+ builtMapFile = mapfile.MapFile.newFromMapFile(mapPath)
58
+ if plfResolver is not None:
59
+ builtMapFile = builtMapFile.resolvePartiallyLinkedFiles(plfResolver)
60
+
61
+ expectedMapFile = mapfile.MapFile.newFromMapFile(expectedMapPath)
62
+ if plfResolverExpected is not None:
63
+ expectedMapFile = expectedMapFile.resolvePartiallyLinkedFiles(plfResolverExpected)
48
64
 
49
65
  endian_diff = 0
50
66
  if endian == "little":
@@ -166,7 +182,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
166
182
 
167
183
  endian = args.endian
168
184
 
169
- exit(doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount, mismatchSize, endian=endian))
185
+ plfExt: list[str]|None = args.plf_ext
186
+
187
+ plfResolver = None
188
+ if plfExt is not None:
189
+ def resolver(x: Path) -> Path|None:
190
+ if x.suffix in plfExt:
191
+ newPath = x.with_suffix(".map")
192
+ if newPath.exists():
193
+ return newPath
194
+ return None
195
+
196
+ plfResolver = resolver
197
+
198
+ exit(doFirstDiff(mapPath, expectedMapPath, romPath, expectedRomPath, diffCount, mismatchSize, endian=endian, plfResolver=plfResolver))
170
199
 
171
200
 
172
201
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -200,4 +229,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
200
229
  parser.add_argument("-m", "--mismatch-size", help="Do not exit early if the ROM sizes does not match", action="store_true")
201
230
  parser.add_argument("-e", "--endian", help="Specify endianness of the binary", choices=["big", "little"], default="big")
202
231
 
232
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
233
+
203
234
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  import json
11
12
  from pathlib import Path
@@ -13,13 +14,20 @@ from pathlib import Path
13
14
  from .. import mapfile
14
15
 
15
16
 
16
- def doJsonify(mapPath: Path, outputPath: Path|None, humanReadable: bool=True, applyFixes: bool=False) -> int:
17
+ def doJsonify(
18
+ mapPath: Path,
19
+ outputPath: Path|None,
20
+ humanReadable: bool=True,
21
+ applyFixes: bool=False,
22
+ plfResolver: Callable[[Path], Path|None]|None=None,
23
+ ) -> int:
17
24
  if not mapPath.exists():
18
25
  print(f"Could not find mapfile at '{mapPath}'")
19
26
  return 1
20
27
 
21
- mapFile = mapfile.MapFile()
22
- mapFile.readMapFile(mapPath)
28
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
29
+ if plfResolver is not None:
30
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
23
31
 
24
32
  jsonStr = json.dumps(mapFile.toJson(humanReadable=humanReadable), indent=4)
25
33
 
@@ -44,8 +52,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
44
52
  outputPath: Path|None = Path(args.output) if args.output is not None else None
45
53
  machine: bool = args.machine
46
54
  applyFixes: bool = args.apply_fixes
55
+ plfExt: list[str]|None = args.plf_ext
47
56
 
48
- exit(doJsonify(mapPath, outputPath, humanReadable=not machine, applyFixes=applyFixes))
57
+ plfResolver = None
58
+ if plfExt is not None:
59
+ def resolver(x: Path) -> Path|None:
60
+ if x.suffix in plfExt:
61
+ newPath = x.with_suffix(".map")
62
+ if newPath.exists():
63
+ return newPath
64
+ return None
65
+
66
+ plfResolver = resolver
67
+
68
+ exit(doJsonify(mapPath, outputPath, humanReadable=not machine, applyFixes=applyFixes, plfResolver=plfResolver))
49
69
 
50
70
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
51
71
  parser = subparser.add_parser("jsonify", help="Converts a mapfile into a json format.")
@@ -67,4 +87,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
67
87
  parser.add_argument("-m", "--machine", help="Emit numbers as numbers instead of outputting them as pretty strings.", action="store_true")
68
88
  parser.add_argument("-f", "--apply-fixes", help="DEPRECATED, this is applied automatically now. Apply certain fixups, like fixing size calculation of because of the existence of fake `.NON_MATCHING` symbols.", action="store_true")
69
89
 
90
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
91
+
70
92
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import dataclasses
10
11
  import decomp_settings
11
12
  from pathlib import Path
@@ -34,13 +35,15 @@ def doObjdiffReport(
34
35
  emitCategories: bool=False,
35
36
  quiet: bool=False,
36
37
  summaryTableConfig: SummaryTableConfig|None=SummaryTableConfig(),
38
+ plfResolver: Callable[[Path], Path|None]|None=None,
37
39
  ) -> int:
38
40
  if not mapPath.exists():
39
41
  print(f"Could not find mapfile at '{mapPath}'")
40
42
  return 1
41
43
 
42
- mapFile = mapfile.MapFile()
43
- mapFile.readMapFile(mapPath)
44
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
45
+ if plfResolver is not None:
46
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
44
47
 
45
48
  if emitCategories:
46
49
  printDefaultCategories(mapFile, prefixesToTrim)
@@ -244,7 +247,11 @@ tools:
244
247
  mapfile_parser:
245
248
  progress_report:
246
249
  # output: report.json # Optional
247
- check_asm_paths: True
250
+ # If you don't have .NON_MATCHING markers in all your function and data
251
+ # symbols then you should set `check_asm_paths: True` and
252
+ # `report_data: False`, otherwise those progress will get a fake boost.
253
+ check_asm_paths: False
254
+ report_data: True
248
255
  # Change if the asm path in the build folder is deeper than two subfolders.
249
256
  # i.e.: "build/us/asm/header.o" -> `path_index: 3`.
250
257
  # i.e.: "build/us/asm/us/header.o" -> `path_index: 4`.
@@ -274,6 +281,12 @@ tools:
274
281
  - {p}
275
282
  """, end="")
276
283
 
284
+ print(" # The following categories are autogenerated and they are intended as a")
285
+ print(" # guide and examples on how to setup your own categories. Please don't")
286
+ print(" # commit them as-is.")
287
+ print()
288
+ print(" # List of categories. `id`s must be unique, but each path may be")
289
+ print(" # duplicated across categories.")
277
290
  print(" categories:")
278
291
  print(" # Categories by path")
279
292
  printCategories(categoriesByPath)
@@ -310,6 +323,7 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
310
323
  pathIndex = int(args.path_index)
311
324
  else:
312
325
  pathIndex = pathIndexDefault
326
+ reportCategories.setReportData(settings.reportData)
313
327
  else:
314
328
  outputPath = args.output
315
329
  if args.prefixes_to_trim is not None:
@@ -317,6 +331,7 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
317
331
  else:
318
332
  prefixesToTrim = []
319
333
  pathIndex = int(args.path_index) if args.path_index is not None else pathIndexDefault
334
+ reportCategories.setReportData(False)
320
335
 
321
336
  if decompConfig is not None:
322
337
  version = decompConfig.get_version_by_name(args.version)
@@ -347,6 +362,18 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
347
362
  else:
348
363
  summaryTableConfig = None
349
364
 
365
+ plfExt: list[str]|None = args.plf_ext
366
+
367
+ plfResolver = None
368
+ if plfExt is not None:
369
+ def resolver(x: Path) -> Path|None:
370
+ if x.suffix in plfExt:
371
+ newPath = x.with_suffix(".map")
372
+ if newPath.exists():
373
+ return newPath
374
+ return None
375
+ plfResolver = resolver
376
+
350
377
  exit(doObjdiffReport(
351
378
  mapPath,
352
379
  outputPath,
@@ -357,6 +384,7 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
357
384
  nonmatchingsPath=nonmatchingsPath,
358
385
  emitCategories=emitCategories,
359
386
  summaryTableConfig=summaryTableConfig,
387
+ plfResolver=plfResolver,
360
388
  ))
361
389
 
362
390
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
@@ -386,7 +414,8 @@ tools:
386
414
  mapfile_parser:
387
415
  progress_report:
388
416
  # output: report.json # Optional
389
- check_asm_paths: True
417
+ check_asm_paths: False
418
+ report_data: True
390
419
  # path_index: 2
391
420
  # List of build prefixes to trim from each object file
392
421
  prefixes_to_trim:
@@ -468,6 +497,8 @@ tools:
468
497
  parser.add_argument("--emit-categories", help="Print automatically-generated categories from your mapfile, using the decomp.yaml format. These categories are expected to be tweaked and not used as-is.", action="store_true")
469
498
  parser.add_argument("--quiet", help="Avoid printing the progress report to the stdout and to the Github action summary.", action="store_true")
470
499
 
500
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
501
+
471
502
  parser.set_defaults(func=processArguments)
472
503
 
473
504
 
@@ -478,6 +509,7 @@ class SpecificSettings:
478
509
  categories: list[Category]
479
510
  pathIndex: int|None
480
511
  checkAsmPaths: bool
512
+ reportData: bool
481
513
 
482
514
  @staticmethod
483
515
  def fromDecompConfig(decompConfig: decomp_settings.Config|None=None) -> SpecificSettings|None:
@@ -489,6 +521,7 @@ class SpecificSettings:
489
521
  categories: list[Category] = []
490
522
  pathIndex: int|None = None
491
523
  checkAsmPaths: bool = False
524
+ reportData = False
492
525
  if decompConfig.tools is not None:
493
526
  mapfileParserConfig = decompConfig.tools.get("mapfile_parser")
494
527
  if mapfileParserConfig is not None:
@@ -512,6 +545,7 @@ class SpecificSettings:
512
545
  if var is not None:
513
546
  pathIndex = var
514
547
  checkAsmPaths = bool(raw.get("check_asm_paths", False))
548
+ reportData = bool(raw.get("report_data", False))
515
549
 
516
550
  return SpecificSettings(
517
551
  output,
@@ -519,6 +553,7 @@ class SpecificSettings:
519
553
  categories,
520
554
  pathIndex,
521
555
  checkAsmPaths,
556
+ reportData,
522
557
  )
523
558
 
524
559
  @dataclasses.dataclass
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  from pathlib import Path
11
12
  from typing import TextIO
@@ -21,13 +22,18 @@ def writePj64SymsToFile(mapFile: mapfile.MapFile, outFile: TextIO):
21
22
  symType = "code" if file.sectionType == ".text" else "data"
22
23
  outFile.write(f"{sym.vram:08X},{symType},{sym.name}\n")
23
24
 
24
- def doPj64Syms(mapPath: Path, outputPath: Path|None) -> int:
25
+ def doPj64Syms(
26
+ mapPath: Path,
27
+ outputPath: Path|None,
28
+ plfResolver: Callable[[Path], Path|None]|None=None,
29
+ ) -> int:
25
30
  if not mapPath.exists():
26
31
  print(f"Could not find mapfile at '{mapPath}'")
27
32
  return 1
28
33
 
29
- mapFile = mapfile.MapFile()
30
- mapFile.readMapFile(mapPath)
34
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
35
+ if plfResolver is not None:
36
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
31
37
 
32
38
  if outputPath is None:
33
39
  writePj64SymsToFile(mapFile, sys.stdout)
@@ -48,7 +54,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
48
54
 
49
55
  outputPath: Path = args.output
50
56
 
51
- exit(doPj64Syms(mapPath, outputPath))
57
+ plfExt: list[str]|None = args.plf_ext
58
+
59
+ plfResolver = None
60
+ if plfExt is not None:
61
+ def resolver(x: Path) -> Path|None:
62
+ if x.suffix in plfExt:
63
+ newPath = x.with_suffix(".map")
64
+ if newPath.exists():
65
+ return newPath
66
+ return None
67
+
68
+ plfResolver = resolver
69
+
70
+ exit(doPj64Syms(mapPath, outputPath, plfResolver=plfResolver))
52
71
 
53
72
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
54
73
  parser = subparser.add_parser("pj64_syms", help="Produce a PJ64 compatible symbol map.")
@@ -68,4 +87,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
68
87
 
69
88
  parser.add_argument("output", help="Path to output file. If omitted then output will be written to stdout", type=Path, nargs="?")
70
89
 
90
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
91
+
71
92
  parser.set_defaults(func=processArguments)
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import argparse
9
+ from collections.abc import Callable
9
10
  import decomp_settings
10
11
  import json
11
12
  from pathlib import Path
@@ -14,20 +15,37 @@ from .. import mapfile
14
15
  from .. import progress_stats
15
16
 
16
17
 
17
- def getProgress(mapPath: Path, asmPath: Path, nonmatchingsPath: Path, pathIndex: int=2, checkFunctionFiles: bool=True, debugging: bool=False) -> tuple[progress_stats.ProgressStats, dict[str, progress_stats.ProgressStats]]:
18
- mapFile = mapfile.MapFile()
19
-
20
- mapFile.debugging = debugging
21
- mapFile.readMapFile(mapPath)
22
-
23
- return mapFile.filterBySectionType(".text").getProgress(asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles)
24
-
25
- def doProgress(mapPath: Path, asmPath: Path, nonmatchingsPath: Path, pathIndex: int=2, checkFunctionFiles: bool=True, print_json: bool=False, debugging: bool=False) -> int:
18
+ def getProgress(
19
+ mapPath: Path,
20
+ asmPath: Path,
21
+ nonmatchingsPath: Path,
22
+ pathIndex: int=2,
23
+ checkFunctionFiles: bool=True,
24
+ debugging: bool=False,
25
+ plfResolver: Callable[[Path], Path|None]|None=None,
26
+ ) -> tuple[progress_stats.ProgressStats, dict[str, progress_stats.ProgressStats]]:
27
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
28
+ mapFile.filterBySectionType(".text")
29
+ if plfResolver is not None:
30
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
31
+
32
+ return mapFile.getProgress(asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles)
33
+
34
+ def doProgress(
35
+ mapPath: Path,
36
+ asmPath: Path,
37
+ nonmatchingsPath: Path,
38
+ pathIndex: int=2,
39
+ checkFunctionFiles: bool=True,
40
+ print_json: bool=False,
41
+ debugging: bool=False,
42
+ plfResolver: Callable[[Path], Path|None]|None=None,
43
+ ) -> int:
26
44
  if not mapPath.exists():
27
45
  print(f"Could not find mapfile at '{mapPath}'")
28
46
  return 1
29
47
 
30
- totalStats, progressPerFolder = getProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, debugging=debugging)
48
+ totalStats, progressPerFolder = getProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, debugging=debugging, plfResolver=plfResolver)
31
49
 
32
50
  if print_json:
33
51
  json_temp: dict[str, dict[str, int|float]] = {
@@ -59,7 +77,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
59
77
  debugging: bool = args.debugging #! @deprecated
60
78
  print_json: bool = args.json
61
79
 
62
- exit(doProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, print_json=print_json, debugging=debugging))
80
+ plfExt: list[str]|None = args.plf_ext
81
+
82
+ plfResolver = None
83
+ if plfExt is not None:
84
+ def resolver(x: Path) -> Path|None:
85
+ if x.suffix in plfExt:
86
+ newPath = x.with_suffix(".map")
87
+ if newPath.exists():
88
+ return newPath
89
+ return None
90
+
91
+ plfResolver = resolver
92
+
93
+ exit(doProgress(mapPath, asmPath, nonmatchingsPath, pathIndex=pathIndex, checkFunctionFiles=checkFunctionFiles, print_json=print_json, debugging=debugging, plfResolver=plfResolver))
63
94
 
64
95
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
65
96
  parser = subparser.add_parser("progress", help="Computes current progress of the matched functions. Relies on a splat (https://github.com/ethteck/splat) folder structure and matched functions not longer having a file.")
@@ -92,4 +123,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
92
123
  parser.add_argument("-d", "--debugging", help="Enable debugging prints. This option is deprecated", action="store_true")
93
124
  parser.add_argument("-j", "--json", help="Print the stats as json instead of a human readable format.", action="store_true")
94
125
 
126
+ parser.add_argument("-x", "--plf-ext", help="File extension for partially linked files (plf). Will be used to transform the `plf`s path into a mapfile path by replacing the extension. The extension must contain the leading period. This argument can be passed multiple times.", action="append")
127
+
95
128
  parser.set_defaults(func=processArguments)