-
Notifications
You must be signed in to change notification settings - Fork 278
/
Copy pathreconstruct_traceback.py
executable file
·72 lines (60 loc) · 2.46 KB
/
reconstruct_traceback.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python3
import argparse
import json
import re
import sys
from starkware.cairo.lang.compiler.program import Program
from starkware.cairo.lang.version import __version__
def reconstruct_traceback(program: Program, traceback_txt: str):
def location_replacer(match: re.Match, keep_original_line: bool) -> str:
assert program.debug_info is not None, "Missing debug information in the compiled program."
pc = int(match.group("pc"))
instruction_location = program.debug_info.instruction_locations.get(pc)
if instruction_location is None:
# Return the text unchanged.
return match.group(0)
res = instruction_location.inst.to_string_with_content(
match.group(0) if keep_original_line else ""
)
return res
traceback_txt = re.sub(
r"Unknown location \(pc=0:(?P<pc>\d+)\)",
lambda match: location_replacer(match=match, keep_original_line=False),
traceback_txt,
)
traceback_txt = re.sub(
r"Error at pc=0:(?P<pc>\d+):",
lambda match: location_replacer(match=match, keep_original_line=True),
traceback_txt,
)
return traceback_txt
def main():
parser = argparse.ArgumentParser(
description="A tool to reconstruct Cairo traceback given a compiled program with debug "
"information."
)
parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
parser.add_argument("--program", type=str, help="A path to the Cairo program.")
parser.add_argument("--contract", type=str, help="A path to the StarkNet contract.")
parser.add_argument(
"--traceback",
type=str,
required=True,
help="A path to the traceback file with the missing location information. "
'Use "-" to read the traceback from stdin.',
)
args = parser.parse_args()
assert (0 if args.program is None else 1) + (
0 if args.contract is None else 1
) == 1, "Exactly one of --program, --contract must be specified."
if args.program is not None:
program_json = json.load(open(args.program))
else:
assert args.contract is not None
program_json = json.load(open(args.contract))["program"]
program = Program.load(data=program_json)
traceback = (open(args.traceback) if args.traceback != "-" else sys.stdin).read()
print(reconstruct_traceback(program, traceback))
return 0
if __name__ == "__main__":
sys.exit(main())