)]}'
{
  "commit": "ecf2f95de1e16b135085f8635b415ef169afbf68",
  "tree": "d4fa0f1d11c9cebc7707017bf1276ada4e1c07c2",
  "parents": [
    "6c5225a848988b61f0afdffe6e2e93dc7c10e88d"
  ],
  "author": {
    "name": "Simon Marchi",
    "email": "simon.marchi@polymtl.ca",
    "time": "Sat Jan 24 00:15:00 2026 -0500"
  },
  "committer": {
    "name": "Simon Marchi",
    "email": "simon.marchi@efficios.com",
    "time": "Thu Feb 05 13:37:39 2026 -0500"
  },
  "message": "gdb/amd-dbgapi: add basic watchpoint support\n\nAdd basic watchpoint support for the amd-dbgapi target.  This means\nplacing write watchpoints on globally addressable memory.  More\ncomplexity will come eventually to allow placing watchpoints on the\nvarious other address spaces, but that will require adding proper\nsupport for non-default address spaces first.\n\nImplementation\n--------------\n\nI think the implementation is not too surprising, just adding the\nrequired target methods.  But there are some things worthy of mention:\n\n - amd-dbgapi does not support read watchpoints.  If the core attempts\n   to insert a read (or access, which means read/write) watchpoint,\n   amd_dbgapi_target::insert_watchpoint returns an error.\n\n   If we silently let the beneath target (linux-nat) install the read\n   watchpoint, it would be potentially confusing.  Everything would look\n   fine to the user, but a read from the GPU would not be caught, so it\n   would look like the watchpoint doesn\u0027t work.\n\n   There is a loophole though: read watchpoints created before the\n   runtime is loaded (and therefore the amd-dbgapi target is pushed)\n   will still be inserted.  Only when execution stops, and the user\n   tries to resume again, will the check in\n   amd_dbgapi_target::insert_watchpoint be hit.\n\n   Another option would be to allow the host read watchpoint to go\n   through, but warn that the reads from the AMD GPU device will not be\n   watched.  We would need to be smart to avoid flooding the user with\n   warnings.  But I decided to upstream the current ROCgdb behavior\n   first, we can always change it later.\n\n - When the amd-dbgapi target gets pushed, we create amd-dbgapi\n   watchpoints for any existing hardware write watchpoint location.\n\n - When the core asks the target to insert a watchpoint, we ask the\n   target beneath to insert it first.  If the beneath target fails, we\n   return immediately with an error.\n\n - When the core asks to remove a watchpoint, we ask the target beneath\n   to to remove it first.  Even if it fails, we still try to remove the\n   amd-dbgapi watchpoint.\n\n - When stopping after a watchpoint hit while the \"precise-memory\"\n   setting is not enabled, it is possible for the wave to stop a few\n   instructions later than the instruction that made the write that\n   triggered the watchpoint.  We print a warning in that case, similar\n   to what we do when a memory violation happens while \"precis-memory\"\n   is disabled.\n\nTesting\n-------\n\n - Tests precise-memory-warning-watchpoint.exp and\n   watchpoint-at-end-of-shader.exp are more or less brought as-is from\n   downstream ROCgdb.  I modified precise-memory-warning-watchpoint.exp\n   to watch a hipMalloc\u0027ed region instead of a `__device__` global\n   variable.  The latter doesn\u0027t work upstream, because we don\u0027t yet\n   support the DWARF constructs that describe the variable location.\n\n - I added test watchpoint-basic.exp with various simple cases to\n   exercises different code paths added by this patch.\n\nDifferences from downstream ROCgdb\n----------------------------------\n\nWhile extracting this code from ROCgdb, I made a few minor but possibly\nsignificant (read: erroneous) changes.  Those should be reviewed\ncarefully.  I think that some code in ROCgdb was written at a time where\nthe amd-dbgapi target was always pushed at the very start of the\ninferior execution, so assumptions were different.\n\n - The value type for the `amd_dbgapi_inferior_info::watchpoint_map` map\n   is now a structure, instead of an std::pair, just because it makes\n   the code more readable.\n\n - The insert_watchpoint and remove_watchpoint methods (and perhaps\n   others) now assume that if they are called, the runtime is in the\n   \"enabled\" state.\n\n - insert_initial_watchpoints has one more check (loc-\u003eowner-\u003etype !\u003d\n   bp_hardware_watchpoint), to filter out non-write watchpoints.\n   Otherwise, I think that we could mistakenly insert some write\n   watchpoints for some pre-existing read watchpoints.\n\n - Because it is possible for read watchpoints to be created before the\n   target is pushed, remove_watchpoint returns early if it sees that the\n   code asks for the removal of a read watchpoint, instead of asserting\n   \"type \u003d\u003d hw_write\" (this was caught by the new test).\n\n - In ROCgdb, remove_watchpoint does:\n\n     if (addr \u003c it-\u003efirst || (addr + len) \u003e it-\u003esecond.first)\n       return 1;\n\n   I replaced it with some assertions.\n\n   The first half of this condition should always be true, due to how\n   std::upper_bound works.\n\n   For the second part: if the watchpoint was created successfully, it\n   is because it did fully cover the requested region (see\n   insert_one_watchpoint).  I don\u0027t see why the core would ask us to\n   remove a watchpoint that wasn\u0027t successfully inserted.  I am not 100%\n   sure about that one, there might be some edge cases where this is not\n   true.\n\n - I changed a manual free in stopped_by_watchpoint to a\n   gdb::unique_xmalloc_ptr, even though it changes nothing functionally.\n\n - I merged some conditions in amd_dbgapi_target_normal_stop.\n\nChange-Id: Ia15fb7434dc0c142a5a32997ada2e3a163c89f98\nApproved-by: Lancelot Six \u003clancelot.six@amd.com\u003e\nCo-Authored-By: Laurent Morichetti \u003claurent.morichetti@amd.com\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "471b7a7725ed5c9bfacea5193252463d0f92cfaf",
      "old_mode": 33188,
      "old_path": "gdb/amd-dbgapi-target.c",
      "new_id": "4e52683dc55afccb1d040706590fc18cb257a8d9",
      "new_mode": 33188,
      "new_path": "gdb/amd-dbgapi-target.c"
    },
    {
      "type": "modify",
      "old_id": "a4ccad32a8b90346d5c5f9ce5933c5361880b11c",
      "old_mode": 33188,
      "old_path": "gdb/breakpoint.c",
      "new_id": "da99ec27e19f02f90d13e5503c702876b29c6fe0",
      "new_mode": 33188,
      "new_path": "gdb/breakpoint.c"
    },
    {
      "type": "modify",
      "old_id": "0d9111ba92e906ac4d1464bb9d9e9fe327de205f",
      "old_mode": 33188,
      "old_path": "gdb/breakpoint.h",
      "new_id": "6b5dbcfe8a3c036e77b3a84d0c58045f911518b9",
      "new_mode": 33188,
      "new_path": "gdb/breakpoint.h"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "dfa50be4b0da886a86f41e55287735c08c49ef76",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/precise-memory-warning-watchpoint.cpp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "9f8dac68047b2f882948772c440bbd70efdaaef1",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/precise-memory-warning-watchpoint.exp"
    },
    {
      "type": "modify",
      "old_id": "70d232b873b86fd795daa78044ec6ae34a761e23",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.rocm/rocm-test-utils.h",
      "new_id": "cbb1f654461739a8e0bbf0ce7ad5ab5b1ceba195",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/rocm-test-utils.h"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "e25c93e78489a17e08ef6c432e9c4e3780c4779b",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/watchpoint-at-end-of-shader.cpp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "ff233c8b26a669f1cc85f5852dfdcc94856817da",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/watchpoint-at-end-of-shader.exp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "a89f33678f4b82c46b97ed15fda96e9682ea8ab8",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/watchpoint-basic.cpp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "cd4b9c68f58abf53acad63aa99b2999bf823ff53",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.rocm/watchpoint-basic.exp"
    }
  ]
}
