2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
6 #include "BreakpointManager.h"
10 #include <AutoDeleter.h>
13 #include <util/AutoLock.h>
17 //#define TRACE_BREAKPOINT_MANAGER
18 #ifdef TRACE_BREAKPOINT_MANAGER
19 # define TRACE(x...) dprintf(x)
21 # define TRACE(x...) do {} while (false)
25 // soft limit for the number of breakpoints
26 const int32 kMaxBreakpointCount
= 10240;
29 BreakpointManager::InstalledBreakpoint::InstalledBreakpoint(addr_t address
)
40 BreakpointManager::BreakpointManager()
45 rw_lock_init(&fLock
, "breakpoint manager");
49 BreakpointManager::~BreakpointManager()
51 WriteLocker
locker(fLock
);
53 // delete the installed breakpoint objects
54 BreakpointTree::Iterator it
= fBreakpoints
.GetIterator();
55 while (InstalledBreakpoint
* installedBreakpoint
= it
.Next()) {
58 // delete underlying software breakpoint
59 if (installedBreakpoint
->breakpoint
->software
)
60 delete installedBreakpoint
->breakpoint
;
62 delete installedBreakpoint
;
65 // delete the watchpoints
66 while (InstalledWatchpoint
* watchpoint
= fWatchpoints
.RemoveHead())
69 // delete the hardware breakpoint objects
70 while (Breakpoint
* breakpoint
= fHardwareBreakpoints
.RemoveHead())
73 rw_lock_destroy(&fLock
);
78 BreakpointManager::Init()
80 // create objects for the hardware breakpoints
81 for (int32 i
= 0; i
< DEBUG_MAX_BREAKPOINTS
; i
++) {
82 Breakpoint
* breakpoint
= new(std::nothrow
) Breakpoint
;
83 if (breakpoint
== NULL
)
86 breakpoint
->address
= 0;
87 breakpoint
->installedBreakpoint
= NULL
;
88 breakpoint
->used
= false;
89 breakpoint
->software
= false;
91 fHardwareBreakpoints
.Add(breakpoint
);
99 BreakpointManager::InstallBreakpoint(void* _address
)
101 const addr_t address
= (addr_t
)_address
;
103 WriteLocker
locker(fLock
);
105 if (fBreakpointCount
>= kMaxBreakpointCount
)
108 // check whether there's already a breakpoint at the address
109 InstalledBreakpoint
* installed
= fBreakpoints
.Lookup(address
);
110 if (installed
!= NULL
)
113 // create the breakpoint object
114 installed
= new(std::nothrow
) InstalledBreakpoint(address
);
115 if (installed
== NULL
)
117 ObjectDeleter
<InstalledBreakpoint
> installedDeleter(installed
);
119 // If we still have enough hardware breakpoints left, install a hardware
121 Breakpoint
* breakpoint
= _GetUnusedHardwareBreakpoint(false);
122 if (breakpoint
!= NULL
) {
123 status_t error
= _InstallHardwareBreakpoint(breakpoint
, address
);
127 breakpoint
->installedBreakpoint
= installed
;
128 installed
->breakpoint
= breakpoint
;
130 // install a software breakpoint
131 status_t error
= _InstallSoftwareBreakpoint(installed
, address
);
136 fBreakpoints
.Insert(installed
);
137 installedDeleter
.Detach();
145 BreakpointManager::UninstallBreakpoint(void* _address
)
147 const addr_t address
= (addr_t
)_address
;
149 WriteLocker
locker(fLock
);
151 InstalledBreakpoint
* installed
= fBreakpoints
.Lookup(address
);
152 if (installed
== NULL
)
155 if (installed
->breakpoint
->software
)
156 _UninstallSoftwareBreakpoint(installed
->breakpoint
);
158 _UninstallHardwareBreakpoint(installed
->breakpoint
);
160 fBreakpoints
.Remove(installed
);
169 BreakpointManager::InstallWatchpoint(void* _address
, uint32 type
, int32 length
)
171 const addr_t address
= (addr_t
)_address
;
173 WriteLocker
locker(fLock
);
175 InstalledWatchpoint
* watchpoint
= _FindWatchpoint(address
);
176 if (watchpoint
!= NULL
)
179 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
180 // We need at least one hardware breakpoint for our breakpoint management.
181 if (fWatchpointCount
+ 1 >= DEBUG_MAX_WATCHPOINTS
)
184 if (fWatchpointCount
>= DEBUG_MAX_WATCHPOINTS
)
188 watchpoint
= new(std::nothrow
) InstalledWatchpoint
;
189 if (watchpoint
== NULL
)
191 ObjectDeleter
<InstalledWatchpoint
> watchpointDeleter(watchpoint
);
193 status_t error
= _InstallWatchpoint(watchpoint
, address
, type
, length
);
197 fWatchpoints
.Add(watchpointDeleter
.Detach());
204 BreakpointManager::UninstallWatchpoint(void* address
)
206 WriteLocker
locker(fLock
);
208 InstalledWatchpoint
* watchpoint
= _FindWatchpoint((addr_t
)address
);
209 if (watchpoint
== NULL
)
212 ObjectDeleter
<InstalledWatchpoint
> deleter(watchpoint
);
213 fWatchpoints
.Remove(watchpoint
);
216 return _UninstallWatchpoint(watchpoint
);
221 BreakpointManager::RemoveAllBreakpoints()
223 WriteLocker
locker(fLock
);
225 // remove the breakpoints
226 BreakpointTree::Iterator it
= fBreakpoints
.GetIterator();
227 while (InstalledBreakpoint
* installedBreakpoint
= it
.Next()) {
230 // uninstall underlying hard/software breakpoint
231 if (installedBreakpoint
->breakpoint
->software
)
232 _UninstallSoftwareBreakpoint(installedBreakpoint
->breakpoint
);
234 _UninstallHardwareBreakpoint(installedBreakpoint
->breakpoint
);
236 delete installedBreakpoint
;
239 // remove the watchpoints
240 while (InstalledWatchpoint
* watchpoint
= fWatchpoints
.RemoveHead()) {
241 _UninstallWatchpoint(watchpoint
);
247 /*! \brief Returns whether the given address can be accessed in principle.
248 No check whether there's an actually accessible area is performed, though.
251 BreakpointManager::CanAccessAddress(const void* _address
, bool write
)
253 const addr_t address
= (addr_t
)_address
;
255 // user addresses are always fine
256 if (IS_USER_ADDRESS(address
))
263 /*! \brief Reads data from user memory.
265 Tries to read \a size bytes of data from user memory address \a address
266 into the supplied buffer \a buffer. If only a part could be read the
267 function won't fail. The number of bytes actually read is return through
270 \param address The user memory address from which to read.
271 \param buffer The buffer into which to write.
272 \param size The number of bytes to read.
273 \param bytesRead Will be set to the number of bytes actually read.
274 \return \c B_OK, if reading went fine. Then \a bytesRead will be set to
275 the amount of data actually read. An error indicates that nothing
279 BreakpointManager::ReadMemory(const void* _address
, void* buffer
, size_t size
,
282 const addr_t address
= (addr_t
)_address
;
284 ReadLocker
locker(fLock
);
286 status_t error
= _ReadMemory(address
, buffer
, size
, bytesRead
);
290 // If we have software breakpoints installed, fix the buffer not to contain
293 // address of the first possibly intersecting software breakpoint
294 const addr_t startAddress
295 = std::max(address
, (addr_t
)DEBUG_SOFTWARE_BREAKPOINT_SIZE
- 1)
296 - (DEBUG_SOFTWARE_BREAKPOINT_SIZE
- 1);
298 BreakpointTree::Iterator it
= fBreakpoints
.GetIterator(startAddress
, true,
300 while (InstalledBreakpoint
* installed
= it
.Next()) {
301 Breakpoint
* breakpoint
= installed
->breakpoint
;
302 if (breakpoint
->address
>= address
+ size
)
305 if (breakpoint
->software
) {
306 // Software breakpoint intersects -- replace the read data with
307 // the data saved in the breakpoint object.
308 addr_t minAddress
= std::max(breakpoint
->address
, address
);
309 size_t toCopy
= std::min(address
+ size
,
310 breakpoint
->address
+ DEBUG_SOFTWARE_BREAKPOINT_SIZE
)
312 memcpy((uint8
*)buffer
+ (minAddress
- address
),
313 breakpoint
->softwareData
+ (minAddress
- breakpoint
->address
),
323 BreakpointManager::WriteMemory(void* _address
, const void* _buffer
, size_t size
,
324 size_t& bytesWritten
)
331 addr_t address
= (addr_t
)_address
;
332 const uint8
* buffer
= (uint8
*)_buffer
;
334 WriteLocker
locker(fLock
);
336 // We don't want to overwrite software breakpoints, so things are a bit more
337 // complicated. We iterate through the intersecting software breakpoints,
338 // writing the memory between them normally, but skipping the breakpoints
339 // itself. We write into their softwareData instead.
341 // Get the first breakpoint -- if it starts before the address, we'll
342 // handle it separately to make things in the main loop simpler.
343 const addr_t startAddress
344 = std::max(address
, (addr_t
)DEBUG_SOFTWARE_BREAKPOINT_SIZE
- 1)
345 - (DEBUG_SOFTWARE_BREAKPOINT_SIZE
- 1);
347 BreakpointTree::Iterator it
= fBreakpoints
.GetIterator(startAddress
, true,
349 InstalledBreakpoint
* installed
= it
.Next();
350 while (installed
!= NULL
) {
351 Breakpoint
* breakpoint
= installed
->breakpoint
;
352 if (breakpoint
->address
>= address
)
355 if (breakpoint
->software
) {
356 // We've got a breakpoint that is partially intersecting with the
357 // beginning of the address range to write.
358 size_t toCopy
= std::min(address
+ size
,
359 breakpoint
->address
+ DEBUG_SOFTWARE_BREAKPOINT_SIZE
)
361 memcpy(breakpoint
->softwareData
+ (address
- breakpoint
->address
),
366 bytesWritten
+= toCopy
;
370 installed
= it
.Next();
373 // loop through the breakpoints intersecting with the range
374 while (installed
!= NULL
) {
375 Breakpoint
* breakpoint
= installed
->breakpoint
;
376 if (breakpoint
->address
>= address
+ size
)
379 if (breakpoint
->software
) {
380 // write the data up to the breakpoint (if any)
381 size_t toCopy
= breakpoint
->address
- address
;
384 status_t error
= _WriteMemory(address
, buffer
, toCopy
,
387 return bytesWritten
> 0 ? B_OK
: error
;
389 address
+= chunkWritten
;
390 size
-= chunkWritten
;
391 bytesWritten
+= chunkWritten
;
392 buffer
+= chunkWritten
;
394 if (chunkWritten
< toCopy
)
398 // write to the breakpoint data
399 toCopy
= std::min(size
, (size_t)DEBUG_SOFTWARE_BREAKPOINT_SIZE
);
400 memcpy(breakpoint
->softwareData
, buffer
, toCopy
);
404 bytesWritten
+= toCopy
;
408 installed
= it
.Next();
411 // write remaining data
414 status_t error
= _WriteMemory(address
, buffer
, size
, chunkWritten
);
416 return bytesWritten
> 0 ? B_OK
: error
;
418 bytesWritten
+= chunkWritten
;
426 BreakpointManager::PrepareToContinue(void* _address
)
428 const addr_t address
= (addr_t
)_address
;
430 WriteLocker
locker(fLock
);
432 // Check whether there's a software breakpoint at the continuation address.
433 InstalledBreakpoint
* installed
= fBreakpoints
.Lookup(address
);
434 if (installed
== NULL
|| !installed
->breakpoint
->software
)
437 // We need to replace the software breakpoint by a hardware one, or
438 // we can't continue the thread.
439 Breakpoint
* breakpoint
= _GetUnusedHardwareBreakpoint(true);
440 if (breakpoint
== NULL
) {
441 dprintf("Failed to allocate a hardware breakpoint.\n");
445 status_t error
= _InstallHardwareBreakpoint(breakpoint
, address
);
449 _UninstallSoftwareBreakpoint(installed
->breakpoint
);
451 breakpoint
->installedBreakpoint
= installed
;
452 installed
->breakpoint
= breakpoint
;
456 BreakpointManager::Breakpoint
*
457 BreakpointManager::_GetUnusedHardwareBreakpoint(bool force
)
459 // try to find a free one first
460 for (BreakpointList::Iterator it
= fHardwareBreakpoints
.GetIterator();
461 Breakpoint
* breakpoint
= it
.Next();) {
462 if (!breakpoint
->used
)
469 // replace one by a software breakpoint
470 for (BreakpointList::Iterator it
= fHardwareBreakpoints
.GetIterator();
471 Breakpoint
* breakpoint
= it
.Next();) {
472 if (breakpoint
->installedBreakpoint
== NULL
)
475 status_t error
= _InstallSoftwareBreakpoint(
476 breakpoint
->installedBreakpoint
, breakpoint
->address
);
480 if (_UninstallHardwareBreakpoint(breakpoint
) == B_OK
)
489 BreakpointManager::_InstallSoftwareBreakpoint(InstalledBreakpoint
* installed
,
492 Breakpoint
* breakpoint
= new(std::nothrow
) Breakpoint
;
493 if (breakpoint
== NULL
)
495 ObjectDeleter
<Breakpoint
> breakpointDeleter(breakpoint
);
497 breakpoint
->address
= address
;
498 breakpoint
->installedBreakpoint
= installed
;
499 breakpoint
->used
= true;
500 breakpoint
->software
= true;
502 // save the memory where the software breakpoint shall be installed
503 size_t bytesTransferred
;
504 status_t error
= _ReadMemory(address
, breakpoint
->softwareData
,
505 DEBUG_SOFTWARE_BREAKPOINT_SIZE
, bytesTransferred
);
508 if (bytesTransferred
!= DEBUG_SOFTWARE_BREAKPOINT_SIZE
)
509 return B_BAD_ADDRESS
;
511 // write the breakpoint code
512 error
= _WriteMemory(address
, DEBUG_SOFTWARE_BREAKPOINT
,
513 DEBUG_SOFTWARE_BREAKPOINT_SIZE
, bytesTransferred
);
517 if (bytesTransferred
< DEBUG_SOFTWARE_BREAKPOINT_SIZE
) {
518 // breakpoint written partially only -- undo the written part
519 if (bytesTransferred
> 0) {
521 _WriteMemory(address
, breakpoint
->softwareData
, bytesTransferred
,
524 return B_BAD_ADDRESS
;
527 installed
->breakpoint
= breakpoint
;
528 breakpointDeleter
.Detach();
530 TRACE("installed software breakpoint at %#lx\n", address
);
537 BreakpointManager::_UninstallSoftwareBreakpoint(Breakpoint
* breakpoint
)
540 _WriteMemory(breakpoint
->address
, breakpoint
->softwareData
,
541 DEBUG_SOFTWARE_BREAKPOINT_SIZE
, bytesWritten
);
543 TRACE("uninstalled software breakpoint at %#lx\n", breakpoint
->address
);
551 BreakpointManager::_InstallHardwareBreakpoint(Breakpoint
* breakpoint
,
554 status_t error
= arch_set_breakpoint((void*)address
);
558 // move to the tail of the list
559 fHardwareBreakpoints
.Remove(breakpoint
);
560 fHardwareBreakpoints
.Add(breakpoint
);
562 TRACE("installed hardware breakpoint at %#lx\n", address
);
564 breakpoint
->address
= address
;
565 breakpoint
->used
= true;
571 BreakpointManager::_UninstallHardwareBreakpoint(Breakpoint
* breakpoint
)
573 status_t error
= arch_clear_breakpoint((void*)breakpoint
->address
);
577 TRACE("uninstalled hardware breakpoint at %#lx\n", breakpoint
->address
);
579 breakpoint
->used
= false;
580 breakpoint
->installedBreakpoint
= NULL
;
585 BreakpointManager::InstalledWatchpoint
*
586 BreakpointManager::_FindWatchpoint(addr_t address
) const
588 for (InstalledWatchpointList::ConstIterator it
= fWatchpoints
.GetIterator();
589 InstalledWatchpoint
* watchpoint
= it
.Next();) {
590 if (address
== watchpoint
->address
)
599 BreakpointManager::_InstallWatchpoint(InstalledWatchpoint
* watchpoint
,
600 addr_t address
, uint32 type
, int32 length
)
602 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
603 // We need a hardware breakpoint.
604 watchpoint
->breakpoint
= _GetUnusedHardwareBreakpoint(true);
605 if (watchpoint
->breakpoint
== NULL
) {
606 dprintf("Failed to allocate a hardware breakpoint for watchpoint.\n");
611 status_t error
= arch_set_watchpoint((void*)address
, type
, length
);
615 watchpoint
->address
= address
;
617 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
618 watchpoint
->breakpoint
->used
= true;
626 BreakpointManager::_UninstallWatchpoint(InstalledWatchpoint
* watchpoint
)
628 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
629 watchpoint
->breakpoint
->used
= false;
632 return arch_clear_watchpoint((void*)watchpoint
->address
);
637 BreakpointManager::_ReadMemory(const addr_t _address
, void* _buffer
,
638 size_t size
, size_t& bytesRead
)
640 const uint8
* address
= (const uint8
*)_address
;
641 uint8
* buffer
= (uint8
*)_buffer
;
643 // check the parameters
644 if (!CanAccessAddress(address
, false))
645 return B_BAD_ADDRESS
;
649 // If the region to be read crosses page boundaries, we split it up into
651 status_t error
= B_OK
;
654 // check whether we're still in user address space
655 if (!CanAccessAddress(address
, false)) {
656 error
= B_BAD_ADDRESS
;
660 // don't cross page boundaries in a single read
662 int32 maxRead
= B_PAGE_SIZE
- (addr_t
)address
% B_PAGE_SIZE
;
663 if (toRead
> maxRead
)
666 error
= user_memcpy(buffer
, address
, toRead
);
676 // If reading fails, we only fail, if we haven't read anything yet.
688 BreakpointManager::_WriteMemory(addr_t _address
, const void* _buffer
,
689 size_t size
, size_t& bytesWritten
)
691 uint8
* address
= (uint8
*)_address
;
692 const uint8
* buffer
= (const uint8
*)_buffer
;
694 // check the parameters
695 if (!CanAccessAddress(address
, true))
696 return B_BAD_ADDRESS
;
700 // If the region to be written crosses area boundaries, we split it up into
702 status_t error
= B_OK
;
705 // check whether we're still in user address space
706 if (!CanAccessAddress(address
, true)) {
707 error
= B_BAD_ADDRESS
;
711 // get the area for the address (we need to use _user_area_for(), since
712 // we're looking for a user area)
713 area_id area
= _user_area_for(address
);
715 TRACE("BreakpointManager::_WriteMemory(): area not found for "
716 "address: %p: %lx\n", address
, area
);
722 status_t error
= get_area_info(area
, &areaInfo
);
724 TRACE("BreakpointManager::_WriteMemory(): failed to get info for "
725 "area %ld: %lx\n", area
, error
);
726 error
= B_BAD_ADDRESS
;
730 // restrict this round of writing to the found area
731 int32 toWrite
= size
;
732 int32 maxWrite
= (uint8
*)areaInfo
.address
+ areaInfo
.size
- address
;
733 if (toWrite
> maxWrite
)
736 // if the area is read-only, we temporarily need to make it writable
737 bool protectionChanged
= false;
738 if (!(areaInfo
.protection
& (B_WRITE_AREA
| B_KERNEL_WRITE_AREA
))) {
739 error
= set_area_protection(area
,
740 areaInfo
.protection
| B_WRITE_AREA
);
742 TRACE("BreakpointManager::_WriteMemory(): failed to set new "
743 "protection for area %ld: %lx\n", area
, error
);
746 protectionChanged
= true;
750 error
= user_memcpy(address
, buffer
, toWrite
);
752 // reset the area protection
753 if (protectionChanged
)
754 set_area_protection(area
, areaInfo
.protection
);
757 TRACE("BreakpointManager::_WriteMemory(): user_memcpy() failed: "
762 bytesWritten
+= toWrite
;
768 // If writing fails, we only fail, if we haven't written anything yet.
770 if (bytesWritten
> 0)