Stream: compiler development

Topic: gdb script


view this post on Zulip Anton (Mar 02 2024 at 15:56):

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

view this post on Zulip Richard Feldman (Mar 02 2024 at 16:27):

whoa, super cool!

view this post on Zulip Brendan Hansknecht (Mar 02 2024 at 16:30):

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)

view this post on Zulip Anton (Mar 02 2024 at 17:02):

remmedybg does look nice! Seems like it gets all the important stuff right


Last updated: Jul 06 2025 at 12:14 UTC