diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index be5e74ecc2..7b49c77bb1 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -34,6 +34,8 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) settings generic ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language c_family ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language x86 ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) target_host_interface ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) target_host_interface interfaces ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface cli ] ; @@ -193,6 +195,7 @@ local sources = SyntheticPrimitiveType.cpp SyscallInfo.cpp SystemInfo.cpp + TargetHost.cpp Team.cpp TeamInfo.cpp TeamMemory.cpp @@ -239,6 +242,12 @@ local sources = # source_language/x86 X86AssemblyLanguage.cpp + # target_host_interface + TargetHostInterface.cpp + + # target_host_interface/interfaces + LocalTargetHostInterface.cpp + # types ArrayIndexPath.cpp TargetAddressRangeList.cpp diff --git a/src/apps/debugger/model/TargetHost.cpp b/src/apps/debugger/model/TargetHost.cpp new file mode 100644 index 0000000000..42c90ed4a6 --- /dev/null +++ b/src/apps/debugger/model/TargetHost.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + +#include "TargetHost.h" + +#include + +#include "TeamInfo.h" + + +TargetHost::TargetHost(const BString& name) + : + BReferenceable(), + fName(name), + fLock(), + fListeners(), + fTeams() +{ +} + + +TargetHost::~TargetHost() +{ + while (!fTeams.IsEmpty()) + delete fTeams.RemoveItemAt((int32)0); +} + + +void +TargetHost::AddListener(Listener* listener) +{ + AutoLocker hostLocker(this); + fListeners.Add(listener); +} + + +void +TargetHost::RemoveListener(Listener* listener) +{ + AutoLocker hostLocker(this); + fListeners.Remove(listener); +} + + +int32 +TargetHost::CountTeams() const +{ + return fTeams.CountItems(); +} + + +status_t +TargetHost::AddTeam(const team_info& info) +{ + TeamInfo* teamInfo = new (std::nothrow) TeamInfo(info.team, info); + if (teamInfo == NULL) + return B_NO_MEMORY; + + if (!fTeams.BinaryInsert(teamInfo, &_CompareTeams)) + return B_NO_MEMORY; + + _NotifyTeamAdded(teamInfo); + return B_OK; +} + + +void +TargetHost::RemoveTeam(team_id team) +{ + int32 index = fTeams.BinarySearchIndexByKey(team, + &_FindTeamByKey); + if (index < 0) + return; + + _NotifyTeamRemoved(team); + TeamInfo* info = fTeams.RemoveItemAt(index); + delete info; +} + + +void +TargetHost::UpdateTeam(const team_info& info) +{ + int32 index = fTeams.BinarySearchIndexByKey(info.team, + &_FindTeamByKey); + if (index < 0) + return; + + TeamInfo* teamInfo = fTeams.ItemAt(index); + teamInfo->SetTo(info.team, info); + _NotifyTeamRenamed(teamInfo); +} + + +TeamInfo* +TargetHost::TeamInfoAt(int32 index) const +{ + return fTeams.ItemAt(index); +} + + +TeamInfo* +TargetHost::TeamInfoByID(team_id team) const +{ + return fTeams.BinarySearchByKey(team, &_FindTeamByKey); +} + + +/*static*/ int +TargetHost::_CompareTeams(const TeamInfo* a, const TeamInfo* b) +{ + return a->TeamID() < b->TeamID() ? -1 : 1; +} + + +/*static*/ int +TargetHost::_FindTeamByKey(const team_id* id, const TeamInfo* info) +{ + if (*id < info->TeamID()) + return -1; + else if (*id > info->TeamID()) + return 1; + return 0; +} + + +void +TargetHost::_NotifyTeamAdded(TeamInfo* info) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->TeamAdded(info); + } +} + + +void +TargetHost::_NotifyTeamRemoved(team_id team) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->TeamRemoved(team); + } +} + + +void +TargetHost::_NotifyTeamRenamed(TeamInfo* info) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->TeamRenamed(info); + } +} + + +// #pragma mark - TargetHost::Listener + + +TargetHost::Listener::~Listener() +{ +} + + +void +TargetHost::Listener::TeamAdded(TeamInfo* info) +{ +} + + +void +TargetHost::Listener::TeamRemoved(team_id team) +{ +} + + +void +TargetHost::Listener::TeamRenamed(TeamInfo* info) +{ +} diff --git a/src/apps/debugger/model/TargetHost.h b/src/apps/debugger/model/TargetHost.h new file mode 100644 index 0000000000..ad63df25ce --- /dev/null +++ b/src/apps/debugger/model/TargetHost.h @@ -0,0 +1,74 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef TARGET_HOST_H +#define TARGET_HOST_H + +#include +#include +#include + +#include +#include +#include + + +class TeamInfo; + + +class TargetHost : public BReferenceable { +public: + class Listener; +public: + TargetHost(const BString& name); + virtual ~TargetHost(); + + bool Lock() { return fLock.Lock(); } + void Unlock() { fLock.Unlock(); } + + const BString& Name() const { return fName; } + + void AddListener(Listener* listener); + void RemoveListener(Listener* listener); + + int32 CountTeams() const; + status_t AddTeam(const team_info& info); + void RemoveTeam(team_id team); + void UpdateTeam(const team_info& info); + TeamInfo* TeamInfoAt(int32 index) const; + TeamInfo* TeamInfoByID(team_id team) const; + +private: + typedef DoublyLinkedList ListenerList; + typedef BObjectList TeamInfoList; + +private: + static int _CompareTeams(const TeamInfo* a, + const TeamInfo* b); + static int _FindTeamByKey(const team_id* id, + const TeamInfo* info); + + void _NotifyTeamAdded(TeamInfo* info); + void _NotifyTeamRemoved(team_id team); + void _NotifyTeamRenamed(TeamInfo* info); + +private: + BString fName; + BLocker fLock; + ListenerList fListeners; + TeamInfoList fTeams; +}; + + +class TargetHost::Listener + : public DoublyLinkedListLinkImpl { +public: + virtual ~Listener(); + + virtual void TeamAdded(TeamInfo* info); + virtual void TeamRemoved(team_id team); + virtual void TeamRenamed(TeamInfo* info); +}; + +#endif // TARGET_HOST_H diff --git a/src/apps/debugger/target_host_interface/TargetHostInterface.cpp b/src/apps/debugger/target_host_interface/TargetHostInterface.cpp new file mode 100644 index 0000000000..473e2c5524 --- /dev/null +++ b/src/apps/debugger/target_host_interface/TargetHostInterface.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + +#include "TargetHostInterface.h" + + +// #pragma mark - TargetHostInterface + +TargetHostInterface::~TargetHostInterface() +{ +} + + +void +TargetHostInterface::SetName(const BString& name) +{ + fName = name; +} diff --git a/src/apps/debugger/target_host_interface/TargetHostInterface.h b/src/apps/debugger/target_host_interface/TargetHostInterface.h new file mode 100644 index 0000000000..825ddafb55 --- /dev/null +++ b/src/apps/debugger/target_host_interface/TargetHostInterface.h @@ -0,0 +1,44 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef TARGET_HOST_INTERFACE_H +#define TARGET_HOST_INTERFACE_H + +#include +#include + +#include + + +class DebuggerInterface; +class TargetHost; + + +class TargetHostInterface : public BReferenceable { +public: + virtual ~TargetHostInterface(); + + virtual status_t Init() = 0; + virtual void Close() = 0; + + const BString& Name() const { return fName; } + void SetName(const BString& name); + + virtual bool Connected() const = 0; + + virtual TargetHost* GetTargetHost() = 0; + + virtual status_t Attach(team_id id, thread_id threadID, + DebuggerInterface*& _interface) = 0; + + virtual status_t CreateTeam(int commandLineArgc, + const char* const* arguments, + DebuggerInterface*& _interface) = 0; + +private: + BString fName; +}; + + +#endif // TARGET_HOST_INTERFACE_H diff --git a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp new file mode 100644 index 0000000000..532106ced3 --- /dev/null +++ b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + +#include "LocalTargetHostInterface.h" + +#include +#include + +#include +#include +#include + +#include "TargetHost.h" + + +LocalTargetHostInterface::LocalTargetHostInterface() + : + TargetHostInterface(), + fTargetHost(NULL), + fDataPort(-1) +{ + SetName("Local"); +} + + +LocalTargetHostInterface::~LocalTargetHostInterface() +{ + Close(); + + if (fTargetHost != NULL) + fTargetHost->ReleaseReference(); +} + + +status_t +LocalTargetHostInterface::Init() +{ + char hostname[HOST_NAME_MAX + 1]; + status_t error = gethostname(hostname, sizeof(hostname)); + if (error != B_OK) + return error; + + fTargetHost = new(std::nothrow) TargetHost(hostname); + if (fTargetHost == NULL) + return B_NO_MEMORY; + + team_info info; + error = get_team_info(B_CURRENT_TEAM, &info); + if (error != B_OK) + return error; + + char buffer[128]; + snprintf(buffer, sizeof(buffer), "LocalTargetHostInterface %" B_PRId32, + info.team); + + fDataPort = create_port(100, buffer); + if (fDataPort < 0) + return fDataPort; + + fPortWorker = spawn_thread(PortLoop, "Local Target Host Loop", + B_NORMAL_PRIORITY, this); + if (fPortWorker < 0) + return fPortWorker; + + resume_thread(fPortWorker); + + AutoLocker hostLocker(fTargetHost); + + error = __start_watching_system(-1, + B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION, + fDataPort, 0); + if (error != B_OK) + return error; + + int32 cookie = 0; + while (get_next_team_info(&cookie, &info) == B_OK) { + error = fTargetHost->AddTeam(info); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +void +LocalTargetHostInterface::Close() +{ + if (fDataPort > 0) { + __stop_watching_system(-1, + B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION, + fDataPort, 0); + + delete_port(fDataPort); + fDataPort = -1; + } + + if (fPortWorker > 0) { + wait_for_thread(fPortWorker, NULL); + fPortWorker = -1; + } +} + + +bool +LocalTargetHostInterface::Connected() const +{ + return true; +} + + +TargetHost* +LocalTargetHostInterface::GetTargetHost() +{ + return fTargetHost; +} + + +status_t +LocalTargetHostInterface::Attach(team_id id, thread_id threadID, + DebuggerInterface*& _interface) +{ + return B_NOT_SUPPORTED; +} + + +status_t +LocalTargetHostInterface::CreateTeam(int commandLineArgc, + const char* const* arguments, DebuggerInterface*& _interface) +{ + return B_NOT_SUPPORTED; +} + + +status_t +LocalTargetHostInterface::PortLoop(void* arg) +{ + LocalTargetHostInterface* interface = (LocalTargetHostInterface*)arg; + + for (;;) { + char buffer[2048]; + int32 messageCode; + ssize_t size = read_port(interface->fDataPort, &messageCode, buffer, + sizeof(buffer)); + if (size == B_INTERRUPTED) + continue; + else if (size < 0) + return size; + + KMessage message; + size = message.SetTo(buffer); + if (size != B_OK) + return size; + + if (message.What() != B_SYSTEM_OBJECT_UPDATE) + continue; + + int32 opcode = 0; + if (message.FindInt32("opcode", &opcode) != B_OK) + continue; + + team_id team = -1; + if (message.FindInt32("team", &team) != B_OK) + continue; + + AutoLocker locker(interface->fTargetHost); + switch (opcode) { + case B_TEAM_CREATED: + case B_TEAM_EXEC: + { + team_info info; + status_t error = get_team_info(team, &info); + if (error != B_OK) + continue; + + if (opcode == B_TEAM_CREATED) + interface->fTargetHost->AddTeam(info); + else + interface->fTargetHost->UpdateTeam(info); + break; + } + + case B_TEAM_DELETED: + { + interface->fTargetHost->RemoveTeam(team); + break; + } + + default: + { + break; + } + } + } + + return B_OK; +} diff --git a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h new file mode 100644 index 0000000000..d5f10f3d6d --- /dev/null +++ b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef LOCAL_TARGET_HOST_INTERFACE_H +#define LOCAL_TARGET_HOST_INTERFACE_H + +#include "TargetHostInterface.h" + +#include + + +class LocalTargetHostInterface : public TargetHostInterface { +public: + LocalTargetHostInterface(); + virtual ~LocalTargetHostInterface(); + + virtual status_t Init(); + virtual void Close(); + + virtual bool Connected() const; + + virtual TargetHost* GetTargetHost(); + + virtual status_t Attach(team_id id, thread_id threadID, + DebuggerInterface*& _interface); + + virtual status_t CreateTeam(int commandLineArgc, + const char* const* arguments, + DebuggerInterface*& _interface); + +private: + static status_t PortLoop(void* arg); + +private: + TargetHost* fTargetHost; + port_id fDataPort; + thread_id fPortWorker; +}; + +#endif // LOCAL_TARGET_HOST_INTERFACE_H