3
3
import sys
4
4
from pathlib import Path
5
5
from subprocess import CalledProcessError
6
- from typing import Any , Dict , Final , Iterable , List , Optional
6
+ from typing import Any , Dict , Final , Iterable , List , Optional , Tuple
7
7
8
8
from pyk .cli_utils import run_process
9
9
from pyk .cterm import CTerm , remove_useless_constraints
17
17
from pyk .prelude .ml import mlAnd , mlEqualsTrue
18
18
from pyk .prelude .string import stringToken
19
19
20
- from .utils import add_include_arg
20
+ from .utils import add_include_arg , byte_offset_to_lines
21
21
22
22
_LOGGER : Final = logging .getLogger (__name__ )
23
23
27
27
28
28
class KEVM (KProve , KRun ):
29
29
30
- srcmap : Optional [Dict [int , str ]]
30
+ _srcmap_dir : Optional [Path ]
31
+ _contract_name : Optional [str ]
32
+ _contract_ids : Dict [int , str ]
33
+ _srcmaps : Dict [str , Dict [int , Tuple [int , int , int , str , int ]]]
34
+ _contract_srcs : Dict [str , List [str ]]
31
35
32
36
def __init__ (
33
37
self ,
@@ -37,7 +41,8 @@ def __init__(
37
41
profile : bool = False ,
38
42
kprove_command : str = 'kprove' ,
39
43
krun_command : str = 'krun' ,
40
- srcmap_file : Optional [Path ] = None ,
44
+ srcmap_dir : Optional [Path ] = None ,
45
+ contract_name : Optional [str ] = None ,
41
46
) -> None :
42
47
# I'm going for the simplest version here, we can change later if there is an advantage.
43
48
# https://stackoverflow.com/questions/9575409/calling-parent-class-init-with-multiple-inheritance-whats-the-right-way
@@ -52,10 +57,15 @@ def __init__(
52
57
)
53
58
KRun .__init__ (self , definition_dir , use_directory = use_directory , profile = profile , command = krun_command )
54
59
KEVM ._patch_symbol_table (self .symbol_table )
55
- self .srcmap = None
56
- if srcmap_file is not None and srcmap_file .exists ():
57
- with open (srcmap_file , 'r' ) as sm :
58
- self .srcmap = {int (k ): v for k , v in json .loads (sm .read ()).items ()}
60
+ self ._srcmap_dir = srcmap_dir
61
+ self ._contract_name = contract_name
62
+ self ._contract_ids = {}
63
+ self ._srcmaps = {}
64
+ self ._contract_srcs = {}
65
+ if self ._srcmap_dir is not None :
66
+ self ._contract_ids = {
67
+ int (k ): v for k , v in json .loads ((self ._srcmap_dir / 'contract_id_map.json' ).read_text ()).items ()
68
+ }
59
69
60
70
@staticmethod
61
71
def kompile (
@@ -196,12 +206,34 @@ def short_info(self, cterm: CTerm) -> List[str]:
196
206
_pc = get_cell (cterm .config , 'PC_CELL' )
197
207
pc_str = f'pc: { self .pretty_print (_pc )} '
198
208
ret_strs = [k_str , calldepth_str , statuscode_str , pc_str ]
199
- if type (_pc ) is KToken and self .srcmap is not None :
200
- pc = int (_pc .token )
201
- if pc in self .srcmap :
202
- ret_strs .append (f'srcmap: { self .srcmap [pc ]} ' )
203
- else :
204
- _LOGGER .warning (f'pc not found in srcmap: { pc } ' )
209
+ if self ._srcmap_dir is not None and self ._contract_name is not None and self ._contract_ids is not None :
210
+ if self ._contract_name not in self ._srcmaps :
211
+ _srcmap_pre = json .loads ((self ._srcmap_dir / f'{ self ._contract_name } .json' ).read_text ())
212
+ _srcmap : Dict [int , Tuple [int , int , int , str , int ]] = {}
213
+ for k , v in _srcmap_pre .items ():
214
+ s , l , f , j , m = v
215
+ assert type (s ) is int
216
+ assert type (l ) is int
217
+ assert type (f ) is int
218
+ assert type (j ) is str
219
+ assert type (m ) is int
220
+ _srcmap [int (k )] = (s , l , f , j , m )
221
+ self ._srcmaps [self ._contract_name ] = _srcmap
222
+ _srcmap = self ._srcmaps [self ._contract_name ]
223
+ if type (_pc ) is KToken :
224
+ pc = int (_pc .token )
225
+ if pc in _srcmap :
226
+ s , l , f , j , m = _srcmap [pc ]
227
+ if f in self ._contract_ids :
228
+ contract_file = self ._contract_ids [f ]
229
+ if contract_file not in self ._contract_srcs :
230
+ self ._contract_srcs [contract_file ] = (
231
+ (self ._srcmap_dir .parent .parent / contract_file ).read_text ().split ('\n ' )
232
+ )
233
+ _ , start , end = byte_offset_to_lines (self ._contract_srcs [contract_file ], s , l )
234
+ ret_strs .append (f'src: { self ._contract_ids [f ]} :{ start } :{ end } ' )
235
+ else :
236
+ _LOGGER .warning (f'pc not found in srcmap: { pc } ' )
205
237
return ret_strs
206
238
207
239
@staticmethod
@@ -467,7 +499,8 @@ def __init__(
467
499
main_file : Optional [Path ] = None ,
468
500
use_directory : Optional [Path ] = None ,
469
501
profile : bool = False ,
470
- srcmap_file : Optional [Path ] = None ,
502
+ srcmap_dir : Optional [Path ] = None ,
503
+ contract_name : Optional [str ] = None ,
471
504
) -> None :
472
505
# copied from KEVM class and adapted to inherit KPrint instead
473
506
KEVM .__init__ (
@@ -476,7 +509,8 @@ def __init__(
476
509
main_file = main_file ,
477
510
use_directory = use_directory ,
478
511
profile = profile ,
479
- srcmap_file = srcmap_file ,
512
+ srcmap_dir = srcmap_dir ,
513
+ contract_name = contract_name ,
480
514
)
481
515
Foundry ._patch_symbol_table (self .symbol_table )
482
516
0 commit comments