|
36 | 36 | Any, cast, Dict, List, NoReturn, Optional, Set, Tuple, TYPE_CHECKING) |
37 | 37 |
|
38 | 38 | from chb.app.AppAccess import AppAccess |
| 39 | +from chb.app.Function import Function |
39 | 40 |
|
40 | 41 | from chb.ast.AbstractSyntaxTree import AbstractSyntaxTree |
41 | 42 | from chb.ast.ASTApplicationInterface import ASTApplicationInterface |
|
62 | 63 | from chb.userdata.UserHints import UserHints |
63 | 64 |
|
64 | 65 | import chb.util.dotutil as UD |
| 66 | +from chb.util.DotGraph import DotGraph |
65 | 67 | import chb.util.fileutil as UF |
66 | 68 | import chb.util.graphutil as UG |
67 | 69 | from chb.util.loggingutil import chklogger, LogLevel |
@@ -150,6 +152,7 @@ def buildast(args: argparse.Namespace) -> NoReturn: |
150 | 152 | hide_annotations: bool = args.hide_annotations |
151 | 153 | show_reachingdefs: str = args.show_reachingdefs |
152 | 154 | output_reachingdefs: str = args.output_reachingdefs |
| 155 | + fileformat: str = args.format |
153 | 156 | verbose: bool = args.verbose |
154 | 157 | loglevel: str = args.loglevel |
155 | 158 | logfilename: Optional[str] = args.logfilename |
@@ -347,7 +350,7 @@ def buildast(args: argparse.Namespace) -> NoReturn: |
347 | 350 | # xdata records for all instructions in the function. Locations that |
348 | 351 | # have a common user are merged. Types are provided by lhs_types. |
349 | 352 | astinterface.introduce_ssa_variables( |
350 | | - f.rdef_locations(), f.register_lhs_types, f.lhs_names) |
| 353 | + f.rdef_location_partition(), f.register_lhs_types, f.lhs_names) |
351 | 354 |
|
352 | 355 | # Introduce stack variables for all stack buffers with types |
353 | 356 | astinterface.introduce_stack_variables( |
@@ -393,51 +396,14 @@ def buildast(args: argparse.Namespace) -> NoReturn: |
393 | 396 | UC.print_error("\nSpecify a file to save the reaching defs") |
394 | 397 | continue |
395 | 398 |
|
396 | | - rdefspec = show_reachingdefs.split(":") |
397 | | - if len(rdefspec) != 2: |
398 | | - UC.print_error( |
399 | | - "\nArgument to show_reachingdefs not recognized") |
400 | | - continue |
401 | | - |
402 | | - useloc = rdefspec[0] |
403 | | - register = rdefspec[1] |
404 | | - |
405 | | - if not f.has_instruction(useloc): |
406 | | - UC.print_status_update("Useloc: " + useloc + " not found") |
407 | | - continue |
408 | | - |
409 | | - tgtinstr = f.instruction(useloc) |
410 | | - |
411 | | - if not register in f.rdef_locations(): |
| 399 | + register = show_reachingdefs |
| 400 | + if not register in f.rdef_location_partition(): |
412 | 401 | UC.print_status_update( |
413 | 402 | "Register " + register + " not found in rdeflocations") |
414 | 403 | continue |
415 | 404 |
|
416 | | - cblock = f.containing_block(useloc) |
417 | | - graph = UG.DirectedGraph(list(f.cfg.blocks.keys()), f.cfg.edges) |
418 | | - rdefs = tgtinstr.reaching_definitions(register) |
419 | | - dotpaths: List[DotRdefPath] = [] |
420 | | - graph.find_paths(f.faddr, cblock) |
421 | | - for (i, p) in enumerate( |
422 | | - sorted(graph.get_paths(), key=lambda p: len(p))): |
423 | | - cfgpath = DotRdefPath( |
424 | | - "path" + str(i), |
425 | | - f, |
426 | | - astinterface, |
427 | | - p, |
428 | | - subgraph=True, |
429 | | - nodeprefix = str(i) +":", |
430 | | - rdefinstrs = rdefs) |
431 | | - dotpaths.append(cfgpath) |
432 | | - |
433 | | - pdffilename = UD.print_dot_subgraphs( |
434 | | - app.path, |
435 | | - "paths", |
436 | | - output_reachingdefs, |
437 | | - "pdf", |
438 | | - [dotcfg.build() for dotcfg in dotpaths]) |
439 | | - |
440 | | - UC.print_status_update("Printed " + pdffilename) |
| 405 | + print_reachingdefs( |
| 406 | + app, astinterface, output_reachingdefs, fileformat, f, register) |
441 | 407 |
|
442 | 408 | else: |
443 | 409 | UC.print_error("Unable to find function " + faddr) |
@@ -469,6 +435,102 @@ def buildast(args: argparse.Namespace) -> NoReturn: |
469 | 435 | exit(0) |
470 | 436 |
|
471 | 437 |
|
| 438 | +def print_reachingdefs( |
| 439 | + app: AppAccess, |
| 440 | + astinterface: ASTInterface, |
| 441 | + filename: str, |
| 442 | + fileformat: str, |
| 443 | + f: Function, |
| 444 | + register: str) -> None: |
| 445 | + dotpaths: List[Tuple[DotRdefPath, str, str]] = [] |
| 446 | + regspill = register + "_spill" |
| 447 | + for (iaddr, instr) in f.instructions.items(): |
| 448 | + if register in instr.rdef_locations(): |
| 449 | + register_o = app.bdictionary.register_by_name(register) |
| 450 | + cblock = f.containing_block(iaddr) |
| 451 | + rdefs = instr.reaching_definitions(register) |
| 452 | + for rdef in rdefs: |
| 453 | + if rdef == "init": |
| 454 | + if regspill in instr.annotation: |
| 455 | + continue |
| 456 | + rdblock = f.faddr |
| 457 | + graph = UG.DirectedGraph(list(f.cfg.blocks.keys()), f.cfg.edges) |
| 458 | + graph.find_paths(rdblock, cblock) |
| 459 | + for (i, p) in enumerate( |
| 460 | + sorted(graph.get_paths(), key=lambda p: len(p))): |
| 461 | + p = ["init"] + p |
| 462 | + cfgpath = DotRdefPath( |
| 463 | + "path_" + str(rdef) + "_" + str(iaddr) + "_" + str(i), |
| 464 | + f, |
| 465 | + astinterface, |
| 466 | + p, |
| 467 | + register_o, |
| 468 | + subgraph=True, |
| 469 | + nodeprefix = str(iaddr) + str(rdef) + str(i) + ":", |
| 470 | + rdefinstrs = rdefs, |
| 471 | + useinstrs=[iaddr]) |
| 472 | + dotpaths.append((cfgpath, rdef, iaddr)) |
| 473 | + else: |
| 474 | + rdblock = f.containing_block(rdef) |
| 475 | + graph = UG.DirectedGraph(list(f.cfg.blocks.keys()), f.cfg.edges) |
| 476 | + graph.find_paths(rdblock, cblock) |
| 477 | + for (i, p) in enumerate( |
| 478 | + sorted(graph.get_paths(), key=lambda p: len(p))): |
| 479 | + cfgpath = DotRdefPath( |
| 480 | + "path_" + str(rdef) + "_" + str(iaddr) + "_" + str(i), |
| 481 | + f, |
| 482 | + astinterface, |
| 483 | + p, |
| 484 | + subgraph=True, |
| 485 | + nodeprefix = str(iaddr) + str(rdef) + str(i) + ":", |
| 486 | + rdefinstrs = rdefs, |
| 487 | + useinstrs=[iaddr]) |
| 488 | + dotpaths.append((cfgpath, rdef, iaddr)) |
| 489 | + |
| 490 | + possibly_spurious_rdefs: List[Tuple[str, str]] = [] |
| 491 | + legitimate_rdefs: List[Tuple[str, str]] = [] |
| 492 | + dotgraphs: List[Tuple[DotRdefPath, DotGraph, str, str]] = [] |
| 493 | + |
| 494 | + for (dotcfg, rdef, iaddr) in dotpaths: |
| 495 | + dotgr = dotcfg.build() |
| 496 | + if dotgr is not None: |
| 497 | + if dotcfg.is_potentially_spurious(): |
| 498 | + possibly_spurious_rdefs.append((rdef, iaddr)) |
| 499 | + else: |
| 500 | + legitimate_rdefs.append((rdef, iaddr)) |
| 501 | + dotgraphs.append((dotcfg, dotgr, rdef, iaddr)) |
| 502 | + |
| 503 | + printgraphs: List[DotGraph] = [] |
| 504 | + for (dotcfg, dg, rdef, iaddr) in dotgraphs: |
| 505 | + if dotcfg.is_potentially_spurious(): |
| 506 | + if (rdef, iaddr) in legitimate_rdefs: |
| 507 | + pass |
| 508 | + else: |
| 509 | + printgraphs.append(dg) |
| 510 | + else: |
| 511 | + printgraphs.append(dg) |
| 512 | + |
| 513 | + pdffilename = UD.print_dot_subgraphs( |
| 514 | + app.path, |
| 515 | + "paths", |
| 516 | + filename, |
| 517 | + fileformat, |
| 518 | + printgraphs) |
| 519 | + |
| 520 | + UC.print_status_update("Printed " + pdffilename) |
| 521 | + if len(possibly_spurious_rdefs) > 0: |
| 522 | + print("Possibly spurious reachingdefs to be removed: ") |
| 523 | + print("~" * 80) |
| 524 | + for (rdef, iaddr) in set(possibly_spurious_rdefs): |
| 525 | + if not (rdef, iaddr) in legitimate_rdefs: |
| 526 | + print(" rdefloc: " + rdef + "; useloc: " + iaddr) |
| 527 | + print("~" * 80) |
| 528 | + |
| 529 | + # print("\nLegitimate reaching defs:") |
| 530 | + # for (rdef, iaddr) in set(legitimate_rdefs): |
| 531 | + # print(" rdefloc: " + rdef + "; useloc: " + iaddr) |
| 532 | + |
| 533 | + |
472 | 534 | def showast(args: argparse.Namespace) -> NoReturn: |
473 | 535 | print("still under construction ..") |
474 | 536 | exit(1) |
|
0 commit comments