1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include "BreakpointManager.h"
7
8 #include <algorithm>
9
10 #include <AutoDeleter.h>
11
12 #include <kernel.h>
13 #include <util/AutoLock.h>
14 #include <vm/vm.h>
15
16
17 //#define TRACE_BREAKPOINT_MANAGER
18 #ifdef TRACE_BREAKPOINT_MANAGER
19 # define TRACE(x...) dprintf(x)
20 #else
21 # define TRACE(x...) do {} while (false)
22 #endif
23
24
25 // soft limit for the number of breakpoints
26 const int32 kMaxBreakpointCount = 10240;
27
28
InstalledBreakpoint(addr_t address)29 BreakpointManager::InstalledBreakpoint::InstalledBreakpoint(addr_t address)
30 :
31 breakpoint(NULL),
32 address(address)
33 {
34 }
35
36
37 // #pragma mark -
38
39
BreakpointManager()40 BreakpointManager::BreakpointManager()
41 :
42 fBreakpointCount(0),
43 fWatchpointCount(0)
44 {
45 rw_lock_init(&fLock, "breakpoint manager");
46 }
47
48
~BreakpointManager()49 BreakpointManager::~BreakpointManager()
50 {
51 WriteLocker locker(fLock);
52
53 // delete the installed breakpoint objects
54 BreakpointTree::Iterator it = fBreakpoints.GetIterator();
55 while (InstalledBreakpoint* installedBreakpoint = it.Next()) {
56 it.Remove();
57
58 // delete underlying software breakpoint
59 if (installedBreakpoint->breakpoint->software)
60 delete installedBreakpoint->breakpoint;
61
62 delete installedBreakpoint;
63 }
64
65 // delete the watchpoints
66 while (InstalledWatchpoint* watchpoint = fWatchpoints.RemoveHead())
67 delete watchpoint;
68
69 // delete the hardware breakpoint objects
70 while (Breakpoint* breakpoint = fHardwareBreakpoints.RemoveHead())
71 delete breakpoint;
72
73 rw_lock_destroy(&fLock);
74 }
75
76
77 status_t
Init()78 BreakpointManager::Init()
79 {
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)
84 return B_NO_MEMORY;
85
86 breakpoint->address = 0;
87 breakpoint->installedBreakpoint = NULL;
88 breakpoint->used = false;
89 breakpoint->software = false;
90
91 fHardwareBreakpoints.Add(breakpoint);
92 }
93
94 return B_OK;
95 }
96
97
98 status_t
InstallBreakpoint(void * _address)99 BreakpointManager::InstallBreakpoint(void* _address)
100 {
101 const addr_t address = (addr_t)_address;
102
103 WriteLocker locker(fLock);
104
105 if (fBreakpointCount >= kMaxBreakpointCount)
106 return B_BUSY;
107
108 // check whether there's already a breakpoint at the address
109 InstalledBreakpoint* installed = fBreakpoints.Lookup(address);
110 if (installed != NULL)
111 return B_BAD_VALUE;
112
113 // create the breakpoint object
114 installed = new(std::nothrow) InstalledBreakpoint(address);
115 if (installed == NULL)
116 return B_NO_MEMORY;
117 ObjectDeleter<InstalledBreakpoint> installedDeleter(installed);
118
119 // If we still have enough hardware breakpoints left, install a hardware
120 // breakpoint.
121 Breakpoint* breakpoint = _GetUnusedHardwareBreakpoint(false);
122 if (breakpoint != NULL) {
123 status_t error = _InstallHardwareBreakpoint(breakpoint, address);
124 if (error != B_OK)
125 return error;
126
127 breakpoint->installedBreakpoint = installed;
128 installed->breakpoint = breakpoint;
129 } else {
130 // install a software breakpoint
131 status_t error = _InstallSoftwareBreakpoint(installed, address);
132 if (error != B_OK)
133 return error;
134 }
135
136 fBreakpoints.Insert(installed);
137 installedDeleter.Detach();
138 fBreakpointCount++;
139
140 return B_OK;
141 }
142
143
144 status_t
UninstallBreakpoint(void * _address)145 BreakpointManager::UninstallBreakpoint(void* _address)
146 {
147 const addr_t address = (addr_t)_address;
148
149 WriteLocker locker(fLock);
150
151 InstalledBreakpoint* installed = fBreakpoints.Lookup(address);
152 if (installed == NULL)
153 return B_BAD_VALUE;
154
155 if (installed->breakpoint->software)
156 _UninstallSoftwareBreakpoint(installed->breakpoint);
157 else
158 _UninstallHardwareBreakpoint(installed->breakpoint);
159
160 fBreakpoints.Remove(installed);
161 delete installed;
162 fBreakpointCount--;
163
164 return B_OK;
165 }
166
167
168 status_t
InstallWatchpoint(void * _address,uint32 type,int32 length)169 BreakpointManager::InstallWatchpoint(void* _address, uint32 type, int32 length)
170 {
171 const addr_t address = (addr_t)_address;
172
173 WriteLocker locker(fLock);
174
175 InstalledWatchpoint* watchpoint = _FindWatchpoint(address);
176 if (watchpoint != NULL)
177 return B_BAD_VALUE;
178
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)
182 return B_BUSY;
183 #else
184 if (fWatchpointCount >= DEBUG_MAX_WATCHPOINTS)
185 return B_BUSY;
186 #endif
187
188 watchpoint = new(std::nothrow) InstalledWatchpoint;
189 if (watchpoint == NULL)
190 return B_NO_MEMORY;
191 ObjectDeleter<InstalledWatchpoint> watchpointDeleter(watchpoint);
192
193 status_t error = _InstallWatchpoint(watchpoint, address, type, length);
194 if (error != B_OK)
195 return error;
196
197 fWatchpoints.Add(watchpointDeleter.Detach());
198 fWatchpointCount++;
199 return B_OK;
200 }
201
202
203 status_t
UninstallWatchpoint(void * address)204 BreakpointManager::UninstallWatchpoint(void* address)
205 {
206 WriteLocker locker(fLock);
207
208 InstalledWatchpoint* watchpoint = _FindWatchpoint((addr_t)address);
209 if (watchpoint == NULL)
210 return B_BAD_VALUE;
211
212 ObjectDeleter<InstalledWatchpoint> deleter(watchpoint);
213 fWatchpoints.Remove(watchpoint);
214 fWatchpointCount--;
215
216 return _UninstallWatchpoint(watchpoint);
217 }
218
219
220 void
RemoveAllBreakpoints()221 BreakpointManager::RemoveAllBreakpoints()
222 {
223 WriteLocker locker(fLock);
224
225 // remove the breakpoints
226 BreakpointTree::Iterator it = fBreakpoints.GetIterator();
227 while (InstalledBreakpoint* installedBreakpoint = it.Next()) {
228 it.Remove();
229
230 // uninstall underlying hard/software breakpoint
231 if (installedBreakpoint->breakpoint->software)
232 _UninstallSoftwareBreakpoint(installedBreakpoint->breakpoint);
233 else
234 _UninstallHardwareBreakpoint(installedBreakpoint->breakpoint);
235
236 delete installedBreakpoint;
237 }
238
239 // remove the watchpoints
240 while (InstalledWatchpoint* watchpoint = fWatchpoints.RemoveHead()) {
241 _UninstallWatchpoint(watchpoint);
242 delete watchpoint;
243 }
244 }
245
246
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.
249 */
250 /*static*/ bool
CanAccessAddress(const void * _address,bool write)251 BreakpointManager::CanAccessAddress(const void* _address, bool write)
252 {
253 const addr_t address = (addr_t)_address;
254
255 // user addresses are always fine
256 if (IS_USER_ADDRESS(address))
257 return true;
258
259 return false;
260 }
261
262
263 /*! \brief Reads data from user memory.
264
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
268 \a bytesRead.
269
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
276 has been read.
277 */
278 status_t
ReadMemory(const void * _address,void * buffer,size_t size,size_t & bytesRead)279 BreakpointManager::ReadMemory(const void* _address, void* buffer, size_t size,
280 size_t& bytesRead)
281 {
282 const addr_t address = (addr_t)_address;
283
284 ReadLocker locker(fLock);
285
286 status_t error = _ReadMemory(address, buffer, size, bytesRead);
287 if (error != B_OK)
288 return error;
289
290 // If we have software breakpoints installed, fix the buffer not to contain
291 // any of them.
292
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);
297
298 BreakpointTree::Iterator it = fBreakpoints.GetIterator(startAddress, true,
299 true);
300 while (InstalledBreakpoint* installed = it.Next()) {
301 Breakpoint* breakpoint = installed->breakpoint;
302 if (breakpoint->address >= address + size)
303 break;
304
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)
311 - minAddress;
312 memcpy((uint8*)buffer + (minAddress - address),
313 breakpoint->softwareData + (minAddress - breakpoint->address),
314 toCopy);
315 }
316 }
317
318 return B_OK;
319 }
320
321
322 status_t
WriteMemory(void * _address,const void * _buffer,size_t size,size_t & bytesWritten)323 BreakpointManager::WriteMemory(void* _address, const void* _buffer, size_t size,
324 size_t& bytesWritten)
325 {
326 bytesWritten = 0;
327
328 if (size == 0)
329 return B_OK;
330
331 addr_t address = (addr_t)_address;
332 const uint8* buffer = (uint8*)_buffer;
333
334 WriteLocker locker(fLock);
335
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.
340
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);
346
347 BreakpointTree::Iterator it = fBreakpoints.GetIterator(startAddress, true,
348 true);
349 InstalledBreakpoint* installed = it.Next();
350 while (installed != NULL) {
351 Breakpoint* breakpoint = installed->breakpoint;
352 if (breakpoint->address >= address)
353 break;
354
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)
360 - address;
361 memcpy(breakpoint->softwareData + (address - breakpoint->address),
362 buffer, toCopy);
363
364 address += toCopy;
365 size -= toCopy;
366 bytesWritten += toCopy;
367 buffer += toCopy;
368 }
369
370 installed = it.Next();
371 }
372
373 // loop through the breakpoints intersecting with the range
374 while (installed != NULL) {
375 Breakpoint* breakpoint = installed->breakpoint;
376 if (breakpoint->address >= address + size)
377 break;
378
379 if (breakpoint->software) {
380 // write the data up to the breakpoint (if any)
381 size_t toCopy = breakpoint->address - address;
382 if (toCopy > 0) {
383 size_t chunkWritten;
384 status_t error = _WriteMemory(address, buffer, toCopy,
385 chunkWritten);
386 if (error != B_OK)
387 return bytesWritten > 0 ? B_OK : error;
388
389 address += chunkWritten;
390 size -= chunkWritten;
391 bytesWritten += chunkWritten;
392 buffer += chunkWritten;
393
394 if (chunkWritten < toCopy)
395 return B_OK;
396 }
397
398 // write to the breakpoint data
399 toCopy = std::min(size, (size_t)DEBUG_SOFTWARE_BREAKPOINT_SIZE);
400 memcpy(breakpoint->softwareData, buffer, toCopy);
401
402 address += toCopy;
403 size -= toCopy;
404 bytesWritten += toCopy;
405 buffer += toCopy;
406 }
407
408 installed = it.Next();
409 }
410
411 // write remaining data
412 if (size > 0) {
413 size_t chunkWritten;
414 status_t error = _WriteMemory(address, buffer, size, chunkWritten);
415 if (error != B_OK)
416 return bytesWritten > 0 ? B_OK : error;
417
418 bytesWritten += chunkWritten;
419 }
420
421 return B_OK;
422 }
423
424
425 void
PrepareToContinue(void * _address)426 BreakpointManager::PrepareToContinue(void* _address)
427 {
428 const addr_t address = (addr_t)_address;
429
430 WriteLocker locker(fLock);
431
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)
435 return;
436
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");
442 return;
443 }
444
445 status_t error = _InstallHardwareBreakpoint(breakpoint, address);
446 if (error != B_OK)
447 return;
448
449 _UninstallSoftwareBreakpoint(installed->breakpoint);
450
451 breakpoint->installedBreakpoint = installed;
452 installed->breakpoint = breakpoint;
453 }
454
455
456 BreakpointManager::Breakpoint*
_GetUnusedHardwareBreakpoint(bool force)457 BreakpointManager::_GetUnusedHardwareBreakpoint(bool force)
458 {
459 // try to find a free one first
460 for (BreakpointList::Iterator it = fHardwareBreakpoints.GetIterator();
461 Breakpoint* breakpoint = it.Next();) {
462 if (!breakpoint->used)
463 return breakpoint;
464 }
465
466 if (!force)
467 return NULL;
468
469 // replace one by a software breakpoint
470 for (BreakpointList::Iterator it = fHardwareBreakpoints.GetIterator();
471 Breakpoint* breakpoint = it.Next();) {
472 if (breakpoint->installedBreakpoint == NULL)
473 continue;
474
475 status_t error = _InstallSoftwareBreakpoint(
476 breakpoint->installedBreakpoint, breakpoint->address);
477 if (error != B_OK)
478 continue;
479
480 if (_UninstallHardwareBreakpoint(breakpoint) == B_OK)
481 return breakpoint;
482 }
483
484 return NULL;
485 }
486
487
488 status_t
_InstallSoftwareBreakpoint(InstalledBreakpoint * installed,addr_t address)489 BreakpointManager::_InstallSoftwareBreakpoint(InstalledBreakpoint* installed,
490 addr_t address)
491 {
492 Breakpoint* breakpoint = new(std::nothrow) Breakpoint;
493 if (breakpoint == NULL)
494 return B_NO_MEMORY;
495 ObjectDeleter<Breakpoint> breakpointDeleter(breakpoint);
496
497 breakpoint->address = address;
498 breakpoint->installedBreakpoint = installed;
499 breakpoint->used = true;
500 breakpoint->software = true;
501
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);
506 if (error != B_OK)
507 return error;
508 if (bytesTransferred != DEBUG_SOFTWARE_BREAKPOINT_SIZE)
509 return B_BAD_ADDRESS;
510
511 // write the breakpoint code
512 error = _WriteMemory(address, DEBUG_SOFTWARE_BREAKPOINT,
513 DEBUG_SOFTWARE_BREAKPOINT_SIZE, bytesTransferred);
514 if (error != B_OK)
515 return error;
516
517 if (bytesTransferred < DEBUG_SOFTWARE_BREAKPOINT_SIZE) {
518 // breakpoint written partially only -- undo the written part
519 if (bytesTransferred > 0) {
520 size_t dummy;
521 _WriteMemory(address, breakpoint->softwareData, bytesTransferred,
522 dummy);
523 }
524 return B_BAD_ADDRESS;
525 }
526
527 installed->breakpoint = breakpoint;
528 breakpointDeleter.Detach();
529
530 TRACE("installed software breakpoint at %#lx\n", address);
531
532 return B_OK;
533 }
534
535
536 status_t
_UninstallSoftwareBreakpoint(Breakpoint * breakpoint)537 BreakpointManager::_UninstallSoftwareBreakpoint(Breakpoint* breakpoint)
538 {
539 size_t bytesWritten;
540 _WriteMemory(breakpoint->address, breakpoint->softwareData,
541 DEBUG_SOFTWARE_BREAKPOINT_SIZE, bytesWritten);
542
543 TRACE("uninstalled software breakpoint at %#lx\n", breakpoint->address);
544
545 delete breakpoint;
546 return B_OK;
547 }
548
549
550 status_t
_InstallHardwareBreakpoint(Breakpoint * breakpoint,addr_t address)551 BreakpointManager::_InstallHardwareBreakpoint(Breakpoint* breakpoint,
552 addr_t address)
553 {
554 status_t error = arch_set_breakpoint((void*)address);
555 if (error != B_OK)
556 return error;
557
558 // move to the tail of the list
559 fHardwareBreakpoints.Remove(breakpoint);
560 fHardwareBreakpoints.Add(breakpoint);
561
562 TRACE("installed hardware breakpoint at %#lx\n", address);
563
564 breakpoint->address = address;
565 breakpoint->used = true;
566 return B_OK;
567 }
568
569
570 status_t
_UninstallHardwareBreakpoint(Breakpoint * breakpoint)571 BreakpointManager::_UninstallHardwareBreakpoint(Breakpoint* breakpoint)
572 {
573 status_t error = arch_clear_breakpoint((void*)breakpoint->address);
574 if (error != B_OK)
575 return error;
576
577 TRACE("uninstalled hardware breakpoint at %#lx\n", breakpoint->address);
578
579 breakpoint->used = false;
580 breakpoint->installedBreakpoint = NULL;
581 return B_OK;
582 }
583
584
585 BreakpointManager::InstalledWatchpoint*
_FindWatchpoint(addr_t address) const586 BreakpointManager::_FindWatchpoint(addr_t address) const
587 {
588 for (InstalledWatchpointList::ConstIterator it = fWatchpoints.GetIterator();
589 InstalledWatchpoint* watchpoint = it.Next();) {
590 if (address == watchpoint->address)
591 return watchpoint;
592 }
593
594 return NULL;
595 }
596
597
598 status_t
_InstallWatchpoint(InstalledWatchpoint * watchpoint,addr_t address,uint32 type,int32 length)599 BreakpointManager::_InstallWatchpoint(InstalledWatchpoint* watchpoint,
600 addr_t address, uint32 type, int32 length)
601 {
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");
607 return B_BUSY;
608 }
609 #endif
610
611 status_t error = arch_set_watchpoint((void*)address, type, length);
612 if (error != B_OK)
613 return error;
614
615 watchpoint->address = address;
616
617 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
618 watchpoint->breakpoint->used = true;
619 #endif
620
621 return B_OK;
622 }
623
624
625 status_t
_UninstallWatchpoint(InstalledWatchpoint * watchpoint)626 BreakpointManager::_UninstallWatchpoint(InstalledWatchpoint* watchpoint)
627 {
628 #if DEBUG_SHARED_BREAK_AND_WATCHPOINTS
629 watchpoint->breakpoint->used = false;
630 #endif
631
632 return arch_clear_watchpoint((void*)watchpoint->address);
633 }
634
635
636 status_t
_ReadMemory(const addr_t _address,void * _buffer,size_t size,size_t & bytesRead)637 BreakpointManager::_ReadMemory(const addr_t _address, void* _buffer,
638 size_t size, size_t& bytesRead)
639 {
640 const uint8* address = (const uint8*)_address;
641 uint8* buffer = (uint8*)_buffer;
642
643 // check the parameters
644 if (!CanAccessAddress(address, false))
645 return B_BAD_ADDRESS;
646 if (size <= 0)
647 return B_BAD_VALUE;
648
649 // If the region to be read crosses page boundaries, we split it up into
650 // smaller chunks.
651 status_t error = B_OK;
652 bytesRead = 0;
653 while (size > 0) {
654 // check whether we're still in user address space
655 if (!CanAccessAddress(address, false)) {
656 error = B_BAD_ADDRESS;
657 break;
658 }
659
660 // don't cross page boundaries in a single read
661 int32 toRead = size;
662 int32 maxRead = B_PAGE_SIZE - (addr_t)address % B_PAGE_SIZE;
663 if (toRead > maxRead)
664 toRead = maxRead;
665
666 error = user_memcpy(buffer, address, toRead);
667 if (error != B_OK)
668 break;
669
670 bytesRead += toRead;
671 address += toRead;
672 buffer += toRead;
673 size -= toRead;
674 }
675
676 // If reading fails, we only fail, if we haven't read anything yet.
677 if (error != B_OK) {
678 if (bytesRead > 0)
679 return B_OK;
680 return error;
681 }
682
683 return B_OK;
684 }
685
686
687 status_t
_WriteMemory(addr_t _address,const void * _buffer,size_t size,size_t & bytesWritten)688 BreakpointManager::_WriteMemory(addr_t _address, const void* _buffer,
689 size_t size, size_t& bytesWritten)
690 {
691 uint8* address = (uint8*)_address;
692 const uint8* buffer = (const uint8*)_buffer;
693
694 // check the parameters
695 if (!CanAccessAddress(address, true))
696 return B_BAD_ADDRESS;
697 if (size <= 0)
698 return B_BAD_VALUE;
699
700 // If the region to be written crosses area boundaries, we split it up into
701 // smaller chunks.
702 status_t error = B_OK;
703 bytesWritten = 0;
704 while (size > 0) {
705 // check whether we're still in user address space
706 if (!CanAccessAddress(address, true)) {
707 error = B_BAD_ADDRESS;
708 break;
709 }
710
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);
714 if (area < 0) {
715 TRACE("BreakpointManager::_WriteMemory(): area not found for "
716 "address: %p: %lx\n", address, area);
717 error = area;
718 break;
719 }
720
721 area_info areaInfo;
722 status_t error = get_area_info(area, &areaInfo);
723 if (error != B_OK) {
724 TRACE("BreakpointManager::_WriteMemory(): failed to get info for "
725 "area %ld: %lx\n", area, error);
726 error = B_BAD_ADDRESS;
727 break;
728 }
729
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)
734 toWrite = maxWrite;
735
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);
741 if (error != B_OK) {
742 TRACE("BreakpointManager::_WriteMemory(): failed to set new "
743 "protection for area %ld: %lx\n", area, error);
744 break;
745 }
746 protectionChanged = true;
747 }
748
749 // copy the memory
750 error = user_memcpy(address, buffer, toWrite);
751
752 // reset the area protection
753 if (protectionChanged)
754 set_area_protection(area, areaInfo.protection);
755
756 if (error != B_OK) {
757 TRACE("BreakpointManager::_WriteMemory(): user_memcpy() failed: "
758 "%lx\n", error);
759 break;
760 }
761
762 bytesWritten += toWrite;
763 address += toWrite;
764 buffer += toWrite;
765 size -= toWrite;
766 }
767
768 // If writing fails, we only fail, if we haven't written anything yet.
769 if (error != B_OK) {
770 if (bytesWritten > 0)
771 return B_OK;
772 return error;
773 }
774
775 return B_OK;
776 }
777