2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
6 #include "BreakpointManager.h"
12 #include <AutoLocker.h>
14 #include "DebuggerInterface.h"
16 #include "SpecificImageDebugInfo.h"
17 #include "Statement.h"
22 BreakpointManager::BreakpointManager(Team
* team
,
23 DebuggerInterface
* debuggerInterface
)
25 fLock("breakpoint manager"),
27 fDebuggerInterface(debuggerInterface
)
29 fDebuggerInterface
->AcquireReference();
33 BreakpointManager::~BreakpointManager()
35 fDebuggerInterface
->ReleaseReference();
40 BreakpointManager::Init()
42 return fLock
.InitCheck();
47 BreakpointManager::InstallUserBreakpoint(UserBreakpoint
* userBreakpoint
,
50 TRACE_CONTROL("BreakpointManager::InstallUserBreakpoint(%p, %d)\n",
51 userBreakpoint
, enabled
);
53 AutoLocker
<BLocker
> installLocker(fLock
);
54 AutoLocker
<Team
> teamLocker(fTeam
);
56 bool oldEnabled
= userBreakpoint
->IsEnabled();
57 if (userBreakpoint
->IsValid() && enabled
== oldEnabled
) {
58 TRACE_CONTROL(" user breakpoint already valid and with same enabled "
63 // get/create the breakpoints for all instances
64 TRACE_CONTROL(" creating breakpoints for breakpoint instances\n");
66 status_t error
= B_OK
;
68 UserBreakpointInstance
* instance
= userBreakpoint
->InstanceAt(i
); i
++) {
70 TRACE_CONTROL(" breakpoint instance %p\n", instance
);
72 if (instance
->GetBreakpoint() != NULL
) {
73 TRACE_CONTROL(" -> already has breakpoint\n");
77 target_addr_t address
= instance
->Address();
78 Breakpoint
* breakpoint
= fTeam
->BreakpointAtAddress(address
);
79 if (breakpoint
== NULL
) {
80 TRACE_CONTROL(" -> no breakpoint at that address yet\n");
82 Image
* image
= fTeam
->ImageByAddress(address
);
84 TRACE_CONTROL(" -> no image at that address\n");
85 error
= B_BAD_ADDRESS
;
89 breakpoint
= new(std::nothrow
) Breakpoint(image
, address
);
90 if (breakpoint
== NULL
|| !fTeam
->AddBreakpoint(breakpoint
)) {
97 TRACE_CONTROL(" -> adding instance to breakpoint %p\n", breakpoint
);
99 breakpoint
->AddUserBreakpoint(instance
);
100 instance
->SetBreakpoint(breakpoint
);
103 // If everything looks good so far mark the user breakpoint according to
106 userBreakpoint
->SetEnabled(enabled
);
108 // notify user breakpoint listeners
110 fTeam
->NotifyUserBreakpointChanged(userBreakpoint
);
114 // install/uninstall the breakpoints as needed
115 TRACE_CONTROL(" updating breakpoints\n");
119 UserBreakpointInstance
* instance
= userBreakpoint
->InstanceAt(i
);
121 TRACE_CONTROL(" breakpoint instance %p\n", instance
);
123 error
= _UpdateBreakpointInstallation(instance
->GetBreakpoint());
130 TRACE_CONTROL(" success, marking user breakpoint valid\n");
132 // everything went fine -- mark the user breakpoint valid
133 if (!userBreakpoint
->IsValid()) {
135 userBreakpoint
->SetValid(true);
136 userBreakpoint
->AcquireReference();
137 fTeam
->AddUserBreakpoint(userBreakpoint
);
138 fTeam
->NotifyUserBreakpointChanged(userBreakpoint
);
139 // notify again -- the breakpoint hadn't been added before
143 // something went wrong -- revert the situation
144 TRACE_CONTROL(" error, reverting\n");
147 userBreakpoint
->SetEnabled(oldEnabled
);
150 if (!oldEnabled
|| !userBreakpoint
->IsValid()) {
151 for (int32 i
= 0; UserBreakpointInstance
* instance
152 = userBreakpoint
->InstanceAt(i
);
154 Breakpoint
* breakpoint
= instance
->GetBreakpoint();
155 if (breakpoint
== NULL
)
158 if (!userBreakpoint
->IsValid()) {
159 instance
->SetBreakpoint(NULL
);
160 breakpoint
->RemoveUserBreakpoint(instance
);
163 _UpdateBreakpointInstallation(breakpoint
);
167 if (breakpoint
->IsUnused())
168 fTeam
->RemoveBreakpoint(breakpoint
);
173 fTeam
->NotifyUserBreakpointChanged(userBreakpoint
);
178 installLocker
.Unlock();
185 BreakpointManager::UninstallUserBreakpoint(UserBreakpoint
* userBreakpoint
)
187 AutoLocker
<BLocker
> installLocker(fLock
);
188 AutoLocker
<Team
> teamLocker(fTeam
);
190 if (!userBreakpoint
->IsValid())
193 fTeam
->RemoveUserBreakpoint(userBreakpoint
);
195 userBreakpoint
->SetValid(false);
196 userBreakpoint
->SetEnabled(false);
200 // uninstall the breakpoints as needed
202 UserBreakpointInstance
* instance
= userBreakpoint
->InstanceAt(i
); i
++) {
203 if (Breakpoint
* breakpoint
= instance
->GetBreakpoint())
204 _UpdateBreakpointInstallation(breakpoint
);
209 // detach the breakpoints from the user breakpoint instances
211 UserBreakpointInstance
* instance
= userBreakpoint
->InstanceAt(i
); i
++) {
212 if (Breakpoint
* breakpoint
= instance
->GetBreakpoint()) {
213 instance
->SetBreakpoint(NULL
);
214 breakpoint
->RemoveUserBreakpoint(instance
);
216 if (breakpoint
->IsUnused())
217 fTeam
->RemoveBreakpoint(breakpoint
);
221 fTeam
->NotifyUserBreakpointChanged(userBreakpoint
);
224 installLocker
.Unlock();
226 // release the reference from InstallUserBreakpoint()
227 userBreakpoint
->ReleaseReference();
232 BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address
,
233 BreakpointClient
* client
)
235 AutoLocker
<BLocker
> installLocker(fLock
);
236 AutoLocker
<Team
> teamLocker(fTeam
);
238 // create a breakpoint, if it doesn't exist yet
239 Breakpoint
* breakpoint
= fTeam
->BreakpointAtAddress(address
);
240 if (breakpoint
== NULL
) {
241 Image
* image
= fTeam
->ImageByAddress(address
);
243 return B_BAD_ADDRESS
;
245 breakpoint
= new(std::nothrow
) Breakpoint(image
, address
);
246 if (breakpoint
== NULL
)
249 if (!fTeam
->AddBreakpoint(breakpoint
))
253 BReference
<Breakpoint
> breakpointReference(breakpoint
);
257 if (breakpoint
->AddClient(client
)) {
258 if (breakpoint
->IsInstalled())
264 error
= fDebuggerInterface
->InstallBreakpoint(address
);
266 breakpoint
->SetInstalled(true);
272 breakpoint
->RemoveClient(client
);
277 if (breakpoint
->IsUnused())
278 fTeam
->RemoveBreakpoint(breakpoint
);
285 BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address
,
286 BreakpointClient
* client
)
288 AutoLocker
<BLocker
> installLocker(fLock
);
289 AutoLocker
<Team
> teamLocker(fTeam
);
291 Breakpoint
* breakpoint
= fTeam
->BreakpointAtAddress(address
);
292 if (breakpoint
== NULL
)
296 breakpoint
->RemoveClient(client
);
298 // check whether the breakpoint needs to be uninstalled
299 bool uninstall
= !breakpoint
->ShouldBeInstalled()
300 && breakpoint
->IsInstalled();
302 // if unused remove it
303 BReference
<Breakpoint
> breakpointReference(breakpoint
);
304 if (breakpoint
->IsUnused())
305 fTeam
->RemoveBreakpoint(breakpoint
);
310 fDebuggerInterface
->UninstallBreakpoint(address
);
311 breakpoint
->SetInstalled(false);
317 BreakpointManager::UpdateImageBreakpoints(Image
* image
)
319 _UpdateImageBreakpoints(image
, false);
324 BreakpointManager::RemoveImageBreakpoints(Image
* image
)
326 _UpdateImageBreakpoints(image
, true);
331 BreakpointManager::_UpdateImageBreakpoints(Image
* image
, bool removeOnly
)
333 AutoLocker
<BLocker
> installLocker(fLock
);
334 AutoLocker
<Team
> teamLocker(fTeam
);
336 // remove obsolete user breakpoint instances
337 BObjectList
<Breakpoint
> breakpointsToUpdate
;
338 for (UserBreakpointList::ConstIterator it
339 = fTeam
->UserBreakpoints().GetIterator();
340 UserBreakpoint
* userBreakpoint
= it
.Next();) {
341 int32 instanceCount
= userBreakpoint
->CountInstances();
342 for (int32 i
= instanceCount
- 1; i
>= 0; i
--) {
343 UserBreakpointInstance
* instance
= userBreakpoint
->InstanceAt(i
);
344 Breakpoint
* breakpoint
= instance
->GetBreakpoint();
345 if (breakpoint
== NULL
|| breakpoint
->GetImage() != image
)
348 userBreakpoint
->RemoveInstanceAt(i
);
349 breakpoint
->RemoveUserBreakpoint(instance
);
351 if (!breakpointsToUpdate
.AddItem(breakpoint
)) {
352 _UpdateBreakpointInstallation(breakpoint
);
353 if (breakpoint
->IsUnused())
354 fTeam
->RemoveBreakpoint(breakpoint
);
361 // update breakpoints
363 for (int32 i
= 0; Breakpoint
* breakpoint
= breakpointsToUpdate
.ItemAt(i
);
365 _UpdateBreakpointInstallation(breakpoint
);
369 for (int32 i
= 0; Breakpoint
* breakpoint
= breakpointsToUpdate
.ItemAt(i
);
371 if (breakpoint
->IsUnused())
372 fTeam
->RemoveBreakpoint(breakpoint
);
375 // add breakpoint instances for function instances in the image (if we have
376 // an image debug info)
377 BObjectList
<UserBreakpointInstance
> newInstances
;
378 ImageDebugInfo
* imageDebugInfo
= image
->GetImageDebugInfo();
379 if (imageDebugInfo
== NULL
)
382 for (UserBreakpointList::ConstIterator it
383 = fTeam
->UserBreakpoints().GetIterator();
384 UserBreakpoint
* userBreakpoint
= it
.Next();) {
386 Function
* function
= fTeam
->FunctionByID(
387 userBreakpoint
->Location().GetFunctionID());
388 if (function
== NULL
)
391 const SourceLocation
& sourceLocation
392 = userBreakpoint
->Location().GetSourceLocation();
393 target_addr_t relativeAddress
394 = userBreakpoint
->Location().RelativeAddress();
396 // iterate through the function instances
397 for (FunctionInstanceList::ConstIterator it
398 = function
->Instances().GetIterator();
399 FunctionInstance
* functionInstance
= it
.Next();) {
400 if (functionInstance
->GetImageDebugInfo() != imageDebugInfo
)
403 // get the breakpoint address for the instance
404 target_addr_t instanceAddress
= 0;
405 if (functionInstance
->SourceFile() != NULL
) {
406 // We have a source file, so get the address for the source
408 Statement
* statement
= NULL
;
409 FunctionDebugInfo
* functionDebugInfo
410 = functionInstance
->GetFunctionDebugInfo();
411 functionDebugInfo
->GetSpecificImageDebugInfo()
412 ->GetStatementAtSourceLocation(functionDebugInfo
,
413 sourceLocation
, statement
);
414 if (statement
!= NULL
) {
415 instanceAddress
= statement
->CoveringAddressRange().Start();
416 // TODO: What about BreakpointAllowed()?
417 statement
->ReleaseReference();
418 // TODO: Make sure we do hit the function in question!
422 if (instanceAddress
== 0) {
423 // No source file (or we failed getting the statement), so try
424 // to use the same relative address.
425 if (relativeAddress
> functionInstance
->Size())
427 instanceAddress
= functionInstance
->Address() + relativeAddress
;
428 // TODO: Make sure it does at least hit an instruction!
431 // create the user breakpoint instance
432 UserBreakpointInstance
* instance
= new(std::nothrow
)
433 UserBreakpointInstance(userBreakpoint
, instanceAddress
);
434 if (instance
== NULL
|| !newInstances
.AddItem(instance
)) {
439 if (!userBreakpoint
->AddInstance(instance
)) {
440 newInstances
.RemoveItemAt(newInstances
.CountItems() - 1);
444 // get/create the breakpoint for the address
445 target_addr_t address
= instance
->Address();
446 Breakpoint
* breakpoint
= fTeam
->BreakpointAtAddress(address
);
447 if (breakpoint
== NULL
) {
448 breakpoint
= new(std::nothrow
) Breakpoint(image
, address
);
449 if (breakpoint
== NULL
|| !fTeam
->AddBreakpoint(breakpoint
)) {
455 breakpoint
->AddUserBreakpoint(instance
);
456 instance
->SetBreakpoint(breakpoint
);
460 // install the breakpoints for the new user breakpoint instances
462 for (int32 i
= 0; UserBreakpointInstance
* instance
= newInstances
.ItemAt(i
);
464 Breakpoint
* breakpoint
= instance
->GetBreakpoint();
465 if (breakpoint
== NULL
466 || _UpdateBreakpointInstallation(breakpoint
) != B_OK
) {
467 // something went wrong -- remove the instance
470 instance
->GetUserBreakpoint()->RemoveInstance(instance
);
471 if (breakpoint
!= NULL
) {
472 breakpoint
->AddUserBreakpoint(instance
);
473 if (breakpoint
->IsUnused())
474 fTeam
->RemoveBreakpoint(breakpoint
);
484 BreakpointManager::_UpdateBreakpointInstallation(Breakpoint
* breakpoint
)
486 bool shouldBeInstalled
= breakpoint
->ShouldBeInstalled();
488 TRACE_CONTROL("BreakpointManager::_UpdateBreakpointInstallation(%p): "
489 "should be installed: %d, is installed: %d\n", breakpoint
,
490 shouldBeInstalled
, breakpoint
->IsInstalled());
492 if (shouldBeInstalled
== breakpoint
->IsInstalled())
495 if (shouldBeInstalled
) {
497 status_t error
= B_OK
;
498 // if we're not actually connected to a team, silently
499 // allow setting the breakpoint so it's saved to settings
500 // for when we do connect/have the team in the debugger.
501 if (fDebuggerInterface
->Connected())
502 fDebuggerInterface
->InstallBreakpoint(breakpoint
->Address());
507 TRACE_CONTROL("BREAKPOINT at %#" B_PRIx64
" installed: %s\n",
508 breakpoint
->Address(), strerror(error
));
510 breakpoint
->SetInstalled(true);
513 fDebuggerInterface
->UninstallBreakpoint(breakpoint
->Address());
515 TRACE_CONTROL("BREAKPOINT at %#" B_PRIx64
" uninstalled\n",
516 breakpoint
->Address());
518 breakpoint
->SetInstalled(false);