mapfile-parser 2.9.4__cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 2.11.0__cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

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.
@@ -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)
@@ -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,13 +14,22 @@ from .. import mapfile
13
14
  from .. import utils
14
15
 
15
16
 
16
- def doSymInfo(mapPath: Path, symName: str, *, as_vram: bool=False, as_vrom: bool=False, as_name: bool=False) -> int:
17
+ def doSymInfo(
18
+ mapPath: Path,
19
+ symName: str,
20
+ *,
21
+ as_vram: bool=False,
22
+ as_vrom: bool=False,
23
+ as_name: bool=False,
24
+ plfResolver: Callable[[Path], Path|None]|None=None,
25
+ ) -> int:
17
26
  if not mapPath.exists():
18
27
  print(f"Could not find mapfile at '{mapPath}'")
19
28
  return 1
20
29
 
21
- mapFile = mapfile.MapFile()
22
- mapFile.readMapFile(mapPath)
30
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
31
+ if plfResolver is not None:
32
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
23
33
 
24
34
  possibleFiles: list[mapfile.Section] = []
25
35
 
@@ -66,8 +76,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
66
76
  as_vram: bool = args.vram
67
77
  as_vrom: bool = args.vrom
68
78
  as_name: bool = args.name
79
+ plfExt: list[str]|None = args.plf_ext
69
80
 
70
- exit(doSymInfo(mapPath, symName, as_vram=as_vram, as_vrom=as_vrom, as_name=as_name))
81
+ plfResolver = None
82
+ if plfExt is not None:
83
+ def resolver(x: Path) -> Path|None:
84
+ if x.suffix in plfExt:
85
+ newPath = x.with_suffix(".map")
86
+ if newPath.exists():
87
+ return newPath
88
+ return None
89
+
90
+ plfResolver = resolver
91
+
92
+ exit(doSymInfo(mapPath, symName, as_vram=as_vram, as_vrom=as_vrom, as_name=as_name, plfResolver=plfResolver))
71
93
 
72
94
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
73
95
  parser = subparser.add_parser("sym_info", help="Display various information about a symbol or address.")
@@ -86,6 +108,8 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
86
108
  parser.add_argument("mapfile", help="Path to a map file.", type=Path)
87
109
  parser.add_argument("symname", help="Symbol name or VROM/VRAM address to lookup. How to treat this argument will be guessed.")
88
110
 
111
+ 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")
112
+
89
113
  vram_vrom_group = parser.add_mutually_exclusive_group()
90
114
  vram_vrom_group.add_argument("--vram", help="Treat the argument as a VRAM address instead of guessing.", action="store_true")
91
115
  vram_vrom_group.add_argument("--vrom", help="Treat the argument as a VROM address instead of guessing.", action="store_true")
@@ -6,19 +6,29 @@
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
 
12
13
  from .. import mapfile
13
14
 
14
15
 
15
- def doSymbolSizesCsv(mapPath: Path, outputPath: Path|None, filterSection: str|None=None, sameFolder: bool=False, symbolsSummary: bool=False, allFiles: bool=False) -> int:
16
+ def doSymbolSizesCsv(
17
+ mapPath: Path,
18
+ outputPath: Path|None,
19
+ filterSection: str|None=None,
20
+ sameFolder: bool=False,
21
+ symbolsSummary: bool=False,
22
+ allFiles: bool=False,
23
+ plfResolver: Callable[[Path], Path|None]|None=None,
24
+ ) -> int:
16
25
  if not mapPath.exists():
17
26
  print(f"Could not find mapfile at '{mapPath}'")
18
27
  return 1
19
28
 
20
- mapFile = mapfile.MapFile()
21
- mapFile.readMapFile(mapPath)
29
+ mapFile = mapfile.MapFile.newFromMapFile(mapPath)
30
+ if plfResolver is not None:
31
+ mapFile = mapFile.resolvePartiallyLinkedFiles(plfResolver)
22
32
 
23
33
  if filterSection is not None:
24
34
  mapFile = mapFile.filterBySectionType(filterSection)
