Skip to content

Commit 6269091

Browse files
committed
CLI: Support listing/clearing breakpoints in volshell
1 parent 5bb4cd9 commit 6269091

File tree

1 file changed

+42
-2
lines changed

1 file changed

+42
-2
lines changed

volatility3/cli/volshell/generic.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ def help(self, *args):
187187
def construct_locals(self) -> List[Tuple[List[str], Any]]:
188188
"""Returns a listing of the functions to be added to the environment."""
189189
return [
190+
(["bc", "breakpoint_clear"], self.breakpoint_clear),
191+
(["bl", "breakpoint_list"], self.breakpoint_list),
190192
(["bp", "breakpoint"], self.breakpoint),
191193
(["dt", "display_type"], self.display_type),
192194
(["db", "display_bytes"], self.display_bytes),
@@ -827,22 +829,60 @@ def wrapped_read(offset: int, length: int, pad: bool = False) -> bytes:
827829
original_read = getattr(wrapped_read, "original_read")
828830
for breakpoint in getattr(wrapped_read, "breakpoints"):
829831
if (offset <= breakpoint) and (breakpoint < offset + length):
832+
print(
833+
"Hit breakpoint, entering python debugger. To continue running without the debugger use the command continue"
834+
)
830835
import pdb
831836

832837
pdb.set_trace()
833-
print("Hit breakpoint")
838+
_ = "First statement after the breakpoint, use u(p), d(own) and list to navigate through the execution frames"
834839
return original_read(offset, length, pad)
835840

836841
setattr(wrapped_read, "breakpoints", set())
837842
setattr(wrapped_read, "original_read", layer.read)
838843
setattr(layer, "read", wrapped_read)
839844

840845
# Add the new breakpoint
841-
print(f"Setting breakpoint {address:x} on {layer.name}")
846+
print(f"Setting breakpoint {address:#x} on {layer.name}")
842847
breakpoints = getattr(layer.read, "breakpoints")
843848
breakpoints.add(address)
844849
setattr(layer.read, "breakpoints", breakpoints)
845850

851+
def breakpoint_list(self, layer_names: Optional[List[str]] = None):
852+
"""List available breakpoints for a set of layers"""
853+
if not layer_names:
854+
layer_names = [layer_name for layer_name in self.context.layers]
855+
856+
print("Listing breakpoints:")
857+
for layer_name in layer_names:
858+
print(f" {layer_name}")
859+
layer = self.context.layers.get(layer_name, None)
860+
if layer and hasattr(layer.read, "breakpoints"):
861+
for breakpoint in layer.read.breakpoints:
862+
print(f" {breakpoint:#x}")
863+
864+
def breakpoint_clear(
865+
self, offset: Optional[int] = None, layer_name: Optional[str] = None
866+
):
867+
"""Clears a offset breakpoint on a layer (or all breakpoints if offset or layer not specified)
868+
869+
Args:
870+
offset: Address of the breakpoint to clear (or all if None)
871+
layer_name: Layer to clear breakpoints from (or all if None)
872+
"""
873+
print("Clearing breakpoints:")
874+
for candidate_layer_name in self.context.layers:
875+
candidate_layer = self.context.layers[candidate_layer_name]
876+
if layer_name is None or layer_name == candidate_layer_name:
877+
print(f" {candidate_layer_name}")
878+
if hasattr(candidate_layer.read, "breakpoints"):
879+
breakpoints_to_remove = set()
880+
for breakpoint in candidate_layer.read.breakpoints:
881+
if offset is None or offset == breakpoint:
882+
print(f" clearing {breakpoint:#x}")
883+
breakpoints_to_remove.add(breakpoint)
884+
candidate_layer.read.breakpoints -= breakpoints_to_remove
885+
846886

847887
class NullFileHandler(io.BytesIO, interfaces.plugins.FileHandlerInterface):
848888
"""Null FileHandler that swallows files whole without consuming memory"""

0 commit comments

Comments
 (0)