Skip to content

Commit 6839391

Browse files
committed
bt: add indent argument
This allows the bt() function to be used within other helpers without breaking up the indentation of the output. Signed-off-by: Stephen Brennan <[email protected]>
1 parent 69c401b commit 6839391

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

drgn_tools/bt.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def bt_frames(
241241
return expand_frames(stack_trace)
242242

243243

244-
def print_task_header(task: drgn.Object) -> None:
244+
def print_task_header(task: drgn.Object, indent: int = 0) -> None:
245245
"""
246246
Given a task struct, print the header line of the stack trace.
247247
"""
@@ -253,8 +253,9 @@ def print_task_header(task: drgn.Object) -> None:
253253
cpu_note = ""
254254
if cpu_curr(task.prog_, cpu) == task:
255255
cpu_note = "!"
256+
pfx = " " * indent
256257
print(
257-
f"PID: {pid:<7d} TASK: {taskp:x} [{st}] CPU: {cpu}{cpu_note}"
258+
f"{pfx}PID: {pid:<7d} TASK: {taskp:x} [{st}] CPU: {cpu}{cpu_note}"
258259
f' COMMAND: "{comm}"'
259260
)
260261

@@ -265,6 +266,7 @@ def print_frames(
265266
show_vars: bool = False,
266267
show_absent: bool = False,
267268
start_idx: int = 0,
269+
indent: int = 0,
268270
) -> None:
269271
"""
270272
Print stack frames using the drgn-tools (crash-like) format
@@ -274,8 +276,10 @@ def print_frames(
274276
:param trace: The stack trace or list of frames to print
275277
:param show_vars: True if you want to show variables
276278
:param show_absent: True if you further want to show absent variables
277-
:start_idx: Where to start counting the frame indices from
279+
:param start_idx: Where to start counting the frame indices from
280+
:param indent: How many spaces to indent the output
278281
"""
282+
pfx = " " * indent
279283
for i, frame in enumerate(trace):
280284
sp = frame.sp # drgn 0.0.22
281285
intr = "!" if frame.interrupted else " "
@@ -285,7 +289,7 @@ def print_frames(
285289
pc = "???"
286290
name = frame_name(prog, frame)
287291
idx = start_idx + i
288-
out_line = f"{intr}#{idx:2d} [{sp:x}] {name} at {pc}"
292+
out_line = f"{pfx}{intr}#{idx:2d} [{sp:x}] {name} at {pc}"
289293
try:
290294
file_, line, col = frame.source()
291295
out_line += f" {file_}:{line}:{col}"
@@ -306,7 +310,8 @@ def print_frames(
306310
# This formats the registers in three columns.
307311
for j in range(0, len(regnames), 3):
308312
print(
309-
" " * 5
313+
pfx
314+
+ " " * 5
310315
+ " ".join(
311316
f"{reg.upper():>3s}: {registers[reg]:016x}"
312317
for reg in regnames[j : j + 3]
@@ -336,13 +341,14 @@ def print_frames(
336341
if val.absent_ and not show_absent:
337342
continue
338343
val_str = val.format_(dereference=False).replace("\n", "\n ")
339-
print(" " * 5 + f"{local} = {val_str}")
344+
print(pfx + " " * 5 + f"{local} = {val_str}")
340345

341346

342347
def print_traces(
343348
traces: t.List[drgn.StackTrace],
344349
show_vars: bool = False,
345350
show_absent: bool = False,
351+
indent: int = 0,
346352
) -> None:
347353
"""
348354
Given a list of stack traces, print them in the crash-like format
@@ -357,13 +363,15 @@ def print_traces(
357363
idx = 0
358364
prog = traces[0].prog
359365
for trace_idx, trace in enumerate(traces):
360-
print_frames(prog, trace, show_vars=show_vars, start_idx=idx)
366+
print_frames(
367+
prog, trace, show_vars=show_vars, start_idx=idx, indent=indent
368+
)
361369
idx += len(trace)
362370

363371
# Ok, this is the end of the loop over each frame within the trace.
364372
if trace_idx < len(traces) - 1:
365373
# But there is still another segment
366-
print(" -- continuing to previous stack -- ")
374+
print(" " * indent + " -- continuing to previous stack -- ")
367375

368376

369377
def bt(
@@ -373,6 +381,7 @@ def bt(
373381
show_vars: bool = False,
374382
show_absent: bool = False,
375383
retframes: bool = False,
384+
indent: int = 0,
376385
) -> t.Optional[t.List[drgn.StackFrame]]:
377386
"""
378387
Format a crash-like stack trace.
@@ -418,6 +427,7 @@ def bt(
418427
to include absent variables. Normally there's no reason to see this, since
419428
absent variables have no information.
420429
:param retframes: When true, returns a list of stack frames.
430+
:param indent: Number of spaces to indent all output lines
421431
:returns: A list of the stack frames which were printed. This can be useful
422432
for accessing the variables out of the frames interactively. If you're
423433
writing a script that needs to access frames, you may want to consider the
@@ -431,13 +441,15 @@ def bt(
431441
"struct task_struct *",
432442
):
433443
state = task_state_to_char(task)
434-
print_task_header(task)
444+
print_task_header(task, indent=indent)
435445
if state in ("Z", "X"):
436446
print(f"Task is in state: {state} - cannot unwind")
437447
return []
438448

439449
traces = expand_traces(task.prog_.stack_trace(task))
440-
print_traces(traces, show_vars=show_vars, show_absent=show_absent)
450+
print_traces(
451+
traces, show_vars=show_vars, show_absent=show_absent, indent=indent
452+
)
441453
frames = None
442454
if retframes:
443455
frames = []

0 commit comments

Comments
 (0)