@@ -53,8 +63,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
53
63
  sameFolder: bool = args.same_folder
54
64
  symbolsSummary: bool = args.symbols
55
65
  allFiles: bool = args.all
66
+ plfExt: list[str]|None = args.plf_ext
56
67
 
57
- exit(doSymbolSizesCsv(mapPath, outputPath, filterSection, sameFolder, symbolsSummary, allFiles))
68
+ plfResolver = None
69
+ if plfExt is not None:
70
+ def resolver(x: Path) -> Path|None:
71
+ if x.suffix in plfExt:
72
+ newPath = x.with_suffix(".map")
73
+ if newPath.exists():
74
+ return newPath
75
+ return None
76
+
77
+ plfResolver = resolver
78
+
79
+ exit(doSymbolSizesCsv(mapPath, outputPath, filterSection, sameFolder, symbolsSummary, allFiles, plfResolver=plfResolver))
58
80
 
59
81
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
60
82
  parser = subparser.add_parser("symbol_sizes_csv", help="Produces a csv summarizing the files sizes by parsing a map file.")
@@ -78,4 +100,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
78
100
  parser.add_argument("-a", "--all", help="Don't skip files without symbols.", action="store_true")
79
101
  parser.add_argument("-f", "--filter-section", help="Only print the symbols of the passed section. For example: .text")
80
102
 
103
+ 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")
104
+
81
105
  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
  from pathlib import Path
11
12
  import requests # type: ignore
@@ -55,12 +56,25 @@ def uploadEntriesToFrogress(entries: dict[str, int], category: str, url: str, ap
55
56
  return 0
56
57
 
57
58
 
58
- def doUploadFrogress(mapPath: Path, asmPath: Path, nonmatchingsPath: Path, project: str, version: str, category: str, baseurl: str, apikey: str|None=None, verbose: bool=False, checkFunctionFiles: bool=True, dryRun: bool=False) -> int:
59
+ def doUploadFrogress(
60
+ mapPath: Path,
61
+ asmPath: Path,
62
+ nonmatchingsPath: Path,
63
+ project: str,
64
+ version: str,
65
+ category: str,
66
+ baseurl: str,
67
+ apikey: str|None=None,
68
+ verbose: bool=False,
69
+ checkFunctionFiles: bool=True,
70
+ dryRun: bool=False,
71
+ plfResolver: Callable[[Path], Path|None]|None=None,
72
+ ) -> int:
59
73
  if not mapPath.exists():
60
74
  print(f"Could not find mapfile at '{mapPath}'")
61
75
  return 1
62
76
 
63
- totalStats, progressPerFolder = progress.getProgress(mapPath, asmPath, nonmatchingsPath, checkFunctionFiles=checkFunctionFiles)
77
+ totalStats, progressPerFolder = progress.getProgress(mapPath, asmPath, nonmatchingsPath, checkFunctionFiles=checkFunctionFiles, plfResolver=plfResolver)
64
78
 
65
79
  entries: dict[str, int] = getFrogressEntriesFromStats(totalStats, progressPerFolder, verbose)
66
80
 
@@ -89,8 +103,20 @@ def processArguments(args: argparse.Namespace, decompConfig: decomp_settings.Con
89
103
  verbose: bool = args.verbose
90
104
  checkFunctionFiles: bool = not args.avoid_function_files
91
105
  dryRun: bool = args.dry_run
106
+ plfExt: list[str]|None = args.plf_ext
92
107
 
93
- exit(doUploadFrogress(mapPath, asmPath, nonmatchingsPath, project, version, category, baseurl, apikey, verbose, checkFunctionFiles, dryRun=dryRun))
108
+ plfResolver = None
109
+ if plfExt is not None:
110
+ def resolver(x: Path) -> Path|None:
111
+ if x.suffix in plfExt:
112
+ newPath = x.with_suffix(".map")
113
+ if newPath.exists():
114
+ return newPath
115
+ return None
116
+
117
+ plfResolver = resolver
118
+
119
+ exit(doUploadFrogress(mapPath, asmPath, nonmatchingsPath, project, version, category, baseurl, apikey, verbose, checkFunctionFiles, dryRun=dryRun, plfResolver=plfResolver))
94
120
 
95
121
  def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser], decompConfig: decomp_settings.Config|None=None):
