├── standalone_lldb.cmake ├── standalone_lldb_app.cmake ├── README.md ├── x86_debug_registers.patch └── hwbreakpoints.patch /standalone_lldb.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_BUILD_TYPE Release CACHE STRING "") 2 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "") 3 | 4 | set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "") 5 | #set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "") 6 | #set(LLVM_ENABLE_MODULES ON CACHE BOOL "") 7 | set(LLDB_INCLUDE_TESTS OFF CACHE BOOL "") 8 | 9 | set(LLDB_NO_INSTALL_DEFAULT_RPATH ON CACHE BOOL "") 10 | set(CMAKE_OSX_DEPLOYMENT_TARGET 10.11 CACHE STRING "") 11 | 12 | set(LLDB_BUILD_FRAMEWORK ON CACHE BOOL "") 13 | 14 | -------------------------------------------------------------------------------- /standalone_lldb_app.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_BUILD_TYPE Release CACHE STRING "") 2 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "") 3 | 4 | set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "") 5 | set(LLVM_ENABLE_PROJECTS clang;lldb CACHE STRING "") 6 | set(LLDB_INCLUDE_TESTS OFF CACHE BOOL "") 7 | set(LLDB_SKIP_STRIP ON CACHE BOOL "") 8 | 9 | set(LLDB_NO_INSTALL_DEFAULT_RPATH OFF CACHE BOOL "") 10 | set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13 CACHE STRING "") 11 | 12 | set(LLVM_CCACHE_BUILD ON CACHE BOOL "") 13 | 14 | set(LLDB_BUILD_FRAMEWORK OFF CACHE BOOL "") 15 | 16 | set(CMAKE_INSTALL_PREFIX /Applications/lldb-ng.app/Contents/usr CACHE STRING "") 17 | 18 | set(LLDB_ENABLE_PYTHON ON CACHE BOOL "") 19 | set(LLDB_EMBED_PYTHON_HOME OFF CACHE BOOL "") 20 | set(Python3_ROOT_DIR "/Applications/lldb-ng.app/Contents/Frameworks/Python.framework/Versions/3.9/" CACHE STRING "") 21 | set(LLDB_PYTHON_HOME "/Applications/lldb-ng.app/Contents/Frameworks/Python.framework/Versions/3.9/bin" CACHE STRING "") 22 | 23 | set(LLVM_DISTRIBUTION_COMPONENTS 24 | lldb 25 | liblldb 26 | lldb-argdumper 27 | darwin-debug 28 | debugserver 29 | lldb-python-scripts 30 | CACHE STRING "") 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Patch #1 3 | 4 | `hwbreakpoints.patch` and `standalone_lldb.cmake` are LLVM patches to add i386/x86_64 hardware breakpoints support for LLDB. 5 | 6 | Diff generated from llvmorg-9.0.0 tag, the latest stable released. 7 | Should work fine from master at least up to Nov 18th 2019 commits. 8 | 9 | Please read [How to make LLDB a real debugger](https://reverse.put.as/2019/11/19/how-to-make-lldb-a-real-debugger/) blogpost to understand how the patch was built and how to build you own LLDB version. 10 | 11 | A rework of this patch has been introduced in version 11, so not needed anymore if using newer versions. 12 | 13 | ### Patch #2 14 | 15 | `x86_debug_registers.patch` and `standalone_lldb_app.cmake` are LLVM patches to add access to i386/x86_64 debug registers in LLDB. 16 | 17 | Diff generated from [llvm-project-12.0.1.src.tar.xz](https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.1/llvm-project-12.0.1.src.tar.xz), the latest stable at time of writing. 18 | 19 | Pleaes read [How to build a custom and distributable lldb](https://reverse.put.as/2021/07/16/how-to-build-custom-lldb/) blogpost to understand how to compile a standalone lldb version. 20 | 21 | If you have the patch outside the llvm source folder: 22 | ``` bash 23 | patch -p0 -d llvm-project-12.0.1.src __##reg)) 33 | #define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg)) 34 | #define FPU_SIZE_MMST(reg) \ 35 | @@ -1219,6 +1233,7 @@ kern_return_t DNBArchImplI386::EnableHardwareSingleStep(bool enable) { 36 | #define FPU_SIZE_YMM(reg) (32) 37 | #define FPU_SIZE_ZMM(reg) (64) 38 | #define EXC_SIZE(reg) (sizeof(((DNBArchImplI386::EXC *)NULL)->__##reg)) 39 | +#define DBG_SIZE(reg) (sizeof(((DNBArchImplI386::DBG *)NULL)->__##reg)) 40 | 41 | // This does not accurately identify the location of ymm0...7 in 42 | // Context.fpu.avx. That is because there is a bunch of padding 43 | @@ -1670,6 +1685,25 @@ const DNBRegisterInfo DNBArchImplI386::g_exc_registers[] = { 44 | EXC_SIZE(faultvaddr), EXC_OFFSET(faultvaddr), INVALID_NUB_REGNUM, 45 | INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}}; 46 | 47 | +// Debug registers 48 | +const DNBRegisterInfo DNBArchImplI386::g_dbg_registers[] = { 49 | + {e_regSetDBG, dbg_dr0, "dr0", NULL, Uint, Hex, DBG_SIZE(dr0), 50 | + DBG_OFFSET(dr0), -1U, -1U, -1U, -1U, NULL, NULL}, 51 | + {e_regSetDBG, dbg_dr1, "dr1", NULL, Uint, Hex, DBG_SIZE(dr1), 52 | + DBG_OFFSET(dr1), -1U, -1U, -1U, -1U, NULL, NULL}, 53 | + {e_regSetDBG, dbg_dr2, "dr2", NULL, Uint, Hex, DBG_SIZE(dr2), 54 | + DBG_OFFSET(dr2), -1U, -1U, -1U, -1U, NULL, NULL}, 55 | + {e_regSetDBG, dbg_dr3, "dr3", NULL, Uint, Hex, DBG_SIZE(dr3), 56 | + DBG_OFFSET(dr3), -1U, -1U, -1U, -1U, NULL, NULL}, 57 | + {e_regSetDBG, dbg_dr4, "dr4", NULL, Uint, Hex, DBG_SIZE(dr4), 58 | + DBG_OFFSET(dr4), -1U, -1U, -1U, -1U, NULL, NULL}, 59 | + {e_regSetDBG, dbg_dr5, "dr5", NULL, Uint, Hex, DBG_SIZE(dr5), 60 | + DBG_OFFSET(dr5), -1U, -1U, -1U, -1U, NULL, NULL}, 61 | + {e_regSetDBG, dbg_dr6, "dr6", NULL, Uint, Hex, DBG_SIZE(dr6), 62 | + DBG_OFFSET(dr6), -1U, -1U, -1U, -1U, NULL, NULL}, 63 | + {e_regSetDBG, dbg_dr7, "dr7", NULL, Uint, Hex, DBG_SIZE(dr7), 64 | + DBG_OFFSET(dr7), -1U, -1U, -1U, -1U, NULL, NULL}}; 65 | + 66 | // Number of registers in each register set 67 | const size_t DNBArchImplI386::k_num_gpr_registers = 68 | sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); 69 | @@ -1681,12 +1715,17 @@ const size_t DNBArchImplI386::k_num_fpu_registers_avx512f = 70 | sizeof(g_fpu_registers_avx512f) / sizeof(DNBRegisterInfo); 71 | const size_t DNBArchImplI386::k_num_exc_registers = 72 | sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); 73 | +const size_t DNBArchImplI386::k_num_dbg_registers = 74 | + sizeof(g_dbg_registers) / sizeof(DNBRegisterInfo); 75 | const size_t DNBArchImplI386::k_num_all_registers_no_avx = 76 | - k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; 77 | + k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers + 78 | + k_num_dbg_registers; 79 | const size_t DNBArchImplI386::k_num_all_registers_avx = 80 | - k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; 81 | + k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers + 82 | + k_num_dbg_registers; 83 | const size_t DNBArchImplI386::k_num_all_registers_avx512f = 84 | - k_num_gpr_registers + k_num_fpu_registers_avx512f + k_num_exc_registers; 85 | + k_num_gpr_registers + k_num_fpu_registers_avx512f + k_num_exc_registers + 86 | + k_num_dbg_registers; 87 | 88 | // Register set definitions. The first definitions at register set index 89 | // of zero is for all registers, followed by other registers sets. The 90 | @@ -1696,20 +1735,23 @@ const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_no_avx[] = { 91 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 92 | {"Floating Point Registers", g_fpu_registers_no_avx, 93 | k_num_fpu_registers_no_avx}, 94 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 95 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 96 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 97 | 98 | const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_avx[] = { 99 | {"i386 Registers", NULL, k_num_all_registers_avx}, 100 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 101 | {"Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx}, 102 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 103 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 104 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 105 | 106 | const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_avx512f[] = { 107 | {"i386 Registers", NULL, k_num_all_registers_avx512f}, 108 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 109 | {"Floating Point Registers", g_fpu_registers_avx512f, 110 | k_num_fpu_registers_avx512f}, 111 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 112 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 113 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 114 | 115 | // Total number of register sets for this architecture 116 | const size_t DNBArchImplI386::k_num_register_sets = 117 | @@ -1963,6 +2005,12 @@ bool DNBArchImplI386::GetRegisterValue(uint32_t set, uint32_t reg, 118 | return true; 119 | } 120 | break; 121 | + case e_regSetDBG: 122 | + if (reg < k_num_dbg_registers) { 123 | + value->value.uint32 = ((uint32_t *)(&m_state.context.dbg))[reg]; 124 | + return true; 125 | + } 126 | + break; 127 | } 128 | } 129 | return false; 130 | @@ -2209,6 +2257,12 @@ bool DNBArchImplI386::SetRegisterValue(uint32_t set, uint32_t reg, 131 | success = true; 132 | } 133 | break; 134 | + case e_regSetDBG: 135 | + if (reg < k_num_dbg_registers) { 136 | + ((uint32_t *)(&m_state.context.dbg))[reg] = value->value.uint32; 137 | + success = true; 138 | + } 139 | + break; 140 | } 141 | } 142 | 143 | @@ -2500,6 +2554,8 @@ kern_return_t DNBArchImplI386::GetRegisterState(int set, bool force) { 144 | return GetFPUState(force); 145 | case e_regSetEXC: 146 | return GetEXCState(force); 147 | + case e_regSetDBG: 148 | + return GetDBGState(force); 149 | default: 150 | break; 151 | } 152 | @@ -2518,6 +2574,8 @@ kern_return_t DNBArchImplI386::SetRegisterState(int set) { 153 | return SetFPUState(); 154 | case e_regSetEXC: 155 | return SetEXCState(); 156 | + case e_regSetDBG: 157 | + return SetDBGState(true); // fG! - true or false??? 158 | default: 159 | break; 160 | } 161 | diff --git lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 162 | index a702ea52e..946694705 100644 163 | --- lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 164 | +++ lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 165 | @@ -77,12 +77,14 @@ protected: 166 | static const DNBRegisterInfo g_fpu_registers_no_avx[]; 167 | static const DNBRegisterInfo g_fpu_registers_avx[]; 168 | static const DNBRegisterInfo g_exc_registers[]; 169 | + static const DNBRegisterInfo g_dbg_registers[]; 170 | static const DNBRegisterSetInfo g_reg_sets_no_avx[]; 171 | static const DNBRegisterSetInfo g_reg_sets_avx[]; 172 | static const size_t k_num_gpr_registers; 173 | static const size_t k_num_fpu_registers_no_avx; 174 | static const size_t k_num_fpu_registers_avx; 175 | static const size_t k_num_exc_registers; 176 | + static const size_t k_num_dbg_registers; 177 | static const size_t k_num_all_registers_no_avx; 178 | static const size_t k_num_all_registers_avx; 179 | static const size_t k_num_register_sets; 180 | diff --git lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 181 | index a633ed26f..7d901d3b2 100644 182 | --- lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 183 | +++ lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 184 | @@ -1322,6 +1322,18 @@ enum { 185 | k_num_exc_regs, 186 | }; 187 | 188 | +enum { 189 | + dbg_dr0, 190 | + dbg_dr1, 191 | + dbg_dr2, 192 | + dbg_dr3, 193 | + dbg_dr4, 194 | + dbg_dr5, 195 | + dbg_dr6, 196 | + dbg_dr7, 197 | + k_num_dbg_regs, 198 | +}; 199 | + 200 | enum ehframe_dwarf_regnums { 201 | ehframe_dwarf_rax = 0, 202 | ehframe_dwarf_rdx = 1, 203 | @@ -1558,6 +1570,9 @@ enum debugserver_regnums { 204 | #define EXC_OFFSET(reg) \ 205 | (offsetof(DNBArchImplX86_64::EXC, __##reg) + \ 206 | offsetof(DNBArchImplX86_64::Context, exc)) 207 | +#define DBG_OFFSET(reg) \ 208 | + (offsetof(DNBArchImplX86_64::DBG, __##reg) + \ 209 | + offsetof(DNBArchImplX86_64::Context, exc)) 210 | #define AVX_OFFSET_YMM(n) (AVX_OFFSET(ymmh0) + (32 * n)) 211 | #define AVX512F_OFFSET_ZMM(n) (AVX512F_OFFSET(zmmh0) + (64 * n)) 212 | 213 | @@ -1571,6 +1586,7 @@ enum debugserver_regnums { 214 | #define FPU_SIZE_YMM(reg) (32) 215 | #define FPU_SIZE_ZMM(reg) (64) 216 | #define EXC_SIZE(reg) (sizeof(((DNBArchImplX86_64::EXC *)NULL)->__##reg)) 217 | +#define DBG_SIZE(reg) (sizeof(((DNBArchImplX86_64::DBG *)NULL)->__##reg)) 218 | 219 | // These macros will auto define the register name, alt name, register size, 220 | // register offset, encoding, format and native register. This ensures that 221 | @@ -2195,6 +2211,25 @@ const DNBRegisterInfo DNBArchImplX86_64::g_exc_registers[] = { 222 | EXC_SIZE(faultvaddr), EXC_OFFSET(faultvaddr), -1U, -1U, -1U, -1U, NULL, 223 | NULL}}; 224 | 225 | +// Debug registers 226 | +const DNBRegisterInfo DNBArchImplX86_64::g_dbg_registers[] = { 227 | + {e_regSetDBG, dbg_dr0, "dr0", NULL, Uint, Hex, DBG_SIZE(dr0), 228 | + DBG_OFFSET(dr0), -1U, -1U, -1U, -1U, NULL, NULL}, 229 | + {e_regSetDBG, dbg_dr1, "dr1", NULL, Uint, Hex, DBG_SIZE(dr1), 230 | + DBG_OFFSET(dr1), -1U, -1U, -1U, -1U, NULL, NULL}, 231 | + {e_regSetDBG, dbg_dr2, "dr2", NULL, Uint, Hex, DBG_SIZE(dr2), 232 | + DBG_OFFSET(dr2), -1U, -1U, -1U, -1U, NULL, NULL}, 233 | + {e_regSetDBG, dbg_dr3, "dr3", NULL, Uint, Hex, DBG_SIZE(dr3), 234 | + DBG_OFFSET(dr3), -1U, -1U, -1U, -1U, NULL, NULL}, 235 | + {e_regSetDBG, dbg_dr4, "dr4", NULL, Uint, Hex, DBG_SIZE(dr4), 236 | + DBG_OFFSET(dr4), -1U, -1U, -1U, -1U, NULL, NULL}, 237 | + {e_regSetDBG, dbg_dr5, "dr5", NULL, Uint, Hex, DBG_SIZE(dr5), 238 | + DBG_OFFSET(dr5), -1U, -1U, -1U, -1U, NULL, NULL}, 239 | + {e_regSetDBG, dbg_dr6, "dr6", NULL, Uint, Hex, DBG_SIZE(dr6), 240 | + DBG_OFFSET(dr6), -1U, -1U, -1U, -1U, NULL, NULL}, 241 | + {e_regSetDBG, dbg_dr7, "dr7", NULL, Uint, Hex, DBG_SIZE(dr7), 242 | + DBG_OFFSET(dr7), -1U, -1U, -1U, -1U, NULL, NULL}}; 243 | + 244 | // Number of registers in each register set 245 | const size_t DNBArchImplX86_64::k_num_gpr_registers = 246 | sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); 247 | @@ -2204,14 +2239,19 @@ const size_t DNBArchImplX86_64::k_num_fpu_registers_avx = 248 | sizeof(g_fpu_registers_avx) / sizeof(DNBRegisterInfo); 249 | const size_t DNBArchImplX86_64::k_num_exc_registers = 250 | sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); 251 | +const size_t DNBArchImplX86_64::k_num_dbg_registers = 252 | + sizeof(g_dbg_registers) / sizeof(DNBRegisterInfo); 253 | const size_t DNBArchImplX86_64::k_num_all_registers_no_avx = 254 | - k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; 255 | + k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers + 256 | + k_num_dbg_registers; 257 | const size_t DNBArchImplX86_64::k_num_all_registers_avx = 258 | - k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; 259 | + k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers + 260 | + k_num_dbg_registers; 261 | const size_t DNBArchImplX86_64::k_num_fpu_registers_avx512f = 262 | sizeof(g_fpu_registers_avx512f) / sizeof(DNBRegisterInfo); 263 | const size_t DNBArchImplX86_64::k_num_all_registers_avx512f = 264 | - k_num_gpr_registers + k_num_fpu_registers_avx512f + k_num_exc_registers; 265 | + k_num_gpr_registers + k_num_fpu_registers_avx512f + k_num_exc_registers + 266 | + k_num_dbg_registers; 267 | 268 | // Register set definitions. The first definitions at register set index 269 | // of zero is for all registers, followed by other registers sets. The 270 | @@ -2221,20 +2261,23 @@ const DNBRegisterSetInfo DNBArchImplX86_64::g_reg_sets_no_avx[] = { 271 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 272 | {"Floating Point Registers", g_fpu_registers_no_avx, 273 | k_num_fpu_registers_no_avx}, 274 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 275 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 276 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 277 | 278 | const DNBRegisterSetInfo DNBArchImplX86_64::g_reg_sets_avx[] = { 279 | {"x86_64 Registers", NULL, k_num_all_registers_avx}, 280 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 281 | {"Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx}, 282 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 283 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 284 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 285 | 286 | const DNBRegisterSetInfo DNBArchImplX86_64::g_reg_sets_avx512f[] = { 287 | {"x86_64 Registers", NULL, k_num_all_registers_avx}, 288 | {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, 289 | {"Floating Point Registers", g_fpu_registers_avx512f, 290 | k_num_fpu_registers_avx512f}, 291 | - {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; 292 | + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, 293 | + {"Debug Registers", g_dbg_registers, k_num_dbg_registers}}; 294 | 295 | // Total number of register sets for this architecture 296 | const size_t DNBArchImplX86_64::k_num_register_sets = 297 | @@ -2481,6 +2524,12 @@ bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg, 298 | return true; 299 | } 300 | break; 301 | + case e_regSetDBG: 302 | + if (reg < k_num_dbg_registers) { 303 | + value->value.uint64 = ((uint64_t *)(&m_state.context.dbg))[reg]; 304 | + return true; 305 | + } 306 | + break; 307 | } 308 | } 309 | return false; 310 | @@ -2705,6 +2754,12 @@ bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg, 311 | break; 312 | } 313 | break; 314 | + case e_regSetDBG: 315 | + if (reg < k_num_dbg_registers) { 316 | + ((uint64_t *)(&m_state.context.dbg))[reg] = value->value.uint64; 317 | + success = true; 318 | + } 319 | + break; 320 | } 321 | } 322 | 323 | @@ -3006,6 +3061,8 @@ kern_return_t DNBArchImplX86_64::GetRegisterState(int set, bool force) { 324 | return GetFPUState(force); 325 | case e_regSetEXC: 326 | return GetEXCState(force); 327 | + case e_regSetDBG: 328 | + return GetDBGState(force); 329 | default: 330 | break; 331 | } 332 | @@ -3024,6 +3081,8 @@ kern_return_t DNBArchImplX86_64::SetRegisterState(int set) { 333 | return SetFPUState(); 334 | case e_regSetEXC: 335 | return SetEXCState(); 336 | + case e_regSetDBG: 337 | + return SetDBGState(true); // fG! - true or false??? 338 | default: 339 | break; 340 | } 341 | diff --git lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 342 | index 96da02a4c..9cb697b59 100644 343 | --- lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 344 | +++ lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 345 | @@ -77,12 +77,14 @@ protected: 346 | static const DNBRegisterInfo g_fpu_registers_no_avx[]; 347 | static const DNBRegisterInfo g_fpu_registers_avx[]; 348 | static const DNBRegisterInfo g_exc_registers[]; 349 | + static const DNBRegisterInfo g_dbg_registers[]; 350 | static const DNBRegisterSetInfo g_reg_sets_no_avx[]; 351 | static const DNBRegisterSetInfo g_reg_sets_avx[]; 352 | static const size_t k_num_gpr_registers; 353 | static const size_t k_num_fpu_registers_no_avx; 354 | static const size_t k_num_fpu_registers_avx; 355 | static const size_t k_num_exc_registers; 356 | + static const size_t k_num_dbg_registers; 357 | static const size_t k_num_all_registers_no_avx; 358 | static const size_t k_num_all_registers_avx; 359 | static const size_t k_num_register_sets; 360 | -------------------------------------------------------------------------------- /hwbreakpoints.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h 2 | index b5e2e25ef47..cc791b8d0eb 100644 3 | --- a/lldb/tools/debugserver/source/DNBArch.h 4 | +++ b/lldb/tools/debugserver/source/DNBArch.h 5 | @@ -78,7 +78,8 @@ public: 6 | virtual bool NotifyException(MachException::Data &exc) { return false; } 7 | virtual uint32_t NumSupportedHardwareBreakpoints() { return 0; } 8 | virtual uint32_t NumSupportedHardwareWatchpoints() { return 0; } 9 | - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size) { 10 | + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, 11 | + bool also_set_on_task) { 12 | return INVALID_NUB_HW_INDEX; 13 | } 14 | virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, 15 | @@ -86,7 +87,10 @@ public: 16 | bool also_set_on_task) { 17 | return INVALID_NUB_HW_INDEX; 18 | } 19 | - virtual bool DisableHardwareBreakpoint(uint32_t hw_index) { return false; } 20 | + virtual bool DisableHardwareBreakpoint(uint32_t hw_index, 21 | + bool also_set_on_task) { 22 | + return false; 23 | + } 24 | virtual bool DisableHardwareWatchpoint(uint32_t hw_index, 25 | bool also_set_on_task) { 26 | return false; 27 | diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm 28 | index 15a347778cf..c19cb76d590 100644 29 | --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm 30 | +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm 31 | @@ -1944,6 +1944,10 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, 32 | if (bp->HardwarePreferred()) { 33 | bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp)); 34 | if (bp->IsHardware()) { 35 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::" 36 | + "EnableBreakpoint ( addr = " 37 | + "0x%8.8llx ) : hw bpt SUCCESS.", 38 | + (uint64_t)addr); 39 | bp->SetEnabled(true); 40 | return true; 41 | } 42 | diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp 43 | index b51ea694922..84e2de1f4c4 100644 44 | --- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp 45 | +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp 46 | @@ -534,9 +534,12 @@ bool MachThread::RestoreRegisterState(uint32_t save_id) { 47 | return m_arch_up->RestoreRegisterState(save_id); 48 | } 49 | 50 | -uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp) { 51 | - if (bp != NULL && bp->IsBreakpoint()) 52 | - return m_arch_up->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); 53 | +uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp, 54 | + bool also_set_on_task) { 55 | + if (bp != NULL && bp->IsBreakpoint()) { 56 | + return m_arch_up->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize(), 57 | + also_set_on_task); 58 | + } 59 | return INVALID_NUB_HW_INDEX; 60 | } 61 | 62 | @@ -555,9 +558,12 @@ bool MachThread::RollbackTransForHWP() { 63 | 64 | bool MachThread::FinishTransForHWP() { return m_arch_up->FinishTransForHWP(); } 65 | 66 | -bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp) { 67 | - if (bp != NULL && bp->IsHardware()) 68 | - return m_arch_up->DisableHardwareBreakpoint(bp->GetHardwareIndex()); 69 | +bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp, 70 | + bool also_set_on_task) { 71 | + if (bp != NULL && bp->IsHardware()) { 72 | + return m_arch_up->DisableHardwareBreakpoint(bp->GetHardwareIndex(), 73 | + also_set_on_task); 74 | + } 75 | return false; 76 | } 77 | 78 | diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h 79 | index 1634522fde4..cbcd94ea576 100644 80 | --- a/lldb/tools/debugserver/source/MacOSX/MachThread.h 81 | +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h 82 | @@ -66,10 +66,12 @@ public: 83 | uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer 84 | 85 | DNBBreakpoint *CurrentBreakpoint(); 86 | - uint32_t EnableHardwareBreakpoint(const DNBBreakpoint *breakpoint); 87 | + uint32_t EnableHardwareBreakpoint(const DNBBreakpoint *breakpoint, 88 | + bool also_set_on_task); 89 | uint32_t EnableHardwareWatchpoint(const DNBBreakpoint *watchpoint, 90 | bool also_set_on_task); 91 | - bool DisableHardwareBreakpoint(const DNBBreakpoint *breakpoint); 92 | + bool DisableHardwareBreakpoint(const DNBBreakpoint *breakpoint, 93 | + bool also_set_on_task); 94 | bool DisableHardwareWatchpoint(const DNBBreakpoint *watchpoint, 95 | bool also_set_on_task); 96 | uint32_t NumSupportedHardwareWatchpoints() const; 97 | diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp 98 | index 0fa4437843a..21cee460ba6 100644 99 | --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp 100 | +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp 101 | @@ -480,19 +480,60 @@ void MachThreadList::NotifyBreakpointChanged(const DNBBreakpoint *bp) { 102 | 103 | uint32_t 104 | MachThreadList::EnableHardwareBreakpoint(const DNBBreakpoint *bp) const { 105 | + uint32_t hw_index = INVALID_NUB_HW_INDEX; 106 | if (bp != NULL) { 107 | + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); 108 | const size_t num_threads = m_threads.size(); 109 | - for (uint32_t idx = 0; idx < num_threads; ++idx) 110 | - m_threads[idx]->EnableHardwareBreakpoint(bp); 111 | + // On Mac OS X we have to prime the control registers for new threads. We 112 | + // do this 113 | + // using the control register data for the first thread, for lack of a 114 | + // better way of choosing. 115 | + bool also_set_on_task = true; 116 | + for (uint32_t idx = 0; idx < num_threads; ++idx) { 117 | + if ((hw_index = m_threads[idx]->EnableHardwareBreakpoint( 118 | + bp, also_set_on_task)) == INVALID_NUB_HW_INDEX) { 119 | + // We know that idx failed for some reason. Let's rollback the 120 | + // transaction for [0, idx). 121 | + for (uint32_t i = 0; i < idx; ++i) { 122 | + m_threads[i]->RollbackTransForHWP(); 123 | + } 124 | + return INVALID_NUB_HW_INDEX; 125 | + } 126 | + also_set_on_task = false; 127 | + } 128 | + // Notify each thread to commit the pending transaction. 129 | + for (uint32_t idx = 0; idx < num_threads; ++idx) { 130 | + m_threads[idx]->FinishTransForHWP(); 131 | + } 132 | } 133 | - return INVALID_NUB_HW_INDEX; 134 | + return hw_index; 135 | } 136 | 137 | bool MachThreadList::DisableHardwareBreakpoint(const DNBBreakpoint *bp) const { 138 | if (bp != NULL) { 139 | + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); 140 | const size_t num_threads = m_threads.size(); 141 | + 142 | + // On Mac OS X we have to prime the control registers for new threads. We 143 | + // do this 144 | + // using the control register data for the first thread, for lack of a 145 | + // better way of choosing. 146 | + bool also_set_on_task = true; 147 | + for (uint32_t idx = 0; idx < num_threads; ++idx) { 148 | + if (!m_threads[idx]->DisableHardwareBreakpoint(bp, also_set_on_task)) { 149 | + // We know that idx failed for some reason. Let's rollback the 150 | + // transaction for [0, idx). 151 | + for (uint32_t i = 0; i < idx; ++i) 152 | + m_threads[i]->RollbackTransForHWP(); 153 | + return false; 154 | + } 155 | + also_set_on_task = false; 156 | + } 157 | + // Notify each thread to commit the pending transaction. 158 | for (uint32_t idx = 0; idx < num_threads; ++idx) 159 | - m_threads[idx]->DisableHardwareBreakpoint(bp); 160 | + m_threads[idx]->FinishTransForHWP(); 161 | + 162 | + return true; 163 | } 164 | return false; 165 | } 166 | diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp 167 | index 45d05d6e0bd..90cc25650e3 100644 168 | --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp 169 | +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp 170 | @@ -980,7 +980,8 @@ uint32_t DNBArchMachARM::NumSupportedHardwareWatchpoints() { 171 | } 172 | 173 | uint32_t DNBArchMachARM::EnableHardwareBreakpoint(nub_addr_t addr, 174 | - nub_size_t size) { 175 | + nub_size_t size, 176 | + bool also_set_on_task) { 177 | // Make sure our address isn't bogus 178 | if (addr & 1) 179 | return INVALID_NUB_HW_INDEX; 180 | @@ -1052,7 +1053,8 @@ uint32_t DNBArchMachARM::EnableHardwareBreakpoint(nub_addr_t addr, 181 | return INVALID_NUB_HW_INDEX; 182 | } 183 | 184 | -bool DNBArchMachARM::DisableHardwareBreakpoint(uint32_t hw_index) { 185 | +bool DNBArchMachARM::DisableHardwareBreakpoint(uint32_t hw_index, 186 | + bool also_set_on_task) { 187 | kern_return_t kret = GetDBGState(false); 188 | 189 | const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); 190 | diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h 191 | index 4bb899b4503..4c27a342f9f 100644 192 | --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h 193 | +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h 194 | @@ -70,8 +70,10 @@ public: 195 | 196 | virtual uint32_t NumSupportedHardwareBreakpoints(); 197 | virtual uint32_t NumSupportedHardwareWatchpoints(); 198 | - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size); 199 | - virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index); 200 | + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, 201 | + bool also_set_on_task); 202 | + virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, 203 | + bool also_set_on_task); 204 | 205 | virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, 206 | bool read, bool write, 207 | diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp 208 | index 7d2d0c2ef1b..b17c040facd 100644 209 | --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp 210 | +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp 211 | @@ -718,6 +718,11 @@ bool DNBArchImplI386::NotifyException(MachException::Data &exc) { 212 | return false; 213 | } 214 | 215 | +uint32_t DNBArchImplI386::NumSupportedHardwareBreakpoints() { 216 | + // Available debug address registers: dr0, dr1, dr2, dr3. 217 | + return 4; 218 | +} 219 | + 220 | uint32_t DNBArchImplI386::NumSupportedHardwareWatchpoints() { 221 | // Available debug address registers: dr0, dr1, dr2, dr3. 222 | return 4; 223 | @@ -797,6 +802,148 @@ void DNBArchImplI386::SetWatchpoint(DBG &debug_state, uint32_t hw_index, 224 | return; 225 | } 226 | 227 | +void DNBArchImplI386::SetHardwareBreakpoint(DBG &debug_state, uint32_t hw_index, 228 | + nub_addr_t addr, nub_size_t size) { 229 | + // Set both dr7 (debug control register) and dri (debug address register). 230 | + 231 | + // dr7{7-0} encodes the local/gloabl enable bits: 232 | + // global enable --. .-- local enable 233 | + // | | 234 | + // v v 235 | + // dr0 -> bits{1-0} 236 | + // dr1 -> bits{3-2} 237 | + // dr2 -> bits{5-4} 238 | + // dr3 -> bits{7-6} 239 | + // 240 | + // dr7{31-16} encodes the rw/len bits: 241 | + // b_x+3, b_x+2, b_x+1, b_x 242 | + // where bits{x+1, x} => rw 243 | + // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io 244 | + // read-or-write (unused) 245 | + // and bits{x+3, x+2} => len 246 | + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte 247 | + // 248 | + // dr0 -> bits{19-16} 249 | + // dr1 -> bits{23-20} 250 | + // dr2 -> bits{27-24} 251 | + // dr3 -> bits{31-28} 252 | + debug_state.__dr7 |= 253 | + (1 << (2 * hw_index) | 0 << (16 + 4 * hw_index)); 254 | + uint32_t addr_32 = addr & 0xffffffff; 255 | + switch (hw_index) { 256 | + case 0: 257 | + debug_state.__dr0 = addr_32; 258 | + break; 259 | + case 1: 260 | + debug_state.__dr1 = addr_32; 261 | + break; 262 | + case 2: 263 | + debug_state.__dr2 = addr_32; 264 | + break; 265 | + case 3: 266 | + debug_state.__dr3 = addr_32; 267 | + break; 268 | + default: 269 | + assert(0 && 270 | + "invalid hardware register index, must be one of 0, 1, 2, or 3"); 271 | + } 272 | + return; 273 | +} 274 | + 275 | +uint32_t DNBArchImplI386::EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, 276 | + bool also_set_on_task) { 277 | + DNBLogThreadedIf(LOG_BREAKPOINTS, 278 | + "DNBArchImplI386::EnableHardwareBreakpoint( addr = " 279 | + "0x%8.8llx, size = %llu )", 280 | + (uint64_t)addr, (uint64_t)size); 281 | + 282 | + const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); 283 | + // Read the debug state 284 | + kern_return_t kret = GetDBGState(false); 285 | + 286 | + if (kret != KERN_SUCCESS) { 287 | + return INVALID_NUB_HW_INDEX; 288 | + } 289 | + 290 | + // Check to make sure we have the needed hardware support 291 | + uint32_t i = 0; 292 | + 293 | + DBG &debug_state = m_state.context.dbg; 294 | + for (i = 0; i < num_hw_breakpoints; ++i) { 295 | + if (IsWatchpointVacant(debug_state, i)) { 296 | + break; 297 | + } 298 | + } 299 | + 300 | + // See if we found an available hw breakpoint slot above 301 | + if (i < num_hw_breakpoints) { 302 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplI386::EnableHardwareBreakpoint( free slot = %u )", 303 | + i); 304 | + 305 | + StartTransForHWP(); 306 | + 307 | + // Modify our local copy of the debug state, first. 308 | + SetHardwareBreakpoint(debug_state, i, addr, size); 309 | + // Now set the watch point in the inferior. 310 | + kret = SetDBGState(also_set_on_task); 311 | + 312 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplI386::" 313 | + "EnableHardwareBreakpoint() " 314 | + "SetDBGState() => 0x%8.8x.", 315 | + kret); 316 | + 317 | + if (kret == KERN_SUCCESS) { 318 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplI386::EnableHardwareBreakpoint( enabled at slot = %u)", 319 | + i); 320 | + return i; 321 | + } 322 | + // Revert to the previous debug state voluntarily. The transaction 323 | + // coordinator knows that we have failed. 324 | + else { 325 | + m_state.context.dbg = GetDBGCheckpoint(); 326 | + } 327 | + } 328 | + else { 329 | + DNBLogThreadedIf(LOG_BREAKPOINTS, 330 | + "DNBArchImplI386::EnableHardwareBreakpoint(addr = " 331 | + "0x%8.8llx, size = %llu) => all hardware breakpoint " 332 | + "resources are being used.", 333 | + (uint64_t)addr, (uint64_t)size); 334 | + } 335 | + 336 | + return INVALID_NUB_HW_INDEX; 337 | +} 338 | + 339 | +bool DNBArchImplI386::DisableHardwareBreakpoint(uint32_t hw_index, 340 | + bool also_set_on_task) { 341 | + kern_return_t kret = GetDBGState(false); 342 | + 343 | + const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); 344 | + if (kret == KERN_SUCCESS) { 345 | + DBG &debug_state = m_state.context.dbg; 346 | + if (hw_index < num_hw_points && 347 | + !IsWatchpointVacant(debug_state, hw_index)) { 348 | + 349 | + StartTransForHWP(); 350 | + 351 | + // Modify our local copy of the debug state, first. 352 | + ClearWatchpoint(debug_state, hw_index); 353 | + // Now disable the watch point in the inferior. 354 | + kret = SetDBGState(true); 355 | + DNBLogThreadedIf(LOG_WATCHPOINTS, 356 | + "DNBArchImplI386::DisableHardwareBreakpoint( %u )", 357 | + hw_index); 358 | + 359 | + if (kret == KERN_SUCCESS) 360 | + return true; 361 | + else // Revert to the previous debug state voluntarily. The transaction 362 | + // coordinator knows that we have failed. 363 | + m_state.context.dbg = GetDBGCheckpoint(); 364 | + } 365 | + } 366 | + return false; 367 | +} 368 | + 369 | void DNBArchImplI386::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) { 370 | debug_state.__dr7 &= ~(3 << (2 * hw_index)); 371 | switch (hw_index) { 372 | diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 373 | index 12b515a2957..ea63140722b 100644 374 | --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 375 | +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h 376 | @@ -51,7 +51,12 @@ public: 377 | virtual bool ThreadDidStop(); 378 | virtual bool NotifyException(MachException::Data &exc); 379 | 380 | + virtual uint32_t NumSupportedHardwareBreakpoints(); 381 | virtual uint32_t NumSupportedHardwareWatchpoints(); 382 | + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, 383 | + bool also_set_on_task); 384 | + virtual bool DisableHardwareBreakpoint(uint32_t hw_index, 385 | + bool also_set_on_task); 386 | virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, 387 | bool read, bool write, 388 | bool also_set_on_task); 389 | @@ -210,6 +215,9 @@ protected: 390 | 391 | static uint32_t GetRegisterContextSize(); 392 | 393 | + static void SetHardwareBreakpoint(DBG &debug_state, uint32_t hw_index, 394 | + nub_addr_t addr, nub_size_t size); 395 | + 396 | // Helper functions for watchpoint manipulations. 397 | static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, 398 | nub_addr_t addr, nub_size_t size, bool read, 399 | diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 400 | index 319215e8a7f..0233ce3f592 100644 401 | --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 402 | +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp 403 | @@ -679,6 +679,12 @@ uint32_t DNBArchImplX86_64::NumSupportedHardwareWatchpoints() { 404 | return 4; 405 | } 406 | 407 | +uint32_t DNBArchImplX86_64::NumSupportedHardwareBreakpoints() { 408 | + DNBLogThreadedIf(LOG_BREAKPOINTS, 409 | + "DNBArchImplX86_64::NumSupportedHardwareBreakpoints"); 410 | + return 4; 411 | +} 412 | + 413 | static uint32_t size_and_rw_bits(nub_size_t size, bool read, bool write) { 414 | uint32_t rw; 415 | if (read) { 416 | @@ -853,6 +859,149 @@ DNBArchImplX86_64::DBG DNBArchImplX86_64::GetDBGCheckpoint() { 417 | return m_2pc_dbg_checkpoint; 418 | } 419 | 420 | +void DNBArchImplX86_64::SetHardwareBreakpoint(DBG &debug_state, uint32_t hw_index, 421 | + nub_addr_t addr, nub_size_t size) { 422 | + // Set both dr7 (debug control register) and dri (debug address register). 423 | + 424 | + // dr7{7-0} encodes the local/gloabl enable bits: 425 | + // global enable --. .-- local enable 426 | + // | | 427 | + // v v 428 | + // dr0 -> bits{1-0} 429 | + // dr1 -> bits{3-2} 430 | + // dr2 -> bits{5-4} 431 | + // dr3 -> bits{7-6} 432 | + // 433 | + // dr7{31-16} encodes the rw/len bits: 434 | + // b_x+3, b_x+2, b_x+1, b_x 435 | + // where bits{x+1, x} => rw 436 | + // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io 437 | + // read-or-write (unused) 438 | + // and bits{x+3, x+2} => len 439 | + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte 440 | + // 441 | + // dr0 -> bits{19-16} 442 | + // dr1 -> bits{23-20} 443 | + // dr2 -> bits{27-24} 444 | + // dr3 -> bits{31-28} 445 | + debug_state.__dr7 |= 446 | + (1 << (2 * hw_index) | 0 << (16 + 4 * hw_index)); 447 | + 448 | + switch (hw_index) { 449 | + case 0: 450 | + debug_state.__dr0 = addr; 451 | + break; 452 | + case 1: 453 | + debug_state.__dr1 = addr; 454 | + break; 455 | + case 2: 456 | + debug_state.__dr2 = addr; 457 | + break; 458 | + case 3: 459 | + debug_state.__dr3 = addr; 460 | + break; 461 | + default: 462 | + assert(0 && 463 | + "invalid hardware register index, must be one of 0, 1, 2, or 3"); 464 | + } 465 | + return; 466 | +} 467 | + 468 | +uint32_t DNBArchImplX86_64::EnableHardwareBreakpoint(nub_addr_t addr, 469 | + nub_size_t size, 470 | + bool also_set_on_task) { 471 | + DNBLogThreadedIf(LOG_BREAKPOINTS, 472 | + "DNBArchImplX86_64::EnableHardwareBreakpoint( addr = " 473 | + "0x%8.8llx, size = %llu )", 474 | + (uint64_t)addr, (uint64_t)size); 475 | + 476 | + const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); 477 | + // Read the debug state 478 | + kern_return_t kret = GetDBGState(false); 479 | + 480 | + if (kret != KERN_SUCCESS) { 481 | + return INVALID_NUB_HW_INDEX; 482 | + } 483 | + 484 | + // Check to make sure we have the needed hardware support 485 | + uint32_t i = 0; 486 | + 487 | + DBG &debug_state = m_state.context.dbg; 488 | + for (i = 0; i < num_hw_breakpoints; ++i) { 489 | + if (IsWatchpointVacant(debug_state, i)) { 490 | + break; 491 | + } 492 | + } 493 | + 494 | + // See if we found an available hw breakpoint slot above 495 | + if (i < num_hw_breakpoints) { 496 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplX86_64::EnableHardwareBreakpoint( free slot = %u )", 497 | + i); 498 | + 499 | + StartTransForHWP(); 500 | + 501 | + // Modify our local copy of the debug state, first. 502 | + SetHardwareBreakpoint(debug_state, i, addr, size); 503 | + // Now set the watch point in the inferior. 504 | + kret = SetDBGState(also_set_on_task); 505 | + 506 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplX86_64::" 507 | + "EnableHardwareBreakpoint() " 508 | + "SetDBGState() => 0x%8.8x.", 509 | + kret); 510 | + 511 | + if (kret == KERN_SUCCESS) { 512 | + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchImplX86_64::EnableHardwareBreakpoint( enabled at slot = %u)", 513 | + i); 514 | + return i; 515 | + } 516 | + // Revert to the previous debug state voluntarily. The transaction 517 | + // coordinator knows that we have failed. 518 | + else { 519 | + m_state.context.dbg = GetDBGCheckpoint(); 520 | + } 521 | + } 522 | + else { 523 | + DNBLogThreadedIf(LOG_BREAKPOINTS, 524 | + "DNBArchImplX86_64::EnableHardwareBreakpoint(addr = " 525 | + "0x%8.8llx, size = %llu) => all hardware breakpoint " 526 | + "resources are being used.", 527 | + (uint64_t)addr, (uint64_t)size); 528 | + } 529 | + 530 | + return INVALID_NUB_HW_INDEX; 531 | +} 532 | + 533 | +bool DNBArchImplX86_64::DisableHardwareBreakpoint(uint32_t hw_index, 534 | + bool also_set_on_task) { 535 | + kern_return_t kret = GetDBGState(false); 536 | + 537 | + const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); 538 | + if (kret == KERN_SUCCESS) { 539 | + DBG &debug_state = m_state.context.dbg; 540 | + if (hw_index < num_hw_points && 541 | + !IsWatchpointVacant(debug_state, hw_index)) { 542 | + 543 | + StartTransForHWP(); 544 | + 545 | + // Modify our local copy of the debug state, first. 546 | + ClearWatchpoint(debug_state, hw_index); 547 | + // Now disable the watch point in the inferior. 548 | + kret = SetDBGState(true); 549 | + DNBLogThreadedIf(LOG_WATCHPOINTS, 550 | + "DNBArchImplX86_64::DisableHardwareBreakpoint( %u )", 551 | + hw_index); 552 | + 553 | + if (kret == KERN_SUCCESS) 554 | + return true; 555 | + else // Revert to the previous debug state voluntarily. The transaction 556 | + // coordinator knows that we have failed. 557 | + m_state.context.dbg = GetDBGCheckpoint(); 558 | + } 559 | + } 560 | + return false; 561 | +} 562 | + 563 | uint32_t DNBArchImplX86_64::EnableHardwareWatchpoint(nub_addr_t addr, 564 | nub_size_t size, bool read, 565 | bool write, 566 | diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 567 | index 62ce37d4c04..e59337d405f 100644 568 | --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 569 | +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h 570 | @@ -50,7 +50,13 @@ public: 571 | virtual bool ThreadDidStop(); 572 | virtual bool NotifyException(MachException::Data &exc); 573 | 574 | + virtual uint32_t NumSupportedHardwareBreakpoints(); 575 | virtual uint32_t NumSupportedHardwareWatchpoints(); 576 | + 577 | + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, 578 | + bool also_set_on_task); 579 | + virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, 580 | + bool also_set_on_task); 581 | virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, 582 | bool read, bool write, 583 | bool also_set_on_task); 584 | @@ -213,6 +219,10 @@ protected: 585 | 586 | static uint32_t GetRegisterContextSize(); 587 | 588 | + 589 | + static void SetHardwareBreakpoint(DBG &debug_state, uint32_t hw_index, 590 | + nub_addr_t addr, nub_size_t size); 591 | + 592 | // Helper functions for watchpoint manipulations. 593 | static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, 594 | nub_addr_t addr, nub_size_t size, bool read, 595 | diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp 596 | index 3a4035b0b9b..11a07f22098 100644 597 | --- a/lldb/tools/debugserver/source/RNBRemote.cpp 598 | +++ b/lldb/tools/debugserver/source/RNBRemote.cpp 599 | @@ -279,12 +279,10 @@ void RNBRemote::CreatePacketTable() { 600 | "x", "Read data from memory")); 601 | t.push_back(Packet(write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, 602 | "X", "Write data to memory")); 603 | - // t.push_back (Packet (insert_hardware_bp, 604 | - // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z1", "Insert hardware 605 | - // breakpoint")); 606 | - // t.push_back (Packet (remove_hardware_bp, 607 | - // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z1", "Remove hardware 608 | - // breakpoint")); 609 | + t.push_back (Packet(insert_hardware_bp, &RNBRemote::HandlePacket_z, NULL, 610 | + "Z1", "Insert hardware breakpoint")); 611 | + t.push_back (Packet(remove_hardware_bp, &RNBRemote::HandlePacket_z, NULL, 612 | + "z1", "Remove hardware breakpoint")); 613 | t.push_back(Packet(insert_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, 614 | "Z2", "Insert write watchpoint")); 615 | t.push_back(Packet(remove_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, 616 | --------------------------------------------------------------------------------