xref: /haiku/src/kits/debugger/debugger_interface/local/LocalDebuggerInterface.cpp (revision b02ee147b1b450723bfa0e6842074e230d7c95be)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2010-2016, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include "LocalDebuggerInterface.h"
8 
9 #include <new>
10 
11 #include <stdio.h>
12 
13 #include <Locker.h>
14 
15 #include <AutoLocker.h>
16 #include <memory_private.h>
17 #include <OS.h>
18 #include <system_info.h>
19 #include <util/DoublyLinkedList.h>
20 #include <util/KMessage.h>
21 
22 #include "debug_utils.h"
23 
24 #include "ArchitectureX86.h"
25 #include "ArchitectureX8664.h"
26 #include "AreaInfo.h"
27 #include "AutoDeleter.h"
28 #include "CpuState.h"
29 #include "DebugEvent.h"
30 #include "ImageInfo.h"
31 #include "SemaphoreInfo.h"
32 #include "SymbolInfo.h"
33 #include "SystemInfo.h"
34 #include "TeamInfo.h"
35 #include "ThreadInfo.h"
36 
37 
38 // number of debug contexts the pool does initially create
39 static const int kInitialDebugContextCount = 3;
40 
41 // maximum number of debug contexts in the pool
42 static const int kMaxDebugContextCount = 10;
43 
44 
45 // #pragma mark - LocalDebuggerInterface::DebugContext
46 
47 struct LocalDebuggerInterface::DebugContext : debug_context,
48 		DoublyLinkedListLinkImpl<DebugContext> {
DebugContextLocalDebuggerInterface::DebugContext49 	DebugContext()
50 	{
51 		team = -1;
52 		nub_port = -1;
53 		reply_port = -1;
54 	}
55 
~DebugContextLocalDebuggerInterface::DebugContext56 	~DebugContext()
57 	{
58 		if (reply_port >= 0)
59 			destroy_debug_context(this);
60 	}
61 
InitLocalDebuggerInterface::DebugContext62 	status_t Init(team_id team, port_id nubPort)
63 	{
64 		return init_debug_context(this, team, nubPort);
65 	}
66 
CloseLocalDebuggerInterface::DebugContext67 	void Close()
68 	{
69 		if (reply_port >= 0) {
70 			destroy_debug_context(this);
71 			team = -1;
72 			nub_port = -1;
73 			reply_port = -1;
74 		}
75 	}
76 };
77 
78 // #pragma mark - LocalDebuggerInterface::DebugContextPool
79 
80 struct LocalDebuggerInterface::DebugContextPool {
DebugContextPoolLocalDebuggerInterface::DebugContextPool81 	DebugContextPool(team_id team, port_id nubPort)
82 		:
83 		fLock("debug context pool"),
84 		fTeam(team),
85 		fNubPort(nubPort),
86 		fBlockSem(-1),
87 		fContextCount(0),
88 		fWaiterCount(0),
89 		fClosed(false)
90 	{
91 	}
92 
~DebugContextPoolLocalDebuggerInterface::DebugContextPool93 	~DebugContextPool()
94 	{
95 		AutoLocker<BLocker> locker(fLock);
96 
97 		while (DebugContext* context = fFreeContexts.RemoveHead())
98 			delete context;
99 
100 		if (fBlockSem >= 0)
101 			delete_sem(fBlockSem);
102 	}
103 
InitLocalDebuggerInterface::DebugContextPool104 	status_t Init()
105 	{
106 		status_t error = fLock.InitCheck();
107 		if (error != B_OK)
108 			return error;
109 
110 		fBlockSem = create_sem(0, "debug context pool block");
111 		if (fBlockSem < 0)
112 			return fBlockSem;
113 
114 		for (int i = 0; i < kInitialDebugContextCount; i++) {
115 			DebugContext* context;
116 			error = _CreateDebugContext(context);
117 			if (error != B_OK)
118 				return error;
119 
120 			fFreeContexts.Add(context);
121 		}
122 
123 		return B_OK;
124 	}
125 
CloseLocalDebuggerInterface::DebugContextPool126 	void Close()
127 	{
128 		AutoLocker<BLocker> locker(fLock);
129 		fClosed = true;
130 
131 		for (DebugContextList::Iterator it = fFreeContexts.GetIterator();
132 				DebugContext* context = it.Next();) {
133 			context->Close();
134 		}
135 
136 		for (DebugContextList::Iterator it = fUsedContexts.GetIterator();
137 				DebugContext* context = it.Next();) {
138 			context->Close();
139 		}
140 	}
141 
GetContextLocalDebuggerInterface::DebugContextPool142 	DebugContext* GetContext()
143 	{
144 		AutoLocker<BLocker> locker(fLock);
145 		DebugContext* context = fFreeContexts.RemoveHead();
146 
147 		if (context == NULL) {
148 			if (fContextCount >= kMaxDebugContextCount
149 				|| _CreateDebugContext(context) != B_OK) {
150 				// wait for a free context
151 				while (context == NULL) {
152 					fWaiterCount++;
153 					locker.Unlock();
154 					while (acquire_sem(fBlockSem) != B_OK);
155 					locker.Lock();
156 					context = fFreeContexts.RemoveHead();
157 				}
158 			}
159 		}
160 
161 		fUsedContexts.Add(context);
162 
163 		return context;
164 	}
165 
PutContextLocalDebuggerInterface::DebugContextPool166 	void PutContext(DebugContext* context)
167 	{
168 		AutoLocker<BLocker> locker(fLock);
169 		fUsedContexts.Remove(context);
170 		fFreeContexts.Add(context);
171 
172 		if (fWaiterCount > 0)
173 			release_sem(fBlockSem);
174 	}
175 
176 private:
177 	typedef DoublyLinkedList<DebugContext> DebugContextList;
178 
179 private:
_CreateDebugContextLocalDebuggerInterface::DebugContextPool180 	status_t _CreateDebugContext(DebugContext*& _context)
181 	{
182 		DebugContext* context = new(std::nothrow) DebugContext;
183 		if (context == NULL)
184 			return B_NO_MEMORY;
185 
186 		if (!fClosed) {
187 			status_t error = context->Init(fTeam, fNubPort);
188 			if (error != B_OK) {
189 				delete context;
190 				return error;
191 			}
192 		}
193 
194 		fContextCount++;
195 
196 		_context = context;
197 		return B_OK;
198 	}
199 
200 private:
201 	BLocker				fLock;
202 	team_id				fTeam;
203 	port_id				fNubPort;
204 	sem_id				fBlockSem;
205 	int32				fContextCount;
206 	int32				fWaiterCount;
207 	DebugContextList	fFreeContexts;
208 	DebugContextList	fUsedContexts;
209 	bool				fClosed;
210 };
211 
212 
213 struct LocalDebuggerInterface::DebugContextGetter {
DebugContextGetterLocalDebuggerInterface::DebugContextGetter214 	DebugContextGetter(DebugContextPool* pool)
215 		:
216 		fPool(pool),
217 		fContext(pool->GetContext())
218 	{
219 	}
220 
~DebugContextGetterLocalDebuggerInterface::DebugContextGetter221 	~DebugContextGetter()
222 	{
223 		fPool->PutContext(fContext);
224 	}
225 
ContextLocalDebuggerInterface::DebugContextGetter226 	DebugContext* Context() const
227 	{
228 		return fContext;
229 	}
230 
231 private:
232 	DebugContextPool*	fPool;
233 	DebugContext*		fContext;
234 };
235 
236 // #pragma mark - LocalDebuggerInterface
237 
LocalDebuggerInterface(team_id team)238 LocalDebuggerInterface::LocalDebuggerInterface(team_id team)
239 	:
240 	DebuggerInterface(),
241 	fTeamID(team),
242 	fDebuggerPort(-1),
243 	fNubPort(-1),
244 	fDebugContextPool(NULL),
245 	fArchitecture(NULL)
246 {
247 }
248 
249 
~LocalDebuggerInterface()250 LocalDebuggerInterface::~LocalDebuggerInterface()
251 {
252 	if (fArchitecture != NULL)
253 		fArchitecture->ReleaseReference();
254 
255 	Close(false);
256 
257 	delete fDebugContextPool;
258 }
259 
260 
261 status_t
Init()262 LocalDebuggerInterface::Init()
263 {
264 	// create the architecture
265 #if defined(ARCH_x86)
266 	fArchitecture = new(std::nothrow) ArchitectureX86(this);
267 #elif defined(ARCH_x86_64)
268 	fArchitecture = new(std::nothrow) ArchitectureX8664(this);
269 #else
270 	return B_UNSUPPORTED;
271 #endif
272 
273 	if (fArchitecture == NULL)
274 		return B_NO_MEMORY;
275 
276 	status_t error = fArchitecture->Init();
277 	if (error != B_OK)
278 		return error;
279 
280 	// create debugger port
281 	char buffer[128];
282 	snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debugger", fTeamID);
283 	fDebuggerPort = create_port(100, buffer);
284 	if (fDebuggerPort < 0)
285 		return fDebuggerPort;
286 
287 	// install as team debugger
288 	fNubPort = install_team_debugger(fTeamID, fDebuggerPort);
289 	if (fNubPort < 0)
290 		return fNubPort;
291 
292 	error = __start_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES,
293 		fDebuggerPort, 0);
294 	if (error != B_OK)
295 		return error;
296 
297 	// create debug context pool
298 	fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort);
299 	if (fDebugContextPool == NULL)
300 		return B_NO_MEMORY;
301 
302 	error = fDebugContextPool->Init();
303 	if (error != B_OK)
304 		return error;
305 
306 	return B_OK;
307 }
308 
309 
310 void
Close(bool killTeam)311 LocalDebuggerInterface::Close(bool killTeam)
312 {
313 	if (killTeam)
314 		kill_team(fTeamID);
315 	else if (fNubPort >= 0)
316 		remove_team_debugger(fTeamID);
317 
318 	if (fDebuggerPort >= 0) {
319 		__stop_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES,
320 			fDebuggerPort, 0);
321 		delete_port(fDebuggerPort);
322 	}
323 
324 	fNubPort = -1;
325 	fDebuggerPort = -1;
326 }
327 
328 
329 bool
Connected() const330 LocalDebuggerInterface::Connected() const
331 {
332 	return fNubPort >= 0;
333 }
334 
335 
336 team_id
TeamID() const337 LocalDebuggerInterface::TeamID() const
338 {
339 	return fTeamID;
340 }
341 
342 
343 Architecture*
GetArchitecture() const344 LocalDebuggerInterface::GetArchitecture() const
345 {
346 	return fArchitecture;
347 }
348 
349 
350 status_t
GetNextDebugEvent(DebugEvent * & _event)351 LocalDebuggerInterface::GetNextDebugEvent(DebugEvent*& _event)
352 {
353 	while (true) {
354 		char buffer[2048];
355 		int32 messageCode;
356 		ssize_t size = read_port(fDebuggerPort, &messageCode, buffer,
357 			sizeof(buffer));
358 		if (size < 0) {
359 			if (size == B_INTERRUPTED)
360 				continue;
361 
362 			return size;
363 		}
364 
365 		if (messageCode <= B_DEBUGGER_MESSAGE_HANDED_OVER) {
366  			debug_debugger_message_data message;
367 			memcpy(&message, buffer, size);
368 			if (message.origin.team != fTeamID)
369 				continue;
370 
371 			bool ignore = false;
372 			status_t error = _CreateDebugEvent(messageCode, message, ignore,
373 				_event);
374 			if (error != B_OK)
375 				return error;
376 
377 			if (ignore) {
378 				if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
379 					error = continue_thread(message.origin.nub_port,
380 						message.origin.thread);
381 				if (error != B_OK)
382 					return error;
383 				continue;
384 			}
385 
386 			return B_OK;
387 		}
388 
389 		KMessage message;
390 		size = message.SetTo(buffer);
391 		if (size != B_OK)
392 			return size;
393 		return _GetNextSystemWatchEvent(_event, message);
394 	}
395 
396 	return B_OK;
397 }
398 
399 
400 status_t
SetTeamDebuggingFlags(uint32 flags)401 LocalDebuggerInterface::SetTeamDebuggingFlags(uint32 flags)
402 {
403 	return set_team_debugging_flags(fNubPort, flags);
404 }
405 
406 
407 status_t
ContinueThread(thread_id thread)408 LocalDebuggerInterface::ContinueThread(thread_id thread)
409 {
410 	return continue_thread(fNubPort, thread);
411 }
412 
413 
414 status_t
StopThread(thread_id thread)415 LocalDebuggerInterface::StopThread(thread_id thread)
416 {
417 	return debug_thread(thread);
418 }
419 
420 
421 status_t
SingleStepThread(thread_id thread)422 LocalDebuggerInterface::SingleStepThread(thread_id thread)
423 {
424 	debug_nub_continue_thread continueMessage;
425 	continueMessage.thread = thread;
426 	continueMessage.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
427 	continueMessage.single_step = true;
428 
429 	return write_port(fNubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD,
430 		&continueMessage, sizeof(continueMessage));
431 }
432 
433 
434 status_t
InstallBreakpoint(target_addr_t address)435 LocalDebuggerInterface::InstallBreakpoint(target_addr_t address)
436 {
437 	DebugContextGetter contextGetter(fDebugContextPool);
438 
439 	debug_nub_set_breakpoint message;
440 	message.reply_port = contextGetter.Context()->reply_port;
441 	message.address = (void*)(addr_t)address;
442 
443 	debug_nub_set_breakpoint_reply reply;
444 
445 	status_t error = send_debug_message(contextGetter.Context(),
446 		B_DEBUG_MESSAGE_SET_BREAKPOINT, &message, sizeof(message), &reply,
447 		sizeof(reply));
448 	return error == B_OK ? reply.error : error;
449 }
450 
451 
452 status_t
UninstallBreakpoint(target_addr_t address)453 LocalDebuggerInterface::UninstallBreakpoint(target_addr_t address)
454 {
455 	debug_nub_clear_breakpoint message;
456 	message.address = (void*)(addr_t)address;
457 
458 	return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_BREAKPOINT,
459 		&message, sizeof(message));
460 }
461 
462 
463 status_t
InstallWatchpoint(target_addr_t address,uint32 type,int32 length)464 LocalDebuggerInterface::InstallWatchpoint(target_addr_t address, uint32 type,
465 	int32 length)
466 {
467 	DebugContextGetter contextGetter(fDebugContextPool);
468 
469 	debug_nub_set_watchpoint message;
470 	message.reply_port = contextGetter.Context()->reply_port;
471 	message.address = (void*)(addr_t)address;
472 	message.type = type;
473 	message.length = length;
474 
475 	debug_nub_set_watchpoint_reply reply;
476 
477 	status_t error = send_debug_message(contextGetter.Context(),
478 		B_DEBUG_MESSAGE_SET_WATCHPOINT, &message, sizeof(message), &reply,
479 		sizeof(reply));
480 	return error == B_OK ? reply.error : error;
481 }
482 
483 
484 status_t
UninstallWatchpoint(target_addr_t address)485 LocalDebuggerInterface::UninstallWatchpoint(target_addr_t address)
486 {
487 	DebugContextGetter contextGetter(fDebugContextPool);
488 
489 	debug_nub_clear_watchpoint message;
490 	message.address = (void*)(addr_t)address;
491 
492 	return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_WATCHPOINT,
493 		&message, sizeof(message));
494 }
495 
496 
497 status_t
GetSystemInfo(SystemInfo & info)498 LocalDebuggerInterface::GetSystemInfo(SystemInfo& info)
499 {
500 	system_info sysInfo;
501 	status_t result = get_system_info(&sysInfo);
502 	if (result != B_OK)
503 		return result;
504 
505 	utsname name;
506 	result = uname(&name);
507 	if (result != B_OK)
508 		return result;
509 
510 	info.SetTo(fTeamID, sysInfo, name);
511 	return B_OK;
512 }
513 
514 
515 status_t
GetTeamInfo(TeamInfo & info)516 LocalDebuggerInterface::GetTeamInfo(TeamInfo& info)
517 {
518 	team_info teamInfo;
519 	status_t result = get_team_info(fTeamID, &teamInfo);
520 	if (result != B_OK)
521 		return result;
522 
523 	info.SetTo(fTeamID, teamInfo);
524 	return B_OK;
525 }
526 
527 
528 status_t
GetThreadInfos(BObjectList<ThreadInfo> & infos)529 LocalDebuggerInterface::GetThreadInfos(BObjectList<ThreadInfo>& infos)
530 {
531 	thread_info threadInfo;
532 	int32 cookie = 0;
533 	while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) {
534 		ThreadInfo* info = new(std::nothrow) ThreadInfo(threadInfo.team,
535 			threadInfo.thread, threadInfo.name);
536 		if (info == NULL || !infos.AddItem(info)) {
537 			delete info;
538 			return B_NO_MEMORY;
539 		}
540 	}
541 
542 	return B_OK;
543 }
544 
545 
546 status_t
GetImageInfos(BObjectList<ImageInfo> & infos)547 LocalDebuggerInterface::GetImageInfos(BObjectList<ImageInfo>& infos)
548 {
549 	// get the team's images
550 	image_info imageInfo;
551 	int32 cookie = 0;
552 	while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) {
553 		ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id,
554 			imageInfo.name, imageInfo.type, (addr_t)imageInfo.text,
555 			imageInfo.text_size, (addr_t)imageInfo.data, imageInfo.data_size);
556 		if (info == NULL || !infos.AddItem(info)) {
557 			delete info;
558 			return B_NO_MEMORY;
559 		}
560 	}
561 
562 	return B_OK;
563 }
564 
565 
566 status_t
GetAreaInfos(BObjectList<AreaInfo> & infos)567 LocalDebuggerInterface::GetAreaInfos(BObjectList<AreaInfo>& infos)
568 {
569 	// get the team's areas
570 	area_info areaInfo;
571 	ssize_t cookie = 0;
572 	while (get_next_area_info(fTeamID, &cookie, &areaInfo) == B_OK) {
573 		AreaInfo* info = new(std::nothrow) AreaInfo(fTeamID, areaInfo.area,
574 			areaInfo.name, (addr_t)areaInfo.address, areaInfo.size,
575 			areaInfo.ram_size, areaInfo.lock, areaInfo.protection);
576 		if (info == NULL || !infos.AddItem(info)) {
577 			delete info;
578 			return B_NO_MEMORY;
579 		}
580 	}
581 
582 	return B_OK;
583 }
584 
585 
586 status_t
GetSemaphoreInfos(BObjectList<SemaphoreInfo> & infos)587 LocalDebuggerInterface::GetSemaphoreInfos(BObjectList<SemaphoreInfo>& infos)
588 {
589 	// get the team's semaphores
590 	sem_info semInfo;
591 	int32 cookie = 0;
592 	while (get_next_sem_info(fTeamID, &cookie, &semInfo) == B_OK) {
593 		SemaphoreInfo* info = new(std::nothrow) SemaphoreInfo(fTeamID,
594 			semInfo.sem, semInfo.name, semInfo.count, semInfo.latest_holder);
595 		if (info == NULL || !infos.AddItem(info)) {
596 			delete info;
597 			return B_NO_MEMORY;
598 		}
599 	}
600 
601 	return B_OK;
602 }
603 
604 
605 status_t
GetSymbolInfos(team_id team,image_id image,BObjectList<SymbolInfo> & infos)606 LocalDebuggerInterface::GetSymbolInfos(team_id team, image_id image,
607 	BObjectList<SymbolInfo>& infos)
608 {
609 	// create a lookup context
610 	debug_symbol_lookup_context* lookupContext;
611 	status_t error = debug_create_symbol_lookup_context(team, image,
612 		&lookupContext);
613 	if (error != B_OK)
614 		return error;
615 
616 	// create a symbol iterator
617 	debug_symbol_iterator* iterator;
618 	error = debug_create_image_symbol_iterator(
619 		lookupContext, image, &iterator);
620 	if (error != B_OK) {
621 		debug_delete_symbol_lookup_context(lookupContext);
622 		return error;
623 	}
624 
625 	// get the symbols
626 	char name[1024];
627 	int32 type;
628 	void* address;
629 	size_t size;
630 	while (debug_next_image_symbol(iterator, name, sizeof(name), &type,
631 			&address, &size) == B_OK) {
632 		SymbolInfo* info = new(std::nothrow) SymbolInfo(
633 			(target_addr_t)(addr_t)address, size, type, name);
634 		if (info == NULL)
635 			break;
636 		if (!infos.AddItem(info)) {
637 			delete info;
638 			break;
639 		}
640 	}
641 
642 	// delete the symbol iterator and lookup context
643 	debug_delete_symbol_iterator(iterator);
644 	debug_delete_symbol_lookup_context(lookupContext);
645 
646 	return B_OK;
647 }
648 
649 
650 status_t
GetSymbolInfo(team_id team,image_id image,const char * name,int32 symbolType,SymbolInfo & info)651 LocalDebuggerInterface::GetSymbolInfo(team_id team, image_id image, const char* name,
652 	int32 symbolType, SymbolInfo& info)
653 {
654 	// create a lookup context
655 	debug_symbol_lookup_context* lookupContext;
656 	status_t error = debug_create_symbol_lookup_context(team, image,
657 		&lookupContext);
658 	if (error != B_OK)
659 		return error;
660 
661 	// try to get the symbol
662 	void* foundAddress;
663 	size_t foundSize;
664 	int32 foundType;
665 	error = debug_get_symbol(lookupContext, image, name, symbolType,
666 		&foundAddress, &foundSize, &foundType);
667 	if (error == B_OK) {
668 		info.SetTo((target_addr_t)(addr_t)foundAddress, foundSize, foundType,
669 			name);
670 	}
671 
672 	// delete the lookup context
673 	debug_delete_symbol_lookup_context(lookupContext);
674 
675 	return error;
676 }
677 
678 
679 status_t
GetThreadInfo(thread_id thread,ThreadInfo & info)680 LocalDebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info)
681 {
682 	thread_info threadInfo;
683 	status_t error = get_thread_info(thread, &threadInfo);
684 	if (error != B_OK)
685 		return error;
686 
687 	info.SetTo(threadInfo.team, threadInfo.thread, threadInfo.name);
688 	return B_OK;
689 }
690 
691 
692 status_t
GetCpuState(thread_id thread,CpuState * & _state)693 LocalDebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state)
694 {
695 	debug_cpu_state debugState;
696 	status_t error = _GetDebugCpuState(thread, debugState);
697 	if (error != B_OK)
698 		return error;
699 	return fArchitecture->CreateCpuState(&debugState, sizeof(debug_cpu_state),
700 		_state);
701 }
702 
703 
704 status_t
SetCpuState(thread_id thread,const CpuState * state)705 LocalDebuggerInterface::SetCpuState(thread_id thread, const CpuState* state)
706 {
707 	debug_cpu_state debugState;
708 	status_t error = _GetDebugCpuState(thread, debugState);
709 	if (error != B_OK)
710 		return error;
711 
712 	DebugContextGetter contextGetter(fDebugContextPool);
713 
714 	error = state->UpdateDebugState(&debugState, sizeof(debugState));
715 	if (error != B_OK)
716 		return error;
717 
718 	debug_nub_set_cpu_state message;
719 	message.thread = thread;
720 
721 	memcpy(&message.cpu_state, &debugState, sizeof(debugState));
722 
723 	return send_debug_message(contextGetter.Context(),
724 		B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL,
725 		0);
726 }
727 
728 
729 status_t
GetCpuFeatures(uint32 & flags)730 LocalDebuggerInterface::GetCpuFeatures(uint32& flags)
731 {
732 	return fArchitecture->GetCpuFeatures(flags);
733 }
734 
735 
736 status_t
WriteCoreFile(const char * path)737 LocalDebuggerInterface::WriteCoreFile(const char* path)
738 {
739 	DebugContextGetter contextGetter(fDebugContextPool);
740 
741 	debug_nub_write_core_file_reply reply;
742 
743 	debug_nub_write_core_file message;
744 	message.reply_port = contextGetter.Context()->reply_port;
745 	strlcpy(message.path, path, sizeof(message.path));
746 
747 	status_t error = send_debug_message(contextGetter.Context(),
748 		B_DEBUG_WRITE_CORE_FILE, &message, sizeof(message), &reply,
749 		sizeof(reply));
750 	if (error == B_OK)
751 		error = reply.error;
752 
753 	return error;
754 }
755 
756 
757 status_t
GetMemoryProperties(target_addr_t address,uint32 & protection,uint32 & locking)758 LocalDebuggerInterface::GetMemoryProperties(target_addr_t address,
759 	uint32& protection, uint32& locking)
760 {
761 	return get_memory_properties(fTeamID, (const void *)address,
762 		&protection, &locking);
763 }
764 
765 
766 ssize_t
ReadMemory(target_addr_t address,void * buffer,size_t size)767 LocalDebuggerInterface::ReadMemory(target_addr_t address, void* buffer, size_t size)
768 {
769 	DebugContextGetter contextGetter(fDebugContextPool);
770 
771 	return debug_read_memory(contextGetter.Context(),
772 		(const void*)(addr_t)address, buffer, size);
773 }
774 
775 
776 ssize_t
WriteMemory(target_addr_t address,void * buffer,size_t size)777 LocalDebuggerInterface::WriteMemory(target_addr_t address, void* buffer,
778 	size_t size)
779 {
780 	DebugContextGetter contextGetter(fDebugContextPool);
781 
782 	return debug_write_memory(contextGetter.Context(),
783 		(const void*)address, buffer, size);
784 }
785 
786 
787 status_t
_CreateDebugEvent(int32 messageCode,const debug_debugger_message_data & message,bool & _ignore,DebugEvent * & _event)788 LocalDebuggerInterface::_CreateDebugEvent(int32 messageCode,
789 	const debug_debugger_message_data& message, bool& _ignore,
790 	DebugEvent*& _event)
791 {
792 	DebugEvent* event = NULL;
793 
794 	switch (messageCode) {
795 		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
796 			event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team,
797 				message.origin.thread);
798 			break;
799 		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
800 			event = new(std::nothrow) DebuggerCallEvent(message.origin.team,
801 				message.origin.thread,
802 				(target_addr_t)message.debugger_call.message);
803 			break;
804 		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
805 		{
806 			CpuState* state = NULL;
807 			status_t error = fArchitecture->CreateCpuState(
808 				&message.breakpoint_hit.cpu_state,
809 				sizeof(debug_cpu_state), state);
810 			if (error != B_OK)
811 				return error;
812 
813 			event = new(std::nothrow) BreakpointHitEvent(message.origin.team,
814 				message.origin.thread, state);
815 			state->ReleaseReference();
816 			break;
817 		}
818 		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
819 		{
820 			CpuState* state = NULL;
821 			status_t error = fArchitecture->CreateCpuState(
822 				&message.watchpoint_hit.cpu_state,
823 				sizeof(debug_cpu_state), state);
824 			if (error != B_OK)
825 				return error;
826 
827 			event = new(std::nothrow) WatchpointHitEvent(message.origin.team,
828 				message.origin.thread, state);
829 			state->ReleaseReference();
830 			break;
831 		}
832 		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
833 		{
834 			CpuState* state = NULL;
835 			status_t error = fArchitecture->CreateCpuState(
836 				&message.single_step.cpu_state,
837 				sizeof(debug_cpu_state), state);
838 			if (error != B_OK)
839 				return error;
840 
841 			event = new(std::nothrow) SingleStepEvent(message.origin.team,
842 				message.origin.thread, state);
843 			state->ReleaseReference();
844 			break;
845 		}
846 		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
847 			event = new(std::nothrow) ExceptionOccurredEvent(
848 				message.origin.team, message.origin.thread,
849 				message.exception_occurred.exception);
850 			break;
851 		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
852 			if (message.origin.team != fTeamID) {
853 				_ignore = true;
854 				return B_OK;
855 			}
856 			event = new(std::nothrow) TeamDeletedEvent(message.origin.team,
857 				message.origin.thread);
858 			break;
859 		case B_DEBUGGER_MESSAGE_TEAM_EXEC:
860 			if (message.origin.team != fTeamID) {
861 				_ignore = true;
862 				return B_OK;
863 			}
864 			event = new(std::nothrow) TeamExecEvent(message.origin.team,
865 				message.origin.thread);
866 			break;
867 		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
868 			event = new(std::nothrow) ThreadCreatedEvent(message.origin.team,
869 				message.origin.thread, message.thread_created.new_thread);
870 			break;
871 		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
872 			event = new(std::nothrow) ThreadDeletedEvent(message.origin.team,
873 				message.origin.thread);
874 			break;
875 		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
876 		{
877 			const image_info& info = message.image_created.info;
878 			event = new(std::nothrow) ImageCreatedEvent(message.origin.team,
879 				message.origin.thread,
880 				ImageInfo(fTeamID, info.id, info.name, info.type,
881 					(addr_t)info.text, info.text_size, (addr_t)info.data,
882 					info.data_size));
883 			break;
884 		}
885 		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
886 		{
887 			const image_info& info = message.image_deleted.info;
888 			event = new(std::nothrow) ImageDeletedEvent(message.origin.team,
889 				message.origin.thread,
890 				ImageInfo(fTeamID, info.id, info.name, info.type,
891 					(addr_t)info.text, info.text_size, (addr_t)info.data,
892 					info.data_size));
893 			break;
894 		}
895 		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
896 		{
897 			event = new(std::nothrow) PostSyscallEvent(message.origin.team,
898 				message.origin.thread,
899 				SyscallInfo(message.post_syscall.start_time,
900 					message.post_syscall.end_time,
901 					message.post_syscall.return_value,
902 					message.post_syscall.syscall, message.post_syscall.args));
903 			break;
904 		}
905 		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
906 		{
907 			event = new(std::nothrow) SignalReceivedEvent(message.origin.team,
908 				message.origin.thread,
909 				SignalInfo(message.signal_received.signal,
910 					message.signal_received.handler,
911 					message.signal_received.deadly));
912 			break;
913 		}
914 		default:
915 			printf("DebuggerInterface for team %" B_PRId32 ": unknown message "
916 				"from kernel: %" B_PRId32 "\n", fTeamID, messageCode);
917 			// fall through...
918 		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
919 		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
920 		case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
921 		case B_DEBUGGER_MESSAGE_HANDED_OVER:
922 			_ignore = true;
923 			return B_OK;
924 	}
925 
926 	if (event == NULL)
927 		return B_NO_MEMORY;
928 
929 	if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
930 		event->SetThreadStopped(true);
931 
932 	_ignore = false;
933 	_event = event;
934 
935 	return B_OK;
936 }
937 
938 
939 status_t
_GetNextSystemWatchEvent(DebugEvent * & _event,KMessage & message)940 LocalDebuggerInterface::_GetNextSystemWatchEvent(DebugEvent*& _event,
941 	KMessage& message)
942 {
943 	status_t error = B_OK;
944 	if (message.What() != B_SYSTEM_OBJECT_UPDATE)
945 		return B_BAD_DATA;
946 
947 	int32 opcode = 0;
948 	if (message.FindInt32("opcode", &opcode) != B_OK)
949 		return B_BAD_DATA;
950 
951 	DebugEvent* event = NULL;
952 	switch (opcode)
953 	{
954 		case B_THREAD_NAME_CHANGED:
955 		{
956 			int32 threadID = -1;
957 			if (message.FindInt32("thread", &threadID) != B_OK)
958 				break;
959 
960 			thread_info info;
961 			error = get_thread_info(threadID, &info);
962 			if (error != B_OK)
963 				break;
964 
965 			event = new(std::nothrow) ThreadRenamedEvent(fTeamID,
966 				threadID, threadID, info.name);
967 			break;
968 		}
969 
970 		default:
971 		{
972 			error = B_BAD_DATA;
973 			break;
974 		}
975 	}
976 
977 	if (event != NULL)
978 		_event = event;
979 
980 	return error;
981 }
982 
983 
984 status_t
_GetDebugCpuState(thread_id thread,debug_cpu_state & _state)985 LocalDebuggerInterface::_GetDebugCpuState(thread_id thread, debug_cpu_state& _state)
986 {
987 	DebugContextGetter contextGetter(fDebugContextPool);
988 
989 	debug_nub_get_cpu_state message;
990 	message.reply_port = contextGetter.Context()->reply_port;
991 	message.thread = thread;
992 
993 	debug_nub_get_cpu_state_reply reply;
994 
995 	status_t error = send_debug_message(contextGetter.Context(),
996 		B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply,
997 		sizeof(reply));
998 	if (error != B_OK)
999 		return error;
1000 	if (reply.error != B_OK)
1001 		return reply.error;
1002 
1003 	memcpy(&_state, &reply.cpu_state, sizeof(debug_cpu_state));
1004 
1005 	return B_OK;
1006 }
1007