96
122
  parser = subparser.add_parser("upload_frogress", help="Uploads current progress of the matched functions to frogress (https://github.com/decompals/frogress).")
@@ -132,4 +158,6 @@ def addSubparser(subparser: argparse._SubParsersAction[argparse.ArgumentParser],
132
158
  parser.add_argument("-f", "--avoid-function-files", help="Avoid checking if the assembly file for a function exists as a way to determine if the function has been matched or not", action="store_true")
133
159
  parser.add_argument("-d", "--dry-run", help="Stop before uploading the progress.", action="store_true")
134
160
 
161
+ 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")
162
+
135
163
  parser.set_defaults(func=processArguments)
mapfile_parser/mapfile.py CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ from collections.abc import Callable
8
9
  import dataclasses
9
10
  import re
10
11
  from typing import Any, Generator
@@ -99,6 +100,7 @@ class Symbol:
99
100
  Note the symbol with the actual `.NON_MATCHING` will have this member
100
101
  set to `false`.
101
102
  """
103
+ inferredStatic: bool = False
102
104
 
103
105
  def getVramStr(self) -> str:
104
106
  return f"0x{self.vram:08X}"
@@ -159,7 +161,7 @@ class Symbol:
159
161
 
160
162
 
161
163
  def clone(self) -> Symbol:
162
- return Symbol(self.name, self.vram, self.size, self.vrom, self.align)
164
+ return Symbol(self.name, self.vram, self.size, self.vrom, self.align, self.nonmatchingSymExists, self.inferredStatic)
163
165
 
164
166
 
165
167
  def __eq__(self, other: object) -> bool:
@@ -377,7 +379,7 @@ class Section:
377
379
 
378
380
 
379
381
  def clone(self) -> Section:
380
- f = Section(self.filepath, self.vram, self.size, self.sectionType, self.vrom, self.align)
382
+ f = Section(self.filepath, self.vram, self.size, self.sectionType, self.vrom, self.align, self.isFill)
381
383
  for sym in self._symbols:
382
384
  f._symbols.append(sym.clone())
383
385
  return f
@@ -449,7 +451,7 @@ class Segment:
449
451
  newSegment._sectionsList.append(section)
450
452
  return newSegment
451
453
 
452
- #! @deprecated: Use either `getEverySectionExceptSectionType` instead.
454
+ #! @deprecated: Use `getEverySectionExceptSectionType` instead.
453
455
  def getEveryFileExceptSectionType(self, sectionType: str) -> Segment:
454
456
  return self.getEverySectionExceptSectionType(sectionType)
455
457
 
@@ -588,28 +590,31 @@ class Segment:
588
590
  self._sectionsList.append(section)
589
591
 
590
592
 
591
- #! @deprecated: Use either `copySectionList` instead.
593
+ #! @deprecated: Use `copySectionList` instead.
592
594
  def copyFileList(self) -> list[Section]:
593
595
  """Returns a copy (not a reference) of the internal section list"""
594
596
  return self.copySectionList()
595
597
 
596
- #! @deprecated: Use either `setSectionList` instead.
598
+ #! @deprecated: Use `setSectionList` instead.
597
599
  def setFileList(self, newList: list[Section]) -> None:
598
600
  """Replaces the internal section list with a copy of `newList`"""
599
601
  return self.setSectionList(newList)
600
602
 
601
- #! @deprecated: Use either `appendSection` instead.
603
+ #! @deprecated: Use `appendSection` instead.
602
604
  def appendFile(self, section: Section) -> None:
603
605
  """Appends a copy of `section` into the internal section list"""
604
606
  return self.appendSection(section)
605
607
 
606
608
 
607
609
  def clone(self) -> Segment:
608
- s = Segment(self.name, self.vram, self.size, self.vrom, self.align)
610
+ s = self.cloneNoSectionlist()
609
611
  for f in self._sectionsList:
610
612
  s._sectionsList.append(f.clone())
611
613
  return s
612
614
 
615
+ def cloneNoSectionlist(self) -> Segment:
616
+ return Segment(self.name, self.vram, self.size, self.vrom, self.align)
617
+
613
618
 
614
619
  def __iter__(self) -> Generator[Section, None, None]:
615
620
  for section in self._sectionsList:
@@ -683,7 +688,7 @@ class MapFile:
683
688
  for section in segment:
684
689
  newSection = Section(section.filepath, section.vram, section.size, section.sectionType, section.vrom, section.align, section.isFill)
685
690
  for symbol in section:
686
- newSymbol = Symbol(symbol.name, symbol.vram, symbol.size, symbol.vrom, symbol.align, symbol.nonmatchingSymExists)
691
+ newSymbol = Symbol(symbol.name, symbol.vram, symbol.size, symbol.vrom, symbol.align, symbol.nonmatchingSymExists, symbol.inferredStatic)
687
692
 
688
693
  newSection._symbols.append(newSymbol)
689
694
  newSegment._sectionsList.append(newSection)
@@ -698,7 +703,7 @@ class MapFile:
698
703
  newSection = SectionRs(section.filepath, section.vram, section.size, section.sectionType, section.vrom, section.align, section.isFill)
699
704
  for symbol in section._symbols:
700
705
  size = symbol.size if symbol.size is not None else 0
701
- newSymbol = SymbolRs(symbol.name, symbol.vram, size, symbol.vrom, symbol.align, symbol.nonmatchingSymExists)
706
+ newSymbol = SymbolRs(symbol.name, symbol.vram, size, symbol.vrom, symbol.align, symbol.nonmatchingSymExists, symbol.inferredStatic)
702
707
 
703
708
  newSection.appendSymbol(newSymbol)
704
709
  newSegment.appendFile(newSection)
@@ -706,7 +711,7 @@ class MapFile:
706
711
 
707
712
  return nativeMapFile
708
713
 
709
- #! @deprecated: Use either `newFromMapFile` instead.
714
+ #! @deprecated: Use `newFromMapFile` instead.
710
715
  def readMapFile(self, mapPath: Path):
711
716
  """
712
717
  Opens the mapfile pointed by the `mapPath` argument and parses it.
@@ -719,12 +724,11 @@ class MapFile:
719
724
  - Metrowerks ld
720
725
  """
721
726
 
722
- nativeMapFile = MapFileRs()
723
- nativeMapFile.readMapFile(mapPath)
727
+ nativeMapFile = MapFileRs.newFromMapFile(mapPath)
724
728
 
725
729
  self._transferContentsFromNativeMapFile(nativeMapFile)
726
730
 
727
- #! @deprecated: Use either `newFromMapStr` instead.
731
+ #! @deprecated: Use `newFromMapStr` instead.
728
732
  def parseMapContents(self, mapContents: str):
729
733
  """
730
734
  Parses the contents of the map.
@@ -739,12 +743,11 @@ class MapFile:
739
743
  - Metrowerks ld
740
744
  """
741
745
 
742
- nativeMapFile = MapFileRs()
743
- nativeMapFile.parseMapContents(mapContents)
746
+ nativeMapFile = MapFileRs.newFromMapStr(mapContents)
744
747
 
745
748
  self._transferContentsFromNativeMapFile(nativeMapFile)
746
749
 
747
- #! @deprecated: Use either `newFromGnuMapStr` instead.
750
+ #! @deprecated: Use `newFromGnuMapStr` instead.
748
751
  def parseMapContentsGNU(self, mapContents: str):
749
752
  """
750
753
  Parses the contents of a GNU ld map.
@@ -752,12 +755,11 @@ class MapFile:
752
755
  The `mapContents` argument must contain the contents of a GNU ld mapfile.
753
756
  """
754
757
 
755
- nativeMapFile = MapFileRs()
756
- nativeMapFile.parseMapContentsGNU(mapContents)
758
+ nativeMapFile = MapFileRs.newFromGnuMapStr(mapContents)
757
759
 
758
760
  self._transferContentsFromNativeMapFile(nativeMapFile)
759
761
 
760
- #! @deprecated: Use either `newFromLldMapStr` instead.
762
+ #! @deprecated: Use `newFromLldMapStr` instead.
761
763
  def parseMapContentsLLD(self, mapContents: str):
762
764
  """
763
765
  Parses the contents of a clang ld.lld map.
@@ -765,8 +767,7 @@ class MapFile:
765
767
  The `mapContents` argument must contain the contents of a clang ld.lld mapfile.
766
768
  """
767
769
 
768
- nativeMapFile = MapFileRs()
769
- nativeMapFile.parseMapContentsLLD(mapContents)
770
+ nativeMapFile = MapFileRs.newFromLldMapStr(mapContents)
770
771
 
771
772
  self._transferContentsFromNativeMapFile(nativeMapFile)
772
773
 
@@ -1015,6 +1016,86 @@ class MapFile:
1015
1016
 
1016
1017
  return compInfo
1017
1018
 
1019
+ def resolvePartiallyLinkedFiles(self, resolver: Callable[[Path], Path|None]) -> MapFile:
1020
+ """
1021
+ Resolve sections and paths of a mapfile built from partially linked objects.
1022
+
1023
+ `elf` files built by using partially linked files/objects (usually
1024
+ referred to as `plf`) usually generate mapfiles that have filepaths that
1025
+ point to the partially linked objects instead of the original objects
1026
+ used to build those intermediary objects, making it awkward to work with
1027
+ paths because all symbols will be listed as part as the same single `plf`.
1028
+
1029
+ This function resolves those sections by using a resolver callback that
1030
+ transforms a path to an object/`plf` into the corresponding mapfile of
1031
+ said partially linked object.
1032
+ This callback should return `None` if the given path does not correspond
1033
+ to a `plf`, the pointed mapfile does not exist, etc.
1034
+
1035
+ An usual convention for a file extension for partially linked objects is
1036
+ the `.plf` extension instead of `.o`.
1037
+ """
1038
+
1039
+ # Construct a mapping for every "plf -> map"
1040
+ knownMaps: dict[Path, MapFile] = dict()
1041
+ for seg in self._segmentsList:
1042
+ for sect in seg._sectionsList:
1043
+ # Only read the map if this is a new plf.
1044
+ if sect.filepath in knownMaps:
1045
+ continue
1046
+ if (other_map_path := resolver(sect.filepath)) is not None:
1047
+ knownMaps[sect.filepath] = MapFile.newFromMapFile(other_map_path)
1048
+ return self._resolve_plf_impl(knownMaps)
1049
+
1050
+ def _resolve_plf_impl(self, knownMaps: dict[Path, MapFile]) -> MapFile:
1051
+ if len(knownMaps) == 0:
1052
+ return self.clone()
1053
+
1054
+ resolvedMap = MapFile()
1055
+ for seg in self._segmentsList:
1056
+ newSeg = seg.cloneNoSectionlist()
1057
+
1058
+ for sect in seg._sectionsList:
1059
+ if (otherMap := knownMaps.get(sect.filepath)) is not None:
1060
+ # Each segment of a plf is just a normal elf section
1061
+ partialSegment = None
1062
+ for x in otherMap._segmentsList:
1063
+ if x.name == sect.sectionType:
1064
+ partialSegment = x
1065
+ break
1066
+
1067
+ if partialSegment is not None:
1068
+ # Take all the sections from the plf map and insert them
1069
+ # into the new generated map, replacing the old sections
1070
+ # and symbols.
1071
+ for partialSect in partialSegment._sectionsList:
1072
+ sectTemp = partialSect.clone()
1073
+
1074
+ # Adjust the vram and vrom addresses of the section
1075
+ # because they are relative to zero.
1076
+ sectTemp.vram += sect.vram - partialSegment.vram
1077
+ if sectTemp.vrom is not None and sect.vrom is not None and partialSegment.vrom is not None:
1078
+ sectTemp.vrom = sectTemp.vrom + sect.vrom - partialSegment.vrom
1079
+
1080
+ # Adjust vram and vrom of symbols too.
1081
+ for partialSym in sectTemp._symbols:
1082
+ partialSym.vram += sect.vram - partialSegment.vram
1083
+ if partialSym.vrom is not None and sect.vrom is not None and partialSegment.vrom is not None:
1084
+ partialSym.vrom = partialSym.vrom + sect.vrom - partialSegment.vrom
1085
+
1086
+ newSeg._sectionsList.append(sectTemp)
1087
+ else:
1088
+ # Keep the original section if there are no sections
1089
+ # matching the section type in the plf.
1090
+ newSeg._sectionsList.append(sect.clone())
1091
+ else:
1092
+ # Keep the original section if there are no maps for this path
1093
+ newSeg._sectionsList.append(sect.clone())
1094
+ pass
1095
+
1096
+ resolvedMap._segmentsList.append(newSeg)
1097
+ return resolvedMap
1098
+
1018
1099
 
1019
1100
  def printAsCsv(self, printVram: bool=True, skipWithoutSymbols: bool=True):
1020
1101
  print(self.toCsv(printVram=printVram, skipWithoutSymbols=skipWithoutSymbols), end="")
@@ -82,8 +82,18 @@ class Symbol:
82
82
  vrom: int|None
83
83
  align: int|None
84
84
  nonmatchingSymExists: bool
85
-
86
- def __init__(self, name: str, vram: int, size: int=0, vrom: int|None=None, align: int|None=None, nonmatchingSymExists: bool=False): ...
85
+ inferredStatic: bool
86
+
87
+ def __init__(
88
+ self,
89
+ name: str,
90
+ vram: int,
91
+ size: int=0,
92
+ vrom: int|None=None,
93
+ align: int|None=None,
94
+ nonmatchingSymExists: bool=False,
95
+ inferredStatic: bool=False,
96
+ ): ...
87
97
 
88
98
  def getVramStr(self) -> str: ...
89
99
  def getSizeStr(self) -> str: ...
@@ -301,6 +311,23 @@ class MapFile:
301
311
  def __len__(self) -> int: ...
302
312
 
303
313
  class ReportCategories:
314
+ """
315
+ Allows configuring certain aspects of the generated objdiff report file,
316
+ like categories.
317
+ """
304
318
  def __init__(self): ...
305
319
 
306
- def push(self, id: str, name: str, paths: list[str]): ...
320
+ def push(self, id: str, name: str, paths: list[str]):
321
+ """
322
+ Add a category with the given list of paths.
323
+
324
+ If the category id already exists then the paths are merged together
325
+ with the previous list of paths.
326
+ """
327
+
328
+ def setReportData(self, reportData: bool):
329
+ """
330
+ Track data progress on the generated report file.
331
+
332
+ Defaults to `True`.
333
+ """
@@ -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
@@ -0,0 +1,25 @@
1
+ mapfile_parser-2.11.0.dist-info/METADATA,sha256=cXRzabRyH-3jCMPfSv5mY5t_NOoEcj7H6-44k3fRRRM,5648
2
+ mapfile_parser-2.11.0.dist-info/WHEEL,sha256=Xci0wQUn185O40gd7BpQOd6FhkCRTTECoTx1iWoeZos,131
3
+ mapfile_parser-2.11.0.dist-info/licenses/LICENSE,sha256=FT7oxTcFUtz2c5eYIYePfzj2UD3hvxtLTa3FWz_nJuM,1073
4
+ mapfile_parser/__init__.py,sha256=p1d7qH8b9dqYKB-aZJBu4yC4WXzVau9Cr1GJ6Eh4CoM,856
5
+ mapfile_parser/__main__.py,sha256=vErQTK2miHF7NseqLgI567tbFUjOrQ7UNxXOr_FwBhc,2176
6
+ mapfile_parser/frontends/__init__.py,sha256=RIUBbM6crp4V4EeMQy0whTonYauh0Oi2oaxu1NfWNao,512
7
+ mapfile_parser/frontends/bss_check.py,sha256=RierwrcKodWAf_-lD4xm9CjF_gh7ponlx0qEacRXKBk,9666
8
+ mapfile_parser/frontends/first_diff.py,sha256=DyQRGHlYTVgfqEo6S25l335DgfJa2XbJ_V37-RQPmjM,10037
9
+ mapfile_parser/frontends/jsonify.py,sha256=xchQspD7p0ai4ZzcKNgLN8pF9K56BGZN0YfcSUwWS5A,3550
10
+ mapfile_parser/frontends/objdiff_report.py,sha256=Iuyb9HlFzSv-TILrywHLREvOKDPUF4QNari07iXP9jQ,20656
11
+ mapfile_parser/frontends/pj64_syms.py,sha256=uQKjBM7qSAfeD9GvURpb_k-TdzynY3XINjp5jli_oJw,3213
12
+ mapfile_parser/frontends/progress.py,sha256=QAzuds8q9gZVin7fgfeB_1bjKwnNYTfd31P_6rOHnRA,5601
13
+ mapfile_parser/frontends/sym_info.py,sha256=10AA3CCIEvyjhnp9nOldaPeh2AdQpwh5vH79-1yVknc,4448
14
+ mapfile_parser/frontends/symbol_sizes_csv.py,sha256=Jr9hBYsMpq7sbLgMLiNi8u_qNXlAy1pOyTZKVvnI_hA,4050
15
+ mapfile_parser/frontends/upload_frogress.py,sha256=PD9XupSd5LeD-xMjVUOjWDcQqK3gt4-1ykf7VVGBMoU,6528
16
+ mapfile_parser/internals/__init__.py,sha256=WW--q8KRIfYTQLOMvRO7PCMSf7uWk-I1T20KU0C2a_0,327
17
+ mapfile_parser/internals/objdiff_report.py,sha256=sZh7rUHdoWJfZKQ3EIeuNH9LqdEis2t7heCo1OOwKJU,6214
18
+ mapfile_parser/mapfile.py,sha256=kN3kOsTQENN0GrpybP-1Yn9NzK-E3qPMR23uuKciAWU,43060
19
+ mapfile_parser/mapfile_parser.cpython-310-aarch64-linux-gnu.so,sha256=4cU9edmyxaZkjkpjZSX4qrkyg_paLiooiishgebLAWo,3662440
20
+ mapfile_parser/mapfile_parser.pyi,sha256=urs5OyBZQIZpF_ncmk1Bfs3H8k9T2CCAGm26bWG9lck,11816
21
+ mapfile_parser/mapfile_rs.py,sha256=0sVtLGvz5SMH5bKeTYu-3sM0f-_xXFRfDyY2g1GDh54,4078
22
+ mapfile_parser/progress_stats.py,sha256=T9V52QIoNBtvsPAbYRlCOAio95Z8VxzZep8bCc1J-H0,2535
23
+ mapfile_parser/progress_stats_rs.py,sha256=Rc9-PuZoKWVTO9TEIRk3Mpw0v6FdCFaJk2h7jUGyT_0,483
24
+ mapfile_parser/utils.py,sha256=Bz6pcuR9lax72Y7avgbOIBlyN-1GcxfDxz5iBodr3n0,1517
25
+ mapfile_parser-2.11.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.6)
2
+ Generator: maturin (1.9.4)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64
@@ -1,25 +0,0 @@
1
- mapfile_parser-2.9.4.dist-info/METADATA,sha256=caVcmO4gT_gP9yjCNcy8wWsLvAq20B3gtz95fQ3VfKU,5810
2
- mapfile_parser-2.9.4.dist-info/WHEEL,sha256=-7sdZJv48eH6meERNCoAANQ5SOegBw5DhY-YjlWczew,131
3
- mapfile_parser-2.9.4.dist-info/licenses/LICENSE,sha256=FT7oxTcFUtz2c5eYIYePfzj2UD3hvxtLTa3FWz_nJuM,1073
4
- mapfile_parser/__init__.py,sha256=LXglMB86pxkPrX_nAqAY2Ma_QV4xfGwmEpV9-a6LTy4,855
5
- mapfile_parser/__main__.py,sha256=vErQTK2miHF7NseqLgI567tbFUjOrQ7UNxXOr_FwBhc,2176
6
- mapfile_parser/frontends/__init__.py,sha256=RIUBbM6crp4V4EeMQy0whTonYauh0Oi2oaxu1NfWNao,512
7
- mapfile_parser/frontends/bss_check.py,sha256=O50pVG8uCp7poEqtrCbh05eIC_TYq3OIaD5VCZz4xGQ,8328
8
- mapfile_parser/frontends/first_diff.py,sha256=P5CqdGM_X7-WCcW7ubktKI6fnhHxezc1R0aL4_v3bOA,8899
9
- mapfile_parser/frontends/jsonify.py,sha256=Xq4fha2wJ70WH0an4BXaLnwgjYhNgAwTvrZZZoicRNQ,2654
10
- mapfile_parser/frontends/objdiff_report.py,sha256=d3I9PgjFIbWIoz_ZDAz58CMOMDrHNEiXwLOAVIlTzUo,18902
11
- mapfile_parser/frontends/pj64_syms.py,sha256=mJwiVGKGBoNrI-6VB4UJSVz7mIlihivX3KvUGRtoyMY,2332
12
- mapfile_parser/frontends/progress.py,sha256=j-6OtUCx8af8f3mcy1njA8AEEkR3mYf9_caCh-gFWDY,4563
13
- mapfile_parser/frontends/sym_info.py,sha256=CGpMdOHUpZslvTe8RpGJ-xrYhEjkhuzYKSJS4FZ60WI,3536
14
- mapfile_parser/frontends/symbol_sizes_csv.py,sha256=HMOBwAu_pN5dufiT-SEGg7cnIAVkyIDmVelP3YIyq0c,3138
15
- mapfile_parser/frontends/upload_frogress.py,sha256=ei3pSz2rzVpDj-0CASnPuyqqhu5Lm90mZ_2tsbF9ALU,5639
16
- mapfile_parser/internals/__init__.py,sha256=WW--q8KRIfYTQLOMvRO7PCMSf7uWk-I1T20KU0C2a_0,327
17
- mapfile_parser/internals/objdiff_report.py,sha256=sZh7rUHdoWJfZKQ3EIeuNH9LqdEis2t7heCo1OOwKJU,6214
18
- mapfile_parser/mapfile.py,sha256=498NSrZtorSe-W0BzxnMtq-d0xOBBcaj8fB9iRK4Tmg,38834
19
- mapfile_parser/mapfile_parser.cpython-310-aarch64-linux-gnu.so,sha256=lo2vNMahULANsQKeaPq8fGS62a5gtI3XjZ_gYr-aThs,3641232
20
- mapfile_parser/mapfile_parser.pyi,sha256=AuaCWiMySw-oBr-AR2NSbYbhpVP8TGS16rMeey6wc28,11227
21
- mapfile_parser/mapfile_rs.py,sha256=0sVtLGvz5SMH5bKeTYu-3sM0f-_xXFRfDyY2g1GDh54,4078
22
- mapfile_parser/progress_stats.py,sha256=T9V52QIoNBtvsPAbYRlCOAio95Z8VxzZep8bCc1J-H0,2535
23
- mapfile_parser/progress_stats_rs.py,sha256=Rc9-PuZoKWVTO9TEIRk3Mpw0v6FdCFaJk2h7jUGyT_0,483
24
- mapfile_parser/utils.py,sha256=Bz6pcuR9lax72Y7avgbOIBlyN-1GcxfDxz5iBodr3n0,1517
25
- mapfile_parser-2.9.4.dist-info/RECORD,,