Debugger: Split into core library and application.
[haiku.git] / src / kits / debugger / target_host_interface / local / LocalTargetHostInterface.cpp
blobcc6006f35cd08dcc84888f3126b9b787bbe66fb7
1 /*
2 * Copyright 2016, Rene Gollent, rene@gollent.com.
3 * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
7 #include "LocalTargetHostInterface.h"
9 #include <set>
11 #include <stdio.h>
12 #include <unistd.h>
14 #include <image.h>
16 #include <AutoDeleter.h>
17 #include <AutoLocker.h>
18 #include <system_info.h>
19 #include <util/KMessage.h>
21 #include "debug_utils.h"
23 #include "CoreFile.h"
24 #include "CoreFileDebuggerInterface.h"
25 #include "LocalDebuggerInterface.h"
26 #include "TargetHost.h"
28 using std::set;
30 LocalTargetHostInterface::LocalTargetHostInterface()
32 TargetHostInterface(),
33 fTargetHost(NULL),
34 fDataPort(-1)
36 SetName("Local");
40 LocalTargetHostInterface::~LocalTargetHostInterface()
42 Close();
44 if (fTargetHost != NULL)
45 fTargetHost->ReleaseReference();
49 status_t
50 LocalTargetHostInterface::Init(Settings* settings)
52 char hostname[HOST_NAME_MAX + 1];
53 status_t error = gethostname(hostname, sizeof(hostname));
54 if (error != B_OK)
55 return error;
57 fTargetHost = new(std::nothrow) TargetHost(hostname);
58 if (fTargetHost == NULL)
59 return B_NO_MEMORY;
61 team_info info;
62 error = get_team_info(B_CURRENT_TEAM, &info);
63 if (error != B_OK)
64 return error;
66 char buffer[128];
67 snprintf(buffer, sizeof(buffer), "LocalTargetHostInterface %" B_PRId32,
68 info.team);
70 fDataPort = create_port(100, buffer);
71 if (fDataPort < 0)
72 return fDataPort;
74 fPortWorker = spawn_thread(_PortLoop, "Local Target Host Loop",
75 B_NORMAL_PRIORITY, this);
76 if (fPortWorker < 0)
77 return fPortWorker;
79 resume_thread(fPortWorker);
81 AutoLocker<TargetHost> hostLocker(fTargetHost);
83 error = __start_watching_system(-1,
84 B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION,
85 fDataPort, 0);
86 if (error != B_OK)
87 return error;
89 int32 cookie = 0;
90 while (get_next_team_info(&cookie, &info) == B_OK) {
91 error = fTargetHost->AddTeam(info);
92 if (error != B_OK)
93 return error;
96 snprintf(buffer, sizeof(buffer), "Local (%s)", hostname);
97 SetName(buffer);
99 return B_OK;
103 void
104 LocalTargetHostInterface::Close()
106 if (fDataPort > 0) {
107 __stop_watching_system(-1,
108 B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION,
109 fDataPort, 0);
111 delete_port(fDataPort);
112 fDataPort = -1;
115 if (fPortWorker > 0) {
116 wait_for_thread(fPortWorker, NULL);
117 fPortWorker = -1;
122 bool
123 LocalTargetHostInterface::IsLocal() const
125 return true;
129 bool
130 LocalTargetHostInterface::Connected() const
132 return true;
136 TargetHost*
137 LocalTargetHostInterface::GetTargetHost()
139 return fTargetHost;
143 status_t
144 LocalTargetHostInterface::Attach(team_id teamID, thread_id threadID,
145 DebuggerInterface*& _interface) const
147 if (teamID < 0 && threadID < 0)
148 return B_BAD_VALUE;
150 status_t error;
151 if (teamID < 0) {
152 thread_info threadInfo;
153 error = get_thread_info(threadID, &threadInfo);
154 if (error != B_OK)
155 return error;
157 teamID = threadInfo.team;
160 LocalDebuggerInterface* interface
161 = new(std::nothrow) LocalDebuggerInterface(teamID);
162 if (interface == NULL)
163 return B_NO_MEMORY;
165 BReference<DebuggerInterface> interfaceReference(interface, true);
166 error = interface->Init();
167 if (error != B_OK)
168 return error;
170 _interface = interface;
171 interfaceReference.Detach();
172 return B_OK;
176 status_t
177 LocalTargetHostInterface::CreateTeam(int commandLineArgc,
178 const char* const* arguments, team_id& _teamID) const
180 thread_id thread = load_program(arguments, commandLineArgc, false);
181 if (thread < 0)
182 return thread;
184 // main thread ID == team ID.
185 _teamID = thread;
186 return B_OK;
190 status_t
191 LocalTargetHostInterface::LoadCore(const char* coreFilePath,
192 DebuggerInterface*& _interface, thread_id& _thread) const
194 // load the core file
195 CoreFile* coreFile = new(std::nothrow) CoreFile;
196 if (coreFile == NULL)
197 return B_NO_MEMORY;
198 ObjectDeleter<CoreFile> coreFileDeleter(coreFile);
200 status_t error = coreFile->Init(coreFilePath);
201 if (error != B_OK)
202 return error;
204 // create the debugger interface
205 CoreFileDebuggerInterface* interface
206 = new(std::nothrow) CoreFileDebuggerInterface(coreFile);
207 if (interface == NULL)
208 return B_NO_MEMORY;
209 coreFileDeleter.Detach();
211 BReference<DebuggerInterface> interfaceReference(interface, true);
212 error = interface->Init();
213 if (error != B_OK)
214 return error;
216 const CoreFileTeamInfo& teamInfo = coreFile->GetTeamInfo();
217 _thread = teamInfo.Id();
218 _interface = interface;
219 interfaceReference.Detach();
221 return B_OK;
225 status_t
226 LocalTargetHostInterface::FindTeamByThread(thread_id thread,
227 team_id& _teamID) const
229 thread_info info;
230 status_t error = get_thread_info(thread, &info);
231 if (error != B_OK)
232 return error;
234 _teamID = info.team;
235 return B_OK;
239 status_t
240 LocalTargetHostInterface::_PortLoop(void* arg)
242 LocalTargetHostInterface* interface = (LocalTargetHostInterface*)arg;
243 set<team_id> waitingTeams;
245 for (;;) {
246 status_t error;
247 bool addToWaiters;
248 char buffer[2048];
249 int32 messageCode;
250 team_id team;
252 ssize_t size = read_port_etc(interface->fDataPort, &messageCode,
253 buffer, sizeof(buffer), B_TIMEOUT, waitingTeams.empty()
254 ? B_INFINITE_TIMEOUT : 20000);
255 if (size == B_INTERRUPTED)
256 continue;
257 else if (size == B_TIMED_OUT && !waitingTeams.empty()) {
258 for (set<team_id>::iterator it = waitingTeams.begin();
259 it != waitingTeams.end(); ++it) {
260 team = *it;
261 error = interface->_HandleTeamEvent(team,
262 B_TEAM_CREATED, addToWaiters);
263 if (error != B_OK)
264 continue;
265 else if (!addToWaiters) {
266 waitingTeams.erase(it);
267 if (waitingTeams.empty())
268 break;
269 it = waitingTeams.begin();
272 continue;
273 } else if (size < 0)
274 return size;
276 KMessage message;
277 size = message.SetTo(buffer);
278 if (size != B_OK)
279 continue;
281 if (message.What() != B_SYSTEM_OBJECT_UPDATE)
282 continue;
284 int32 opcode = 0;
285 if (message.FindInt32("opcode", &opcode) != B_OK)
286 continue;
288 team = -1;
289 if (message.FindInt32("team", &team) != B_OK)
290 continue;
292 error = interface->_HandleTeamEvent(team, opcode,
293 addToWaiters);
294 if (error != B_OK)
295 continue;
296 if (opcode == B_TEAM_CREATED && addToWaiters) {
297 try {
298 waitingTeams.insert(team);
299 } catch (...) {
300 continue;
305 return B_OK;
309 status_t
310 LocalTargetHostInterface::_HandleTeamEvent(team_id team, int32 opcode,
311 bool& addToWaiters)
313 addToWaiters = false;
314 AutoLocker<TargetHost> locker(fTargetHost);
315 switch (opcode) {
316 case B_TEAM_CREATED:
317 case B_TEAM_EXEC:
319 team_info info;
320 status_t error = get_team_info(team, &info);
321 // this team is already gone, no point in sending a notification
322 if (error == B_BAD_TEAM_ID)
323 return B_OK;
324 else if (error != B_OK)
325 return error;
326 else {
327 int32 cookie = 0;
328 image_info imageInfo;
329 addToWaiters = true;
330 while (get_next_image_info(team, &cookie, &imageInfo)
331 == B_OK) {
332 if (imageInfo.type == B_APP_IMAGE) {
333 addToWaiters = false;
334 break;
337 if (addToWaiters)
338 return B_OK;
341 if (opcode == B_TEAM_CREATED)
342 fTargetHost->AddTeam(info);
343 else
344 fTargetHost->UpdateTeam(info);
345 break;
348 case B_TEAM_DELETED:
350 fTargetHost->RemoveTeam(team);
351 break;
354 default:
356 break;
360 return B_OK;