@@ -85,6 +85,7 @@ NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
85
85
}
86
86
87
87
::memset (&m_gpr_ppc64le, 0 , sizeof (m_gpr_ppc64le));
88
+ ::memset (&m_hwp_regs, 0 , sizeof (m_hwp_regs));
88
89
}
89
90
90
91
uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount () const {
@@ -242,4 +243,263 @@ Status NativeRegisterContextLinux_ppc64le::DoWriteGPR(
242
243
®set, buf, buf_size);
243
244
}
244
245
246
+ uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints () {
247
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
248
+
249
+ // Read hardware breakpoint and watchpoint information.
250
+ Status error = ReadHardwareDebugInfo ();
251
+
252
+ if (error.Fail ())
253
+ return 0 ;
254
+
255
+ LLDB_LOG (log , " {0}" , m_max_hwp_supported);
256
+ return m_max_hwp_supported;
257
+ }
258
+
259
+ uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint (
260
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
261
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
262
+ LLDB_LOG (log , " addr: {0:x}, size: {1:x} watch_flags: {2:x}" , addr, size,
263
+ watch_flags);
264
+
265
+ // Read hardware breakpoint and watchpoint information.
266
+ Status error = ReadHardwareDebugInfo ();
267
+
268
+ if (error.Fail ())
269
+ return LLDB_INVALID_INDEX32;
270
+
271
+ uint32_t control_value = 0 , wp_index = 0 ;
272
+ lldb::addr_t real_addr = addr;
273
+ uint32_t rw_mode = 0 ;
274
+
275
+ // Check if we are setting watchpoint other than read/write/access
276
+ // Update watchpoint flag to match ppc64le write-read bit configuration.
277
+ switch (watch_flags) {
278
+ case eWatchpointKindWrite:
279
+ rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
280
+ watch_flags = 2 ;
281
+ break ;
282
+ case eWatchpointKindRead:
283
+ rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
284
+ watch_flags = 1 ;
285
+ break ;
286
+ case (eWatchpointKindRead | eWatchpointKindWrite):
287
+ rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
288
+ break ;
289
+ default :
290
+ return LLDB_INVALID_INDEX32;
291
+ }
292
+
293
+ // Check if size has a valid hardware watchpoint length.
294
+ if (size != 1 && size != 2 && size != 4 && size != 8 )
295
+ return LLDB_INVALID_INDEX32;
296
+
297
+ // Check 8-byte alignment for hardware watchpoint target address.
298
+ // Below is a hack to recalculate address and size in order to
299
+ // make sure we can watch non 8-byte alligned addresses as well.
300
+ if (addr & 0x07 ) {
301
+
302
+ addr_t begin = llvm::alignDown (addr, 8 );
303
+ addr_t end = llvm::alignTo (addr + size, 8 );
304
+ size = llvm::PowerOf2Ceil (end - begin);
305
+
306
+ addr = addr & (~0x07 );
307
+ }
308
+
309
+ // Setup control value
310
+ control_value = watch_flags << 3 ;
311
+ control_value |= ((1 << size) - 1 ) << 5 ;
312
+ control_value |= (2 << 1 ) | 1 ;
313
+
314
+ // Iterate over stored watchpoints and find a free wp_index
315
+ wp_index = LLDB_INVALID_INDEX32;
316
+ for (uint32_t i = 0 ; i < m_max_hwp_supported; i++) {
317
+ if ((m_hwp_regs[i].control & 1 ) == 0 ) {
318
+ wp_index = i; // Mark last free slot
319
+ } else if (m_hwp_regs[i].address == addr) {
320
+ return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
321
+ }
322
+ }
323
+
324
+ if (wp_index == LLDB_INVALID_INDEX32)
325
+ return LLDB_INVALID_INDEX32;
326
+
327
+ // Update watchpoint in local cache
328
+ m_hwp_regs[wp_index].real_addr = real_addr;
329
+ m_hwp_regs[wp_index].address = addr;
330
+ m_hwp_regs[wp_index].control = control_value;
331
+ m_hwp_regs[wp_index].mode = rw_mode;
332
+
333
+ // PTRACE call to set corresponding watchpoint register.
334
+ error = WriteHardwareDebugRegs ();
335
+
336
+ if (error.Fail ()) {
337
+ m_hwp_regs[wp_index].address = 0 ;
338
+ m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t >(1 );
339
+
340
+ return LLDB_INVALID_INDEX32;
341
+ }
342
+
343
+ return wp_index;
344
+ }
345
+
346
+ bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint (
347
+ uint32_t wp_index) {
348
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
349
+ LLDB_LOG (log , " wp_index: {0}" , wp_index);
350
+
351
+ // Read hardware breakpoint and watchpoint information.
352
+ Status error = ReadHardwareDebugInfo ();
353
+
354
+ if (error.Fail ())
355
+ return false ;
356
+
357
+ if (wp_index >= m_max_hwp_supported)
358
+ return false ;
359
+
360
+ // Create a backup we can revert to in case of failure.
361
+ lldb::addr_t tempAddr = m_hwp_regs[wp_index].address ;
362
+ uint32_t tempControl = m_hwp_regs[wp_index].control ;
363
+ long *tempSlot = reinterpret_cast <long *>(m_hwp_regs[wp_index].slot );
364
+
365
+ // Update watchpoint in local cache
366
+ m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t >(1 );
367
+ m_hwp_regs[wp_index].address = 0 ;
368
+ m_hwp_regs[wp_index].slot = 0 ;
369
+ m_hwp_regs[wp_index].mode = 0 ;
370
+
371
+ // Ptrace call to update hardware debug registers
372
+ error = NativeProcessLinux::PtraceWrapper (PPC_PTRACE_DELHWDEBUG,
373
+ m_thread.GetID (), 0 , tempSlot);
374
+
375
+ if (error.Fail ()) {
376
+ m_hwp_regs[wp_index].control = tempControl;
377
+ m_hwp_regs[wp_index].address = tempAddr;
378
+ m_hwp_regs[wp_index].slot = reinterpret_cast <long >(tempSlot);
379
+
380
+ return false ;
381
+ }
382
+
383
+ return true ;
384
+ }
385
+
386
+ uint32_t
387
+ NativeRegisterContextLinux_ppc64le::GetWatchpointSize (uint32_t wp_index) {
388
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
389
+ LLDB_LOG (log , " wp_index: {0}" , wp_index);
390
+
391
+ unsigned control = (m_hwp_regs[wp_index].control >> 5 ) & 0xff ;
392
+ assert (llvm::isPowerOf2_32 (control + 1 ));
393
+ return llvm::countPopulation (control);
394
+ }
395
+
396
+ bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled (
397
+ uint32_t wp_index) {
398
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
399
+ LLDB_LOG (log , " wp_index: {0}" , wp_index);
400
+
401
+ return !!((m_hwp_regs[wp_index].control & 0x1 ) == 0x1 );
402
+ }
403
+
404
+ Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex (
405
+ uint32_t &wp_index, lldb::addr_t trap_addr) {
406
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
407
+ LLDB_LOG (log , " wp_index: {0}, trap_addr: {1:x}" , wp_index, trap_addr);
408
+
409
+ uint32_t watch_size;
410
+ lldb::addr_t watch_addr;
411
+
412
+ for (wp_index = 0 ; wp_index < m_max_hwp_supported; ++wp_index) {
413
+ watch_size = GetWatchpointSize (wp_index);
414
+ watch_addr = m_hwp_regs[wp_index].address ;
415
+
416
+ if (WatchpointIsEnabled (wp_index) && trap_addr >= watch_addr &&
417
+ trap_addr <= watch_addr + watch_size) {
418
+ m_hwp_regs[wp_index].hit_addr = trap_addr;
419
+ return Status ();
420
+ }
421
+ }
422
+
423
+ wp_index = LLDB_INVALID_INDEX32;
424
+ return Status ();
425
+ }
426
+
427
+ lldb::addr_t
428
+ NativeRegisterContextLinux_ppc64le::GetWatchpointAddress (uint32_t wp_index) {
429
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
430
+ LLDB_LOG (log , " wp_index: {0}" , wp_index);
431
+
432
+ if (wp_index >= m_max_hwp_supported)
433
+ return LLDB_INVALID_ADDRESS;
434
+
435
+ if (WatchpointIsEnabled (wp_index))
436
+ return m_hwp_regs[wp_index].real_addr ;
437
+ else
438
+ return LLDB_INVALID_ADDRESS;
439
+ }
440
+
441
+ lldb::addr_t
442
+ NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress (uint32_t wp_index) {
443
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_WATCHPOINTS));
444
+ LLDB_LOG (log , " wp_index: {0}" , wp_index);
445
+
446
+ if (wp_index >= m_max_hwp_supported)
447
+ return LLDB_INVALID_ADDRESS;
448
+
449
+ if (WatchpointIsEnabled (wp_index))
450
+ return m_hwp_regs[wp_index].hit_addr ;
451
+
452
+ return LLDB_INVALID_ADDRESS;
453
+ }
454
+
455
+ Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo () {
456
+ if (!m_refresh_hwdebug_info) {
457
+ return Status ();
458
+ }
459
+
460
+ ::pid_t tid = m_thread.GetID ();
461
+
462
+ struct ppc_debug_info hwdebug_info;
463
+ Status error;
464
+
465
+ error = NativeProcessLinux::PtraceWrapper (
466
+ PPC_PTRACE_GETHWDBGINFO, tid, 0 , &hwdebug_info, sizeof (hwdebug_info));
467
+
468
+ if (error.Fail ())
469
+ return error;
470
+
471
+ m_max_hwp_supported = hwdebug_info.num_data_bps ;
472
+ m_max_hbp_supported = hwdebug_info.num_instruction_bps ;
473
+ m_refresh_hwdebug_info = false ;
474
+
475
+ return error;
476
+ }
477
+
478
+ Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs () {
479
+ struct ppc_hw_breakpoint reg_state;
480
+ Status error;
481
+ long ret;
482
+
483
+ for (uint32_t i = 0 ; i < m_max_hwp_supported; i++) {
484
+ reg_state.addr = m_hwp_regs[i].address ;
485
+ reg_state.trigger_type = m_hwp_regs[i].mode ;
486
+ reg_state.version = 1 ;
487
+ reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
488
+ reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
489
+ reg_state.addr2 = 0 ;
490
+ reg_state.condition_value = 0 ;
491
+
492
+ error = NativeProcessLinux::PtraceWrapper (PPC_PTRACE_SETHWDEBUG,
493
+ m_thread.GetID (), 0 , ®_state,
494
+ sizeof (reg_state), &ret);
495
+
496
+ if (error.Fail ())
497
+ return error;
498
+
499
+ m_hwp_regs[i].slot = ret;
500
+ }
501
+
502
+ return error;
503
+ }
504
+
245
505
#endif // defined(__powerpc64__)
0 commit comments