1
- #!/usr/bin/env python
1
+ #!/usr/bin/env python3
2
2
#===- lib/hwasan/scripts/hwasan_symbolize ----------------------------------===#
3
3
#
4
4
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -16,6 +16,8 @@ from __future__ import unicode_literals
16
16
17
17
import argparse
18
18
import glob
19
+ import html
20
+ import json
19
21
import mmap
20
22
import os
21
23
import re
@@ -106,10 +108,40 @@ class Symbolizer:
106
108
self .__log = False
107
109
self .__warnings = set ()
108
110
self .__index = {}
111
+ self .__link_prefixes = []
112
+ self .__html = False
113
+
114
+ def enable_html (self , enable ):
115
+ self .__html = enable
109
116
110
117
def enable_logging (self , enable ):
111
118
self .__log = enable
112
119
120
+ def maybe_escape (self , text ):
121
+ if self .__html :
122
+ # We need to manually use for leading spaces, html.escape does
123
+ # not do that, and HTML ignores them.
124
+ spaces = 0
125
+ for i , c in enumerate (text ):
126
+ spaces = i
127
+ if c != ' ' :
128
+ break
129
+ text = text [spaces :]
130
+ return spaces * ' ' + html .escape (text )
131
+ return text
132
+
133
+ def print (self , line , escape = True ):
134
+ if escape :
135
+ line = self .maybe_escape (line )
136
+ if self .__html :
137
+ line += '<br/>'
138
+ print (line )
139
+
140
+ def read_linkify (self , filename ):
141
+ with open (filename , 'r' ) as fd :
142
+ data = json .load (fd )
143
+ self .__link_prefixes = [(e ["prefix" ], e ["link" ]) for e in data ]
144
+
113
145
def __open_pipe (self ):
114
146
if not self .__pipe :
115
147
opt = {}
@@ -207,6 +239,26 @@ class Symbolizer:
207
239
except Symbolizer .__EOF :
208
240
pass
209
241
242
+ def maybe_linkify (self , file_line ):
243
+ if not self .__html or not self .__link_prefixes :
244
+ return file_line
245
+ filename , line_col = file_line .split (':' , 1 )
246
+ if not line_col :
247
+ line = '0' # simplify the link generation
248
+ else :
249
+ line = line_col .split (':' )[0 ]
250
+ longest_prefix = max ((
251
+ (prefix , link ) for prefix , link in self .__link_prefixes
252
+ if filename .startswith (prefix )),
253
+ key = lambda x : len (x [0 ]), default = None )
254
+ if longest_prefix is None :
255
+ return file_line
256
+ else :
257
+ prefix , link = longest_prefix
258
+ return '<a href="{}">{}</a>' .format (
259
+ html .escape (link .format (file = filename [len (prefix ):], line = line ,
260
+ file_line = file_line , prefix = prefix )), file_line )
261
+
210
262
def build_index (self ):
211
263
for p in self .__binary_prefixes :
212
264
for dname , _ , fnames in os .walk (p ):
@@ -229,16 +281,22 @@ def symbolize_line(line, symbolizer_path):
229
281
frames = list (symbolizer .iter_call_stack (binary , buildid , addr ))
230
282
231
283
if len (frames ) > 0 :
232
- print ("%s#%s%s%s in %s" % (match .group (1 ), match .group (2 ),
233
- match .group (3 ), frames [0 ][0 ], frames [0 ][1 ]))
284
+ symbolizer .print (
285
+ symbolizer .maybe_escape (
286
+ "%s#%s%s%s in " % (match .group (1 ), match .group (2 ), match .group (3 ),
287
+ frames [0 ][0 ])
288
+ ) + symbolizer .maybe_linkify (frames [0 ][1 ]),
289
+ escape = False )
234
290
for i in range (1 , len (frames )):
235
291
space1 = ' ' * match .end (1 )
236
292
space2 = ' ' * (match .start (4 ) - match .end (1 ) - 2 )
237
- print ("%s->%s%s in %s" % (space1 , space2 , frames [i ][0 ], frames [i ][1 ]))
293
+ symbolizer .print (
294
+ symbolizer .maybe_escape ("%s->%s%s in " % (space1 , space2 , frames [i ][0 ]))
295
+ + symbolizer .maybe_linkify (frames [i ][1 ]), escape = False )
238
296
else :
239
- print (line .rstrip ())
297
+ symbolizer . print (line .rstrip ())
240
298
else :
241
- print (line .rstrip ())
299
+ symbolizer . print (line .rstrip ())
242
300
243
301
def save_access_address (line ):
244
302
global last_access_address , last_access_tag
@@ -280,10 +338,10 @@ def process_stack_history(line, symbolizer, ignore_tags=False):
280
338
tag_offset = local [5 ]
281
339
if not ignore_tags and (tag_offset is None or base_tag ^ tag_offset != last_access_tag ):
282
340
continue
283
- print ('' )
284
- print ('Potentially referenced stack object:' )
285
- print (' %d bytes inside variable "%s" in stack frame of function "%s"' % (obj_offset , local [2 ], local [0 ]))
286
- print (' at %s' % (local [1 ],))
341
+ symbolizer . print ('' )
342
+ symbolizer . print ('Potentially referenced stack object:' )
343
+ symbolizer . print (' %d bytes inside variable "%s" in stack frame of function "%s"' % (obj_offset , local [2 ], local [0 ]))
344
+ symbolizer . print (' at %s' % (local [1 ],))
287
345
return True
288
346
return False
289
347
@@ -295,6 +353,8 @@ parser.add_argument('--symbols', action='append')
295
353
parser .add_argument ('--source' , action = 'append' )
296
354
parser .add_argument ('--index' , action = 'store_true' )
297
355
parser .add_argument ('--symbolizer' )
356
+ parser .add_argument ('--linkify' , type = str )
357
+ parser .add_argument ('--html' , action = 'store_true' )
298
358
parser .add_argument ('args' , nargs = argparse .REMAINDER )
299
359
args = parser .parse_args ()
300
360
@@ -380,10 +440,17 @@ if args.v:
380
440
print ()
381
441
382
442
symbolizer = Symbolizer (symbolizer_path , binary_prefixes , paths_to_cut )
443
+ symbolizer .enable_html (args .html )
383
444
symbolizer .enable_logging (args .d )
384
445
if args .index :
385
446
symbolizer .build_index ()
386
447
448
+ if args .linkify :
449
+ if not args .html :
450
+ print ('Need --html to --linkify' , file = sys .stderr )
451
+ sys .exit (1 )
452
+ symbolizer .read_linkify (args .linkify )
453
+
387
454
for line in sys .stdin :
388
455
if sys .version_info .major < 3 :
389
456
line = line .decode ('utf-8' )
0 commit comments