I wrote a gdb script that prints assembly instructions between two breakpoints in order of execution, it also prints the value of registers used in that line. I found it a lot easier to review assembly like this vs having to jump around and execute commands all the time, so I wanted to share it with all of you :)
# start breakpoint
br #UserApp_main_f03bf86f79d121cbfd774dec4a65912e99f5f17c33852bbc45e81916e62b53b
run
# start python script
python
# end "breakpoint"
STOP_INSTRUCTION_ADDR = 0x0000555555579cfc
import re
old_fun = ""
with open("gdb_py_output.txt", "w") as output_file:
def print_register(register_name):
reg_value_parts = gdb.execute(f"info register {register_name}", to_string=True).strip().split()
reg_value_decimal = int(reg_value_parts[2])
if -10 < reg_value_decimal < 10:
output_file.write(f" |{reg_value_parts[0]} = {reg_value_decimal}\n")
else:
output_file.write(f" |{reg_value_parts[0]} = {reg_value_parts[1]} ({reg_value_decimal})\n")
while True:
asm_instruction = gdb.execute("x/i $pc", to_string=True).split(':')[-1].strip()
frame = gdb.selected_frame()
instruction_address = frame.pc()
fun_name = frame.function().name
# cut off alphanum garbage
clean_fun = '_'.join(fun_name.split('_')[:-1])
if clean_fun == old_fun:
clean_fun = ""
else:
output_file.write("\n----------\n")
old_fun = clean_fun
args = asm_instruction.split(',')
if len(args) > 1:
non_target_args = " ".join(args[1::])
for match in re.finditer(r'\b(x[0-9]+|w[0-9]+)\b', non_target_args):
print_register(match.group())
output_file.write(f"{instruction_address:#x}: {clean_fun:<23} {asm_instruction}\n")
#output_file.write(f"{clean_fun:<23} {asm_instruction}\n")
gdb.execute("stepi", to_string=True)
# Regex to extract the target register from the assembly instruction.
# This regex assumes ARM architecture based on the provided instructions.
reg_match = re.search(r'\b(x[0-9]+|w[0-9]+)\b', asm_instruction)
if reg_match:
target_reg = reg_match.group(0)
# Count the number of arguments to ensure there are two or more.
num_args = len(asm_instruction.split(','))
if num_args >= 2:
print_register(target_reg)
output_file.write("\n")
if gdb.selected_frame().pc() == STOP_INSTRUCTION_ADDR:
break
# end python script
end
quit
Example output:
----------
|x0 = 3
0x555555579c7c: #UserApp_diffSelf mov x4, x0
|x4 = 3
|x1 = 0
0x555555579c80: mov x6, x1
|x6 = 0
|x4 = 3
0x555555579c84: mov x0, x4
|x0 = 3
|x6 = 0
0x555555579c88: mov x2, x6
|x2 = 0
0x555555579c8c: b 0x555555579eb0 <Num_sub_ec2bd03bf86b935fa34d71ad7ebb49f1f10f87d343e521511d8f9e6625620cd>
----------
0x555555579eb0: Num_sub sub sp, sp, #0x20
0x555555579eb4: str x30, [sp, #16]
|x30 = 0x555555579e18 (93824992386584)
|x1 = 0
0x555555579eb8: mov x8, x1
|x8 = 0
|x0 = 3
|x2 = 0
0x555555579ebc: subs x1, x0, x2
|x1 = 3
|x8 = 0
|x3 = 0
0x555555579ec0: sbcs x0, x8, x3
|x0 = 0
0x555555579ec4: mov w8, wzr
|w8 = 0
|w8 = 0
0x555555579ec8: csinc w8, w8, wzr, cs // cs = hs, nlast
|w8 = 0
0x555555579ecc: str x1, [sp]
|x1 = 3
whoa, super cool!
Super cool, but also really sad that it is so much extra effort to give a better interface to gdb. I almost want to use windows to try things like remmedybg that seem to have figured out how to do nice debugger interfaces (though that still may not work well with our super limited debug info)
remmedybg does look nice! Seems like it gets all the important stuff right
Last updated: Jul 06 2025 at 12:14 UTC