mapfile-parser 2.9.4__cp310-cp310-win_amd64.whl → 2.11.0__cp310-cp310-win_amd64.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.
- mapfile_parser/__init__.py +1 -1
- mapfile_parser/frontends/bss_check.py +40 -8
- mapfile_parser/frontends/first_diff.py +38 -7
- mapfile_parser/frontends/jsonify.py +26 -4
- mapfile_parser/frontends/objdiff_report.py +39 -4
- mapfile_parser/frontends/pj64_syms.py +25 -4
- mapfile_parser/frontends/progress.py +44 -11
- mapfile_parser/frontends/sym_info.py +28 -4
- mapfile_parser/frontends/symbol_sizes_csv.py +28 -4
- mapfile_parser/frontends/upload_frogress.py +31 -3
- mapfile_parser/mapfile.py +102 -21
- mapfile_parser/mapfile_parser.cp310-win_amd64.pyd +0 -0
- mapfile_parser/mapfile_parser.pyi +30 -3
- {mapfile_parser-2.9.4.dist-info → mapfile_parser-2.11.0.dist-info}/METADATA +3 -7
- mapfile_parser-2.11.0.dist-info/RECORD +25 -0
- {mapfile_parser-2.9.4.dist-info → mapfile_parser-2.11.0.dist-info}/WHEEL +1 -1
- mapfile_parser-2.9.4.dist-info/RECORD +0 -25
- {mapfile_parser-2.9.4.dist-info → mapfile_parser-2.11.0.dist-info}/licenses/LICENSE +0 -0
mapfile_parser/__init__.py
CHANGED
@@ -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(
|
17
|
-
|
18
|
-
|
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(
|
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
|
-
|
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
|
12
|
+
from typing import Literal
|
12
13
|
|
13
14
|
from .. import mapfile
|
14
15
|
from .. import utils
|
15
16
|
|
16
17
|
|
17
|
-
def doFirstDiff(
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
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(
|
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
|
-
|
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
|
-
|
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(
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
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
|
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
|
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
|
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 =
|
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
|
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
|
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
|
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
|
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="")
|
Binary file
|
@@ -82,8 +82,18 @@ class Symbol:
|
|
82
82
|
vrom: int|None
|
83
83
|
align: int|None
|
84
84
|
nonmatchingSymExists: bool
|
85
|
-
|
86
|
-
|
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.
|
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.
|
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.
|
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=QqhGok_sqwGuZxwfsJ6RQrI5Wngf1VPftpl7QGtwAEE,5773
|
2
|
+
mapfile_parser-2.11.0.dist-info/WHEEL,sha256=Iz7QqxpWQRXToFIDkGspPPKDuV_klwuhW8ziiU5jhR8,96
|
3
|
+
mapfile_parser-2.11.0.dist-info/licenses/LICENSE,sha256=8N8dS9WOtgJ0rkqNNOcazXKVkD2umzsKSHI0bd2HhG0,1094
|
4
|
+
mapfile_parser/__init__.py,sha256=39UcAN6YfyE1M7ZedKbW1qNQUm6krvcPcQyPTxtV2hM,884
|
5
|
+
mapfile_parser/__main__.py,sha256=BxL4C_wPsFHjvdYkqmL7O3AmvVs9DG34S6Quu843tgs,2235
|
6
|
+
mapfile_parser/frontends/__init__.py,sha256=42Wut4H28j9TjPcADXjPtz5oJ-snrfCDcjotOvReo0k,529
|
7
|
+
mapfile_parser/frontends/bss_check.py,sha256=JWCSkF6s3JwtKIfJomvp-qid-vbPsPA6CDGK4i6SsB4,9894
|
8
|
+
mapfile_parser/frontends/first_diff.py,sha256=I6Nml3EXg3yVnumdXLa7NlIUnUqoqznKQYLfT9Dlnh4,10271
|
9
|
+
mapfile_parser/frontends/jsonify.py,sha256=ZDdW_CvoXTc93Ypm9WI0_dJ4pzfiACrQNg2YN1r1-iM,3642
|
10
|
+
mapfile_parser/frontends/objdiff_report.py,sha256=1sEvKg87WpiTpim3xSJRCbVdjlm8QaH7w0dbkYgPcl8,21247
|
11
|
+
mapfile_parser/frontends/pj64_syms.py,sha256=mLsJCwKbYlIyAxAi7hXPnP8C9oACZ0_x_Rgc9HFEwyg,3305
|
12
|
+
mapfile_parser/frontends/progress.py,sha256=3_qWedz55MamSlb3htPj-n8o4q7PN_0_fPtnyDRV2qM,5729
|
13
|
+
mapfile_parser/frontends/sym_info.py,sha256=zoy8dq5bI_jlqld7FuJwjrJbnbictEYJQiNrBjh4oIM,4566
|
14
|
+
mapfile_parser/frontends/symbol_sizes_csv.py,sha256=DEP0612IYaQm9x1UauOU7QHtIXtlRQJCsE-a1GdeceA,4155
|
15
|
+
mapfile_parser/frontends/upload_frogress.py,sha256=xZji60WnQzL_ojQ39v4Ki0G7wgnMlH-NMEyLYfQ2AGM,6691
|
16
|
+
mapfile_parser/internals/__init__.py,sha256=lA5cxXEs9jtz1O5I68rtpEnz3LozDqNAOxV7GmyW2tg,340
|
17
|
+
mapfile_parser/internals/objdiff_report.py,sha256=KBNuqjMxXMXZllqLJd4V-wUFFynLK4qT2UIJgjXKysI,6401
|
18
|
+
mapfile_parser/mapfile.py,sha256=vuY7uzzH_jPi8k2EItdRg2H0YXJfTVuEPwGWm2AFv7w,44220
|
19
|
+
mapfile_parser/mapfile_parser.cp310-win_amd64.pyd,sha256=afVQDjCgHcpst8bhqPeKnlSMSXmmMdMjDh4_9_egt5s,2593792
|
20
|
+
mapfile_parser/mapfile_parser.pyi,sha256=hXSuhmUFEqP6tgNXPsB2HwN-LlOq_r2i4n6_GN6R3js,12149
|
21
|
+
mapfile_parser/mapfile_rs.py,sha256=7xLjYmXZ-o6FKy5I40U-9mc6wRY413zgW8fGSFvz278,4199
|
22
|
+
mapfile_parser/progress_stats.py,sha256=yHA0u1-5-RPEl5bBMM1kxUdp0hlJWsp8S97J8LfOaNc,2604
|
23
|
+
mapfile_parser/progress_stats_rs.py,sha256=5b7uw84OQZUchPlNgosfosifOu9aa5tEz_sUdJGuywo,499
|
24
|
+
mapfile_parser/utils.py,sha256=TY1Xibb88dL8-2PwLVkmahhIYdBJk_6MLPQ3BUzrh70,1572
|
25
|
+
mapfile_parser-2.11.0.dist-info/RECORD,,
|
@@ -1,25 +0,0 @@
|
|
1
|
-
mapfile_parser-2.9.4.dist-info/METADATA,sha256=fZzUkQvB6y3Zha_IKA_PdIWndOw255GzMVxZTMBxmk8,5935
|
2
|
-
mapfile_parser-2.9.4.dist-info/WHEEL,sha256=tvMehAuwYswG9dMmwHb6RW7O-9AAAcnneXQ2akCAgrw,96
|
3
|
-
mapfile_parser-2.9.4.dist-info/licenses/LICENSE,sha256=8N8dS9WOtgJ0rkqNNOcazXKVkD2umzsKSHI0bd2HhG0,1094
|
4
|
-
mapfile_parser/__init__.py,sha256=E_Auvz0aTyah2osA_6O_R5eP3FX1Ygca1muCFAkcRe4,883
|
5
|
-
mapfile_parser/__main__.py,sha256=BxL4C_wPsFHjvdYkqmL7O3AmvVs9DG34S6Quu843tgs,2235
|
6
|
-
mapfile_parser/frontends/__init__.py,sha256=42Wut4H28j9TjPcADXjPtz5oJ-snrfCDcjotOvReo0k,529
|
7
|
-
mapfile_parser/frontends/bss_check.py,sha256=-CiP5UvlKKUGoUHQwuOoEYD9T9UDmkUxL7PpmlONih8,8524
|
8
|
-
mapfile_parser/frontends/first_diff.py,sha256=7aeVSwaJ9WuktU4lxZKJvKCttp0exnOGEMs6Pb1pFo4,9102
|
9
|
-
mapfile_parser/frontends/jsonify.py,sha256=Epb_uZO-sfZ8DjRgKT_whVrYfbtGFm3Lv9ajkRWXlyw,2724
|
10
|
-
mapfile_parser/frontends/objdiff_report.py,sha256=aLamem6P2LpfaeWA5TbEj4YMtMqKp7EdHXgvYrnzoYc,19458
|
11
|
-
mapfile_parser/frontends/pj64_syms.py,sha256=TeIApSG5MIeQS_f9yVcaL9jAPwu0tvtXrzO1OIKV4bY,2403
|
12
|
-
mapfile_parser/frontends/progress.py,sha256=g5sKRg0Lij0j9td_fefC33dqP4VB-mAy4jZNbODLUIw,4658
|
13
|
-
mapfile_parser/frontends/sym_info.py,sha256=TpyFLCCtzxRZVJoHjz8ObGVl36PVmZQkMM5_kER8vtQ,3630
|
14
|
-
mapfile_parser/frontends/symbol_sizes_csv.py,sha256=75qIZv7E1-DZgGuuWj3_XTaVKjF1gLNt5IBh-Ox6OT8,3219
|
15
|
-
mapfile_parser/frontends/upload_frogress.py,sha256=UNRw5VfWxHZtzr5zfRbZ6xi_ojTbZZ5uGV-R6Q5qGJE,5774
|
16
|
-
mapfile_parser/internals/__init__.py,sha256=lA5cxXEs9jtz1O5I68rtpEnz3LozDqNAOxV7GmyW2tg,340
|
17
|
-
mapfile_parser/internals/objdiff_report.py,sha256=KBNuqjMxXMXZllqLJd4V-wUFFynLK4qT2UIJgjXKysI,6401
|
18
|
-
mapfile_parser/mapfile.py,sha256=IgztKA_yORsCCvcjrMzX7NRWdExBj93m-2E3a60azzE,39913
|
19
|
-
mapfile_parser/mapfile_parser.cp310-win_amd64.pyd,sha256=D7r209kwlo8_UqV5pJUAhB5jErIBPjvCEluGBgCvMzY,2608128
|
20
|
-
mapfile_parser/mapfile_parser.pyi,sha256=K8bf1H1DXoa9cSIzjhJQTedNM-HtJnPRX1eVBu_26RM,11533
|
21
|
-
mapfile_parser/mapfile_rs.py,sha256=7xLjYmXZ-o6FKy5I40U-9mc6wRY413zgW8fGSFvz278,4199
|
22
|
-
mapfile_parser/progress_stats.py,sha256=yHA0u1-5-RPEl5bBMM1kxUdp0hlJWsp8S97J8LfOaNc,2604
|
23
|
-
mapfile_parser/progress_stats_rs.py,sha256=5b7uw84OQZUchPlNgosfosifOu9aa5tEz_sUdJGuywo,499
|
24
|
-
mapfile_parser/utils.py,sha256=TY1Xibb88dL8-2PwLVkmahhIYdBJk_6MLPQ3BUzrh70,1572
|
25
|
-
mapfile_parser-2.9.4.dist-info/RECORD,,
|
File without changes
|