7bdeef54a2
Team: - Adjust report generation event to include a final status code for listeners. CliContext,TeamWindow,ReportUserinterface: - Use aforementioned status code to indicate whether report generation succeeded or failed. DebugReportGenerator: - Notify listeners if report generation fails. This may have previously been responsible for some bug reports where it was indicated that the debugger hung without exiting after being asked to save a report from a crashed app. - When dumping disassembly, retrieve it directly if necessary rather than requesting it via the user interface listener. This also fixes the quirk that requesting to save a crash report while looking at the source code of a function would trigger switching it to disassembly visually. - When walking the list of threads to dump, acquire references to all of them before starting. Otherwise, it was potentially possible for a running but not crashed thread to exit while we were generating the report, leaving us with a pointer to a deleted thread. This was most likely the cause of one of the crashes reported in #13082. - When receiving the notification that source code state has changed, clear the waiting function. Otherwise, it was potentially possible for us to get other state change notifications, leading to the data semaphore being released too often. This would then cause later potential waits such as the stack frame memory dump to not actually wait when they should, potentially leading them to dereference objects that weren't yet ready. This fixes another of the crashes in #13802.
566 lines
15 KiB
C++
566 lines
15 KiB
C++
/*
|
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
|
* Copyright 2013-2016, Rene Gollent, rene@gollent.com.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#ifndef TEAM_H
|
|
#define TEAM_H
|
|
|
|
#include <map>
|
|
|
|
#include <Locker.h>
|
|
#include <StringList.h>
|
|
|
|
#include <ObjectList.h>
|
|
|
|
#include "Image.h"
|
|
#include "ImageInfo.h"
|
|
#include "TargetAddressRange.h"
|
|
#include "Thread.h"
|
|
#include "ThreadInfo.h"
|
|
#include "UserBreakpoint.h"
|
|
#include "Watchpoint.h"
|
|
|
|
|
|
// team event types
|
|
enum {
|
|
TEAM_EVENT_TEAM_RENAMED,
|
|
|
|
TEAM_EVENT_THREAD_ADDED,
|
|
TEAM_EVENT_THREAD_REMOVED,
|
|
TEAM_EVENT_IMAGE_ADDED,
|
|
TEAM_EVENT_IMAGE_REMOVED,
|
|
|
|
TEAM_EVENT_THREAD_STATE_CHANGED,
|
|
TEAM_EVENT_THREAD_CPU_STATE_CHANGED,
|
|
TEAM_EVENT_THREAD_STACK_TRACE_CHANGED,
|
|
|
|
TEAM_EVENT_IMAGE_DEBUG_INFO_CHANGED,
|
|
|
|
TEAM_EVENT_IMAGE_LOAD_SETTINGS_CHANGED,
|
|
TEAM_EVENT_IMAGE_LOAD_NAME_ADDED,
|
|
TEAM_EVENT_IMAGE_LOAD_NAME_REMOVED,
|
|
|
|
TEAM_EVENT_DEFAULT_SIGNAL_DISPOSITION_CHANGED,
|
|
TEAM_EVENT_CUSTOM_SIGNAL_DISPOSITION_CHANGED,
|
|
TEAM_EVENT_CUSTOM_SIGNAL_DISPOSITION_REMOVED,
|
|
|
|
TEAM_EVENT_CONSOLE_OUTPUT_RECEIVED,
|
|
|
|
TEAM_EVENT_BREAKPOINT_ADDED,
|
|
TEAM_EVENT_BREAKPOINT_REMOVED,
|
|
TEAM_EVENT_USER_BREAKPOINT_CHANGED,
|
|
|
|
TEAM_EVENT_WATCHPOINT_ADDED,
|
|
TEAM_EVENT_WATCHPOINT_REMOVED,
|
|
TEAM_EVENT_WATCHPOINT_CHANGED,
|
|
|
|
TEAM_EVENT_DEBUG_REPORT_CHANGED,
|
|
|
|
TEAM_EVENT_CORE_FILE_CHANGED,
|
|
|
|
TEAM_EVENT_MEMORY_CHANGED
|
|
};
|
|
|
|
|
|
class Architecture;
|
|
class Breakpoint;
|
|
class BStringList;
|
|
class Function;
|
|
class FunctionID;
|
|
class FunctionInstance;
|
|
class LocatableFile;
|
|
class SourceCode;
|
|
class SourceLocation;
|
|
class Statement;
|
|
class TeamDebugInfo;
|
|
class TeamMemory;
|
|
class TeamTypeInformation;
|
|
class UserBreakpoint;
|
|
class Value;
|
|
|
|
|
|
typedef std::map<int32, int32> SignalDispositionMappings;
|
|
|
|
|
|
class Team {
|
|
public:
|
|
class Event;
|
|
class BreakpointEvent;
|
|
class ConsoleOutputEvent;
|
|
class DebugReportEvent;
|
|
class MemoryChangedEvent;
|
|
class ImageEvent;
|
|
class ImageLoadEvent;
|
|
class ImageLoadNameEvent;
|
|
class DefaultSignalDispositionEvent;
|
|
class CustomSignalDispositionEvent;
|
|
class ThreadEvent;
|
|
class UserBreakpointEvent;
|
|
class WatchpointEvent;
|
|
class CoreFileChangedEvent;
|
|
class Listener;
|
|
|
|
public:
|
|
Team(team_id teamID, TeamMemory* teamMemory,
|
|
Architecture* architecture,
|
|
TeamDebugInfo* debugInfo,
|
|
TeamTypeInformation* typeInformation);
|
|
~Team();
|
|
|
|
status_t Init();
|
|
|
|
bool Lock() { return fLock.Lock(); }
|
|
void Unlock() { fLock.Unlock(); }
|
|
|
|
team_id ID() const { return fID; }
|
|
TeamMemory* GetTeamMemory() const
|
|
{ return fTeamMemory; }
|
|
Architecture* GetArchitecture() const
|
|
{ return fArchitecture; }
|
|
TeamDebugInfo* DebugInfo() const { return fDebugInfo; }
|
|
TeamTypeInformation*
|
|
GetTeamTypeInformation() const
|
|
{ return fTypeInformation; }
|
|
|
|
const char* Name() const { return fName.String(); }
|
|
void SetName(const BString& name);
|
|
|
|
void AddThread(::Thread* thread);
|
|
status_t AddThread(const ThreadInfo& threadInfo,
|
|
::Thread** _thread = NULL);
|
|
void RemoveThread(::Thread* thread);
|
|
bool RemoveThread(thread_id threadID);
|
|
::Thread* ThreadByID(thread_id threadID) const;
|
|
const ThreadList& Threads() const;
|
|
|
|
status_t AddImage(const ImageInfo& imageInfo,
|
|
LocatableFile* imageFile,
|
|
Image** _image = NULL);
|
|
void RemoveImage(Image* image);
|
|
bool RemoveImage(image_id imageID);
|
|
Image* ImageByID(image_id imageID) const;
|
|
Image* ImageByAddress(target_addr_t address) const;
|
|
const ImageList& Images() const;
|
|
void ClearImages();
|
|
|
|
bool AddStopImageName(const BString& name);
|
|
void RemoveStopImageName(const BString& name);
|
|
const BStringList& StopImageNames() const;
|
|
|
|
void SetStopOnImageLoad(bool enabled,
|
|
bool useImageNameList);
|
|
bool StopOnImageLoad() const
|
|
{ return fStopOnImageLoad; }
|
|
bool StopImageNameListEnabled() const
|
|
{ return fStopImageNameListEnabled; }
|
|
|
|
void SetDefaultSignalDisposition(int32 disposition);
|
|
int32 DefaultSignalDisposition() const
|
|
{ return fDefaultSignalDisposition; }
|
|
bool SetCustomSignalDisposition(int32 signal,
|
|
int32 disposition);
|
|
void RemoveCustomSignalDisposition(int32 signal);
|
|
int32 SignalDispositionFor(int32 signal) const;
|
|
// if no custom disposition is found,
|
|
// returns default
|
|
const SignalDispositionMappings&
|
|
GetSignalDispositionMappings() const;
|
|
|
|
void ClearSignalDispositionMappings();
|
|
|
|
bool AddBreakpoint(Breakpoint* breakpoint);
|
|
// takes over reference (also on error)
|
|
void RemoveBreakpoint(Breakpoint* breakpoint);
|
|
// releases its own reference
|
|
int32 CountBreakpoints() const;
|
|
Breakpoint* BreakpointAt(int32 index) const;
|
|
Breakpoint* BreakpointAtAddress(
|
|
target_addr_t address) const;
|
|
void GetBreakpointsInAddressRange(
|
|
TargetAddressRange range,
|
|
BObjectList<UserBreakpoint>& breakpoints)
|
|
const;
|
|
void GetBreakpointsForSourceCode(
|
|
SourceCode* sourceCode,
|
|
BObjectList<UserBreakpoint>& breakpoints)
|
|
const;
|
|
|
|
void AddUserBreakpoint(
|
|
UserBreakpoint* userBreakpoint);
|
|
void RemoveUserBreakpoint(
|
|
UserBreakpoint* userBreakpoint);
|
|
const UserBreakpointList& UserBreakpoints() const
|
|
{ return fUserBreakpoints; }
|
|
|
|
bool AddWatchpoint(Watchpoint* watchpoint);
|
|
// takes over reference (also on error)
|
|
void RemoveWatchpoint(Watchpoint* watchpoint);
|
|
// releases its own reference
|
|
int32 CountWatchpoints() const;
|
|
Watchpoint* WatchpointAt(int32 index) const;
|
|
Watchpoint* WatchpointAtAddress(
|
|
target_addr_t address) const;
|
|
void GetWatchpointsInAddressRange(
|
|
TargetAddressRange range,
|
|
BObjectList<Watchpoint>& watchpoints)
|
|
const;
|
|
const WatchpointList& Watchpoints() const
|
|
{ return fWatchpoints; }
|
|
|
|
status_t GetStatementAtAddress(target_addr_t address,
|
|
FunctionInstance*& _function,
|
|
Statement*& _statement);
|
|
// returns a reference to the statement,
|
|
// not to the functions instance, though,
|
|
// caller must lock
|
|
status_t GetStatementAtSourceLocation(
|
|
SourceCode* sourceCode,
|
|
const SourceLocation& location,
|
|
Statement*& _statement);
|
|
// returns a reference to the statement
|
|
// (any matching statement!),
|
|
// caller must lock,
|
|
|
|
Function* FunctionByID(FunctionID* functionID) const;
|
|
|
|
void AddListener(Listener* listener);
|
|
void RemoveListener(Listener* listener);
|
|
|
|
// service methods for Thread
|
|
void NotifyThreadStateChanged(::Thread* thread);
|
|
void NotifyThreadCpuStateChanged(::Thread* thread);
|
|
void NotifyThreadStackTraceChanged(
|
|
::Thread* thread);
|
|
|
|
// service methods for Image
|
|
void NotifyImageDebugInfoChanged(Image* image);
|
|
|
|
// service methods for Image load settings
|
|
void NotifyStopOnImageLoadChanged(bool enabled,
|
|
bool useImageNameList);
|
|
void NotifyStopImageNameAdded(const BString& name);
|
|
void NotifyStopImageNameRemoved(
|
|
const BString& name);
|
|
|
|
// service methods for Signal Disposition settings
|
|
void NotifyDefaultSignalDispositionChanged(
|
|
int32 newDisposition);
|
|
void NotifyCustomSignalDispositionChanged(
|
|
int32 signal, int32 disposition);
|
|
void NotifyCustomSignalDispositionRemoved(
|
|
int32 signal);
|
|
|
|
// service methods for console output
|
|
void NotifyConsoleOutputReceived(
|
|
int32 fd, const BString& output);
|
|
|
|
// breakpoint related service methods
|
|
void NotifyUserBreakpointChanged(
|
|
UserBreakpoint* breakpoint);
|
|
|
|
// watchpoint related service methods
|
|
void NotifyWatchpointChanged(
|
|
Watchpoint* watchpoint);
|
|
|
|
// debug report related service methods
|
|
void NotifyDebugReportChanged(
|
|
const char* reportPath, status_t result);
|
|
|
|
// core file related service methods
|
|
void NotifyCoreFileChanged(
|
|
const char* targetPath);
|
|
|
|
// memory write related service methods
|
|
void NotifyMemoryChanged(target_addr_t address,
|
|
target_size_t size);
|
|
|
|
private:
|
|
struct BreakpointByAddressPredicate;
|
|
struct WatchpointByAddressPredicate;
|
|
|
|
typedef BObjectList<Breakpoint> BreakpointList;
|
|
typedef DoublyLinkedList<Listener> ListenerList;
|
|
|
|
private:
|
|
void _NotifyTeamRenamed();
|
|
void _NotifyThreadAdded(::Thread* thread);
|
|
void _NotifyThreadRemoved(::Thread* thread);
|
|
void _NotifyImageAdded(Image* image);
|
|
void _NotifyImageRemoved(Image* image);
|
|
|
|
private:
|
|
BLocker fLock;
|
|
team_id fID;
|
|
TeamMemory* fTeamMemory;
|
|
TeamTypeInformation*
|
|
fTypeInformation;
|
|
Architecture* fArchitecture;
|
|
TeamDebugInfo* fDebugInfo;
|
|
BString fName;
|
|
ThreadList fThreads;
|
|
ImageList fImages;
|
|
bool fStopOnImageLoad;
|
|
bool fStopImageNameListEnabled;
|
|
BStringList fStopImageNames;
|
|
int32 fDefaultSignalDisposition;
|
|
SignalDispositionMappings
|
|
fCustomSignalDispositions;
|
|
BreakpointList fBreakpoints;
|
|
WatchpointList fWatchpoints;
|
|
UserBreakpointList fUserBreakpoints;
|
|
ListenerList fListeners;
|
|
};
|
|
|
|
|
|
class Team::Event {
|
|
public:
|
|
Event(uint32 type, Team* team);
|
|
|
|
uint32 EventType() const { return fEventType; }
|
|
Team* GetTeam() const { return fTeam; }
|
|
|
|
protected:
|
|
uint32 fEventType;
|
|
Team* fTeam;
|
|
};
|
|
|
|
|
|
class Team::ThreadEvent : public Event {
|
|
public:
|
|
ThreadEvent(uint32 type, ::Thread* thread);
|
|
|
|
::Thread* GetThread() const { return fThread; }
|
|
|
|
protected:
|
|
::Thread* fThread;
|
|
};
|
|
|
|
|
|
class Team::ImageEvent : public Event {
|
|
public:
|
|
ImageEvent(uint32 type, Image* image);
|
|
|
|
Image* GetImage() const { return fImage; }
|
|
|
|
protected:
|
|
Image* fImage;
|
|
};
|
|
|
|
|
|
class Team::ImageLoadEvent : public Event {
|
|
public:
|
|
ImageLoadEvent(uint32 type, Team* team,
|
|
bool stopOnImageLoad,
|
|
bool stopImageNameListEnabled);
|
|
|
|
bool StopOnImageLoad() const
|
|
{ return fStopOnImageLoad; }
|
|
bool StopImageNameListEnabled() const
|
|
{ return fStopImageNameListEnabled; }
|
|
|
|
private:
|
|
bool fStopOnImageLoad;
|
|
bool fStopImageNameListEnabled;
|
|
};
|
|
|
|
|
|
class Team::ImageLoadNameEvent : public Event {
|
|
public:
|
|
ImageLoadNameEvent(uint32 type, Team* team,
|
|
const BString& name);
|
|
|
|
const BString& ImageName() const { return fImageName; }
|
|
|
|
private:
|
|
BString fImageName;
|
|
};
|
|
|
|
|
|
class Team::DefaultSignalDispositionEvent : public Event {
|
|
public:
|
|
DefaultSignalDispositionEvent(uint32 type,
|
|
Team* team, int32 disposition);
|
|
|
|
int32 DefaultDisposition() const
|
|
{ return fDefaultDisposition; }
|
|
|
|
private:
|
|
int32 fDefaultDisposition;
|
|
};
|
|
|
|
|
|
class Team::CustomSignalDispositionEvent : public Event {
|
|
public:
|
|
CustomSignalDispositionEvent(uint32 type,
|
|
Team* team, int32 signal,
|
|
int32 disposition);
|
|
|
|
int32 Signal() const { return fSignal; }
|
|
int32 Disposition() const { return fDisposition; }
|
|
|
|
private:
|
|
int32 fSignal;
|
|
int32 fDisposition;
|
|
};
|
|
|
|
|
|
class Team::BreakpointEvent : public Event {
|
|
public:
|
|
BreakpointEvent(uint32 type, Team* team,
|
|
Breakpoint* breakpoint);
|
|
|
|
Breakpoint* GetBreakpoint() const { return fBreakpoint; }
|
|
|
|
protected:
|
|
Breakpoint* fBreakpoint;
|
|
};
|
|
|
|
|
|
class Team::ConsoleOutputEvent : public Event {
|
|
public:
|
|
ConsoleOutputEvent(uint32 type, Team* team,
|
|
int32 fd, const BString& output);
|
|
|
|
int32 Descriptor() const { return fDescriptor; }
|
|
const BString& Output() const { return fOutput; }
|
|
|
|
protected:
|
|
int32 fDescriptor;
|
|
BString fOutput;
|
|
};
|
|
|
|
|
|
class Team::DebugReportEvent : public Event {
|
|
public:
|
|
DebugReportEvent(uint32 type, Team* team,
|
|
const char* reportPath,
|
|
status_t finalStatus);
|
|
|
|
const char* GetReportPath() const { return fReportPath; }
|
|
status_t GetFinalStatus() const { return fFinalStatus; }
|
|
protected:
|
|
const char* fReportPath;
|
|
status_t fFinalStatus;
|
|
};
|
|
|
|
|
|
class Team::CoreFileChangedEvent : public Event {
|
|
public:
|
|
CoreFileChangedEvent(uint32 type, Team* team,
|
|
const char* targetPath);
|
|
const char* GetTargetPath() const { return fTargetPath; }
|
|
protected:
|
|
const char* fTargetPath;
|
|
};
|
|
|
|
|
|
class Team::MemoryChangedEvent : public Event {
|
|
public:
|
|
MemoryChangedEvent(uint32 type, Team* team,
|
|
target_addr_t address, target_size_t size);
|
|
|
|
target_addr_t GetTargetAddress() const
|
|
{ return fTargetAddress; }
|
|
|
|
target_size_t GetSize() const { return fSize; }
|
|
protected:
|
|
target_addr_t fTargetAddress;
|
|
target_size_t fSize;
|
|
};
|
|
|
|
|
|
class Team::WatchpointEvent : public Event {
|
|
public:
|
|
WatchpointEvent(uint32 type, Team* team,
|
|
Watchpoint* watchpoint);
|
|
|
|
Watchpoint* GetWatchpoint() const { return fWatchpoint; }
|
|
|
|
protected:
|
|
Watchpoint* fWatchpoint;
|
|
};
|
|
|
|
|
|
class Team::UserBreakpointEvent : public Event {
|
|
public:
|
|
UserBreakpointEvent(uint32 type, Team* team,
|
|
UserBreakpoint* breakpoint);
|
|
|
|
UserBreakpoint* GetBreakpoint() const { return fBreakpoint; }
|
|
|
|
protected:
|
|
UserBreakpoint* fBreakpoint;
|
|
};
|
|
|
|
|
|
class Team::Listener : public DoublyLinkedListLinkImpl<Team::Listener> {
|
|
public:
|
|
virtual ~Listener();
|
|
|
|
virtual void TeamRenamed(
|
|
const Team::Event& event);
|
|
|
|
virtual void ThreadAdded(const Team::ThreadEvent& event);
|
|
virtual void ThreadRemoved(const Team::ThreadEvent& event);
|
|
|
|
virtual void ImageAdded(const Team::ImageEvent& event);
|
|
virtual void ImageRemoved(const Team::ImageEvent& event);
|
|
|
|
virtual void ThreadStateChanged(
|
|
const Team::ThreadEvent& event);
|
|
virtual void ThreadCpuStateChanged(
|
|
const Team::ThreadEvent& event);
|
|
virtual void ThreadStackTraceChanged(
|
|
const Team::ThreadEvent& event);
|
|
|
|
virtual void ImageDebugInfoChanged(
|
|
const Team::ImageEvent& event);
|
|
|
|
virtual void StopOnImageLoadSettingsChanged(
|
|
const Team::ImageLoadEvent& event);
|
|
virtual void StopOnImageLoadNameAdded(
|
|
const Team::ImageLoadNameEvent& event);
|
|
virtual void StopOnImageLoadNameRemoved(
|
|
const Team::ImageLoadNameEvent& event);
|
|
|
|
virtual void DefaultSignalDispositionChanged(
|
|
const Team::DefaultSignalDispositionEvent&
|
|
event);
|
|
virtual void CustomSignalDispositionChanged(
|
|
const Team::CustomSignalDispositionEvent&
|
|
event);
|
|
virtual void CustomSignalDispositionRemoved(
|
|
const Team::CustomSignalDispositionEvent&
|
|
event);
|
|
|
|
virtual void ConsoleOutputReceived(
|
|
const Team::ConsoleOutputEvent& event);
|
|
|
|
virtual void BreakpointAdded(
|
|
const Team::BreakpointEvent& event);
|
|
virtual void BreakpointRemoved(
|
|
const Team::BreakpointEvent& event);
|
|
virtual void UserBreakpointChanged(
|
|
const Team::UserBreakpointEvent& event);
|
|
|
|
virtual void WatchpointAdded(
|
|
const Team::WatchpointEvent& event);
|
|
virtual void WatchpointRemoved(
|
|
const Team::WatchpointEvent& event);
|
|
virtual void WatchpointChanged(
|
|
const Team::WatchpointEvent& event);
|
|
|
|
virtual void DebugReportChanged(
|
|
const Team::DebugReportEvent& event);
|
|
|
|
virtual void CoreFileChanged(
|
|
const Team::CoreFileChangedEvent& event);
|
|
|
|
virtual void MemoryChanged(
|
|
const Team::MemoryChangedEvent& event);
|
|
};
|
|
|
|
|
|
#endif // TEAM_H
|