You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GDB中于断点后添加软件观察点以调试C结构体损坏问题

Solution: Using Software Watchpoints in Your GDB Python Script

Got it, let's tackle this problem. When hardware watchpoints run out (most CPUs only support 2-4 of them), switching to software watchpoints is exactly the right move—they don't have the same limit, even if they do slow things down a bit (totally worth it for tracking down memory corruption!).

Here's how to modify your existing script to use software watchpoints instead:

Step 1: Adjust Allocation Breakpoint to Create Software Watchpoints

In your BreakpointAlloc class's stop() method, explicitly create a software watchpoint that monitors the entire memory range of the allocated struct. You'll need to target the full struct size (not just a single field) to catch any corruption across the instance.

Step 2: Track Watchpoints for Cleanup

Keep using your dictionary to map struct addresses to their watchpoint objects—this makes it trivial to look up and delete the watchpoint when the struct is freed.

Full Modified Script Example

Let's assume your struct is named MyStruct, your allocation function is my_struct_alloc() (returns a pointer to the new instance), and your free function is my_struct_free() (takes the struct pointer as an argument). Here's the adjusted script:

import gdb

# Track watchpoints: key = struct address (integer), value = watchpoint object
watchpoints = {}

class BreakpointAlloc(gdb.Breakpoint):
    def __init__(self):
        # Set breakpoint at the end of your allocation function (right before return)
        super().__init__("my_struct_alloc", gdb.BP_BREAKPOINT)
        self.silent = True  # Avoid spamming the console with breakpoint hits

    def stop(self):
        # Get the newly allocated struct pointer (return value of alloc function)
        # Use $eax for 32-bit systems instead of $rax
        struct_ptr = gdb.parse_and_eval("$rax")
        struct_addr = int(struct_ptr)
        if struct_addr == 0:
            return False  # Skip null allocations

        # Get the size of MyStruct to monitor the entire instance
        struct_size = int(gdb.parse_and_eval("sizeof(MyStruct)"))

        # Create a software watchpoint for the full struct memory range
        wp = gdb.Breakpoint(f"*{struct_addr}", gdb.BP_WATCHPOINT, type=gdb.WP_SOFTWARE)
        wp.watch_write = True  # Monitor writes to catch corruption
        wp.watch_read = False  # Disable read monitoring to save performance
        wp.silent = True

        # Store the watchpoint for later cleanup
        watchpoints[struct_addr] = wp
        print(f"Set software watchpoint for MyStruct at 0x{struct_addr:x}")
        return False  # Let the program continue execution

class BreakpointFree(gdb.Breakpoint):
    def __init__(self):
        # Set breakpoint at the start of your free function
        super().__init__("my_struct_free", gdb.BP_BREAKPOINT)
        self.silent = True

    def stop(self):
        # Get the struct pointer being freed (first function argument)
        # Use $ebx for 32-bit systems instead of $rdi (depends on calling convention)
        struct_ptr = gdb.parse_and_eval("$rdi")
        struct_addr = int(struct_ptr)
        if struct_addr == 0 or struct_addr not in watchpoints:
            return False  # Skip null or untracked instances

        # Remove and clean up the watchpoint
        wp = watchpoints.pop(struct_addr)
        wp.delete()
        print(f"Removed watchpoint for MyStruct at 0x{struct_addr:x}")
        return False  # Let the program continue

# Register breakpoints when the script loads
BreakpointAlloc()
BreakpointFree()
print("Loaded allocation/free watchpoint manager (software watchpoints enabled)")

Key Adjustments & Notes

  • Calling Convention: Double-check the register used to get function arguments/return values. For x86_64 System V (most Linux/macOS), return values live in $rax and first arguments in $rdi. For 32-bit x86, use $eax for returns and either stack variables or $ebx (depending on your compiler's convention). Alternatively, use gdb.frame().read_var("param_name") if you know the exact parameter name in your free function.
  • Watchpoint Behavior: The example enables write-only monitoring to save performance—if you need to track reads too, set wp.watch_read = True.
  • Performance Tradeoff: Software watchpoints work by having GDB periodically check the memory region, so your program will run slower. This is a necessary tradeoff for catching corruption when hardware watchpoints are exhausted.
  • Struct Size: Using gdb.parse_and_eval("sizeof(MyStruct)") ensures you always get the correct size, even if your struct definition changes later.

To use this script, load it into GDB with source your_script.py. It will automatically set software watchpoints for every new MyStruct instance on allocation, and remove them right before the instance is freed. Any write to a struct's memory will trigger the watchpoint, pausing the program so you can inspect what's causing the corruption.

内容的提问来源于stack exchange,提问作者FelipeFR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:14:50