@@ -118,10 +118,17 @@ def _from_core_block(cls, block: core.BNBasicBlockHandle) -> Optional['BasicBloc
118118
119119 def __repr__ (self ):
120120 arch = self .arch
121- if arch :
122- return f"<{ self .__class__ .__name__ } : { arch .name } @{ self .start :#x} -{ self .end :#x} >"
121+ if self .is_il :
122+ # IL indices are shown as decimal
123+ if arch :
124+ return f"<{ self .__class__ .__name__ } : { arch .name } @{ self .start } -{ self .end } >"
125+ else :
126+ return f"<{ self .__class__ .__name__ } : { self .start } -{ self .end } >"
123127 else :
124- return f"<{ self .__class__ .__name__ } : { self .start :#x} -{ self .end :#x} >"
128+ if arch :
129+ return f"<{ self .__class__ .__name__ } : { arch .name } @{ self .start :#x} -{ self .end :#x} >"
130+ else :
131+ return f"<{ self .__class__ .__name__ } : { self .start :#x} -{ self .end :#x} >"
125132
126133 def __len__ (self ):
127134 return int (core .BNGetBasicBlockLength (self .handle ))
@@ -430,65 +437,134 @@ def _make_blocks(self, blocks, count: int) -> List['BasicBlock']:
430437
431438 @property
432439 def dominators (self ) -> List ['BasicBlock' ]:
433- """List of dominators for this basic block (read-only)"""
440+ """
441+ List of dominators for this basic block (read-only).
442+
443+ A dominator of a basic block B is a block that must be executed before B can be executed.
444+ In other words, every path from the entry block to B must go through the dominator.
445+ This includes B itself - every block dominates itself. See
446+ :py:func:`BasicBlock.strict_dominators` for dominators that don't include B.
447+ """
434448 count = ctypes .c_ulonglong ()
435449 blocks = core .BNGetBasicBlockDominators (self .handle , count , False )
436450 return self ._make_blocks (blocks , count .value )
437451
438452 @property
439453 def post_dominators (self ) -> List ['BasicBlock' ]:
440- """List of dominators for this basic block (read-only)"""
454+ """
455+ List of post-dominators for this basic block (read-only)
456+
457+ A post-dominator of a basic block B is a block that must be executed after B is executed.
458+ In other words, every path from B to an exit block must go through the post-dominator.
459+ This includes B itself - every block post-dominates itself. See
460+ :py:func:`BasicBlock.strict_post_dominators` for post-dominators that don't include B.
461+ If B has outgoing edges that can lead to different exit blocks, then this will only include B.
462+ """
441463 count = ctypes .c_ulonglong ()
442464 blocks = core .BNGetBasicBlockDominators (self .handle , count , True )
443465 return self ._make_blocks (blocks , count .value )
444466
445467 @property
446468 def strict_dominators (self ) -> List ['BasicBlock' ]:
447- """List of strict dominators for this basic block (read-only)"""
469+ """
470+ List of strict dominators for this basic block (read-only)
471+
472+ A strict dominator of a basic block B is a dominator of B that is not B itself.
473+ See :py:func:`BasicBlock.dominators` for the definition of a dominator.
474+ """
448475 count = ctypes .c_ulonglong ()
449476 blocks = core .BNGetBasicBlockStrictDominators (self .handle , count , False )
450477 return self ._make_blocks (blocks , count .value )
451478
479+ @property
480+ def strict_post_dominators (self ) -> List ['BasicBlock' ]:
481+ """
482+ List of strict post-dominators for this basic block (read-only)
483+
484+ A strict post-dominator of a basic block B is a post-dominator of B that is not B itself.
485+ See :py:func:`BasicBlock.post_dominators` for the definition of a post-dominator.
486+ """
487+ count = ctypes .c_ulonglong ()
488+ blocks = core .BNGetBasicBlockStrictDominators (self .handle , count , True )
489+ return self ._make_blocks (blocks , count .value )
490+
452491 @property
453492 def immediate_dominator (self ) -> Optional ['BasicBlock' ]:
454- """Immediate dominator of this basic block (read-only)"""
493+ """
494+ Immediate dominator of this basic block (read-only)
495+
496+ The immediate dominator of a basic block B is the dominator closest to B in the control flow graph.
497+ In other words, among all dominators of B, it is the dominator that doesn't dominate any other
498+ dominator of B except itself. Each basic block except the entry block has a unique immediate dominator.
499+ """
455500 result = core .BNGetBasicBlockImmediateDominator (self .handle , False )
456501 if not result :
457502 return None
458503 return self ._create_instance (result )
459504
460505 @property
461506 def immediate_post_dominator (self ) -> Optional ['BasicBlock' ]:
462- """Immediate dominator of this basic block (read-only)"""
507+ """
508+ Immediate post-dominator of this basic block (read-only)
509+
510+ The immediate post-dominator of a basic block B is the post-dominator closest to B in the control flow graph.
511+ In other words, among all post-dominators of B, it is the post-dominator that doesn't post-dominate any other
512+ post-dominator of B except itself.
513+ If B has outgoing edges that can lead to different exit blocks, then this will not exist.
514+ """
463515 result = core .BNGetBasicBlockImmediateDominator (self .handle , True )
464516 if not result :
465517 return None
466518 return self ._create_instance (result )
467519
468520 @property
469521 def dominator_tree_children (self ) -> List ['BasicBlock' ]:
470- """List of child blocks in the dominator tree for this basic block (read-only)"""
522+ """
523+ List of child blocks in the dominator tree for this basic block (read-only)
524+
525+ The dominator tree children of a basic block B are the blocks dominated by B.
526+ See :py:func:`BasicBlock.dominators` for the definition of a dominator.
527+ """
471528 count = ctypes .c_ulonglong ()
472529 blocks = core .BNGetBasicBlockDominatorTreeChildren (self .handle , count , False )
473530 return self ._make_blocks (blocks , count .value )
474531
475532 @property
476533 def post_dominator_tree_children (self ) -> List ['BasicBlock' ]:
477- """List of child blocks in the post dominator tree for this basic block (read-only)"""
534+ """
535+ List of child blocks in the post-dominator tree for this basic block (read-only)
536+
537+ The post-dominator tree children of a basic block B are the blocks post-dominated by B.
538+ See :py:func:`BasicBlock.post_dominators` for the definition of a post-dominator.
539+ """
478540 count = ctypes .c_ulonglong ()
479541 blocks = core .BNGetBasicBlockDominatorTreeChildren (self .handle , count , True )
480542 return self ._make_blocks (blocks , count .value )
481543
482544 @property
483545 def dominance_frontier (self ) -> List ['BasicBlock' ]:
484- """Dominance frontier for this basic block (read-only)"""
546+ """
547+ Dominance frontier for this basic block (read-only)
548+
549+ The dominance frontier of a basic block B is the set of blocks that are not strictly dominated by B,
550+ but are immediately control-dependent on B. In other words, it contains the blocks where B's dominance
551+ "stops" - the blocks that have at least one predecessor not dominated by B, while having another
552+ predecessor that is dominated by B.
553+ """
485554 count = ctypes .c_ulonglong ()
486555 blocks = core .BNGetBasicBlockDominanceFrontier (self .handle , count , False )
487556 return self ._make_blocks (blocks , count .value )
488557
489558 @property
490559 def post_dominance_frontier (self ) -> List ['BasicBlock' ]:
491- """Post dominance frontier for this basic block (read-only)"""
560+ """
561+ Post-dominance frontier for this basic block (read-only)
562+
563+ The post-dominance frontier of a basic block B is the set of blocks that are not strictly post-dominated
564+ by B, but have at least one successor that is post-dominated by B. In other words, it contains the blocks
565+ where B's post-dominance "stops" - the blocks that have at least one successor not post-dominated by B,
566+ while having another successor that is post-dominated by B.
567+ """
492568 count = ctypes .c_ulonglong ()
493569 blocks = core .BNGetBasicBlockDominanceFrontier (self .handle , count , True )
494570 return self ._make_blocks (blocks , count .value )
0 commit comments