1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Team.h"
8
9#include <stdio.h>
10
11#include <new>
12
13#include <AutoLocker.h>
14
15#include "Breakpoint.h"
16#include "DisassembledCode.h"
17#include "FileSourceCode.h"
18#include "Function.h"
19#include "ImageDebugInfo.h"
20#include "SourceCode.h"
21#include "SpecificImageDebugInfo.h"
22#include "Statement.h"
23#include "TeamDebugInfo.h"
24#include "Tracing.h"
25#include "Watchpoint.h"
26
27
28// #pragma mark - BreakpointByAddressPredicate
29
30
31struct Team::BreakpointByAddressPredicate
32	: UnaryPredicate<Breakpoint> {
33	BreakpointByAddressPredicate(target_addr_t address)
34		:
35		fAddress(address)
36	{
37	}
38
39	virtual int operator()(const Breakpoint* breakpoint) const
40	{
41		return -Breakpoint::CompareAddressBreakpoint(&fAddress, breakpoint);
42	}
43
44private:
45	target_addr_t	fAddress;
46};
47
48
49// #pragma mark - WatchpointByAddressPredicate
50
51
52struct Team::WatchpointByAddressPredicate
53	: UnaryPredicate<Watchpoint> {
54	WatchpointByAddressPredicate(target_addr_t address)
55		:
56		fAddress(address)
57	{
58	}
59
60	virtual int operator()(const Watchpoint* watchpoint) const
61	{
62		return -Watchpoint::CompareAddressWatchpoint(&fAddress, watchpoint);
63	}
64
65private:
66	target_addr_t	fAddress;
67};
68
69
70// #pragma mark - Team
71
72
73Team::Team(team_id teamID, TeamMemory* teamMemory, Architecture* architecture,
74	TeamDebugInfo* debugInfo, TeamTypeInformation* typeInformation)
75	:
76	fLock("team lock"),
77	fID(teamID),
78	fTeamMemory(teamMemory),
79	fTypeInformation(typeInformation),
80	fArchitecture(architecture),
81	fDebugInfo(debugInfo)
82{
83	fDebugInfo->AcquireReference();
84}
85
86
87Team::~Team()
88{
89	while (UserBreakpoint* userBreakpoint = fUserBreakpoints.RemoveHead())
90		userBreakpoint->ReleaseReference();
91
92	for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++)
93		breakpoint->ReleaseReference();
94
95	for (int32 i = 0; Watchpoint* watchpoint = fWatchpoints.ItemAt(i); i++)
96		watchpoint->ReleaseReference();
97
98	while (Image* image = fImages.RemoveHead())
99		image->ReleaseReference();
100
101	while (Thread* thread = fThreads.RemoveHead())
102		thread->ReleaseReference();
103
104	fDebugInfo->ReleaseReference();
105}
106
107
108status_t
109Team::Init()
110{
111	return fLock.InitCheck();
112}
113
114
115void
116Team::SetName(const BString& name)
117{
118	fName = name;
119}
120
121
122void
123Team::AddThread(Thread* thread)
124{
125	fThreads.Add(thread);
126	_NotifyThreadAdded(thread);
127}
128
129
130
131status_t
132Team::AddThread(const ThreadInfo& threadInfo, Thread** _thread)
133{
134	Thread* thread = new(std::nothrow) Thread(this, threadInfo.ThreadID());
135	if (thread == NULL)
136		return B_NO_MEMORY;
137
138	status_t error = thread->Init();
139	if (error != B_OK) {
140		delete thread;
141		return error;
142	}
143
144	thread->SetName(threadInfo.Name());
145	AddThread(thread);
146
147	if (_thread != NULL)
148		*_thread = thread;
149
150	return B_OK;
151}
152
153
154void
155Team::RemoveThread(Thread* thread)
156{
157	fThreads.Remove(thread);
158	_NotifyThreadRemoved(thread);
159}
160
161
162bool
163Team::RemoveThread(thread_id threadID)
164{
165	Thread* thread = ThreadByID(threadID);
166	if (thread == NULL)
167		return false;
168
169	RemoveThread(thread);
170	thread->ReleaseReference();
171	return true;
172}
173
174
175Thread*
176Team::ThreadByID(thread_id threadID) const
177{
178	for (ThreadList::ConstIterator it = fThreads.GetIterator();
179			Thread* thread = it.Next();) {
180		if (thread->ID() == threadID)
181			return thread;
182	}
183
184	return NULL;
185}
186
187
188const ThreadList&
189Team::Threads() const
190{
191	return fThreads;
192}
193
194
195status_t
196Team::AddImage(const ImageInfo& imageInfo, LocatableFile* imageFile,
197	Image** _image)
198{
199	Image* image = new(std::nothrow) Image(this, imageInfo, imageFile);
200	if (image == NULL)
201		return B_NO_MEMORY;
202
203	status_t error = image->Init();
204	if (error != B_OK) {
205		delete image;
206		return error;
207	}
208
209	if (image->Type() == B_APP_IMAGE)
210		SetName(image->Name());
211
212	fImages.Add(image);
213	_NotifyImageAdded(image);
214
215	if (_image != NULL)
216		*_image = image;
217
218	return B_OK;
219}
220
221
222void
223Team::RemoveImage(Image* image)
224{
225	fImages.Remove(image);
226	_NotifyImageRemoved(image);
227}
228
229
230bool
231Team::RemoveImage(image_id imageID)
232{
233	Image* image = ImageByID(imageID);
234	if (image == NULL)
235		return false;
236
237	RemoveImage(image);
238	image->ReleaseReference();
239	return true;
240}
241
242
243Image*
244Team::ImageByID(image_id imageID) const
245{
246	for (ImageList::ConstIterator it = fImages.GetIterator();
247			Image* image = it.Next();) {
248		if (image->ID() == imageID)
249			return image;
250	}
251
252	return NULL;
253}
254
255
256Image*
257Team::ImageByAddress(target_addr_t address) const
258{
259	for (ImageList::ConstIterator it = fImages.GetIterator();
260			Image* image = it.Next();) {
261		if (image->ContainsAddress(address))
262			return image;
263	}
264
265	return NULL;
266}
267
268
269const ImageList&
270Team::Images() const
271{
272	return fImages;
273}
274
275
276bool
277Team::AddBreakpoint(Breakpoint* breakpoint)
278{
279	if (fBreakpoints.BinaryInsert(breakpoint, &Breakpoint::CompareBreakpoints))
280		return true;
281
282	breakpoint->ReleaseReference();
283	return false;
284}
285
286
287void
288Team::RemoveBreakpoint(Breakpoint* breakpoint)
289{
290	int32 index = fBreakpoints.BinarySearchIndex(*breakpoint,
291		&Breakpoint::CompareBreakpoints);
292	if (index < 0)
293		return;
294
295	fBreakpoints.RemoveItemAt(index);
296	breakpoint->ReleaseReference();
297}
298
299
300int32
301Team::CountBreakpoints() const
302{
303	return fBreakpoints.CountItems();
304}
305
306
307Breakpoint*
308Team::BreakpointAt(int32 index) const
309{
310	return fBreakpoints.ItemAt(index);
311}
312
313
314Breakpoint*
315Team::BreakpointAtAddress(target_addr_t address) const
316{
317	return fBreakpoints.BinarySearchByKey(address,
318		&Breakpoint::CompareAddressBreakpoint);
319}
320
321
322void
323Team::GetBreakpointsInAddressRange(TargetAddressRange range,
324	BObjectList<UserBreakpoint>& breakpoints) const
325{
326	int32 index = fBreakpoints.FindBinaryInsertionIndex(
327		BreakpointByAddressPredicate(range.Start()));
328	for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) {
329		if (breakpoint->Address() > range.End())
330			break;
331
332		for (UserBreakpointInstanceList::ConstIterator it
333				= breakpoint->UserBreakpoints().GetIterator();
334			UserBreakpointInstance* instance = it.Next();) {
335			breakpoints.AddItem(instance->GetUserBreakpoint());
336		}
337	}
338
339	// TODO: Avoid duplicates!
340}
341
342
343void
344Team::GetBreakpointsForSourceCode(SourceCode* sourceCode,
345	BObjectList<UserBreakpoint>& breakpoints) const
346{
347	if (DisassembledCode* disassembledCode
348			= dynamic_cast<DisassembledCode*>(sourceCode)) {
349		GetBreakpointsInAddressRange(disassembledCode->StatementAddressRange(),
350			breakpoints);
351		return;
352	}
353
354	LocatableFile* sourceFile = sourceCode->GetSourceFile();
355	if (sourceFile == NULL)
356		return;
357
358	// TODO: This can probably be optimized. Maybe by registering the user
359	// breakpoints with the team and sorting them by source code.
360	for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) {
361		UserBreakpointInstance* userBreakpointInstance
362			= breakpoint->FirstUserBreakpoint();
363		if (userBreakpointInstance == NULL)
364			continue;
365
366		UserBreakpoint* userBreakpoint
367			= userBreakpointInstance->GetUserBreakpoint();
368		if (userBreakpoint->Location().SourceFile() == sourceFile)
369			breakpoints.AddItem(userBreakpoint);
370	}
371}
372
373
374void
375Team::AddUserBreakpoint(UserBreakpoint* userBreakpoint)
376{
377	fUserBreakpoints.Add(userBreakpoint);
378	userBreakpoint->AcquireReference();
379}
380
381
382void
383Team::RemoveUserBreakpoint(UserBreakpoint* userBreakpoint)
384{
385	fUserBreakpoints.Remove(userBreakpoint);
386	userBreakpoint->ReleaseReference();
387}
388
389
390bool
391Team::AddWatchpoint(Watchpoint* watchpoint)
392{
393	if (fWatchpoints.BinaryInsert(watchpoint, &Watchpoint::CompareWatchpoints))
394		return true;
395
396	watchpoint->ReleaseReference();
397	return false;
398}
399
400
401void
402Team::RemoveWatchpoint(Watchpoint* watchpoint)
403{
404	int32 index = fWatchpoints.BinarySearchIndex(*watchpoint,
405		&Watchpoint::CompareWatchpoints);
406	if (index < 0)
407		return;
408
409	fWatchpoints.RemoveItemAt(index);
410	watchpoint->ReleaseReference();
411}
412
413
414int32
415Team::CountWatchpoints() const
416{
417	return fWatchpoints.CountItems();
418}
419
420
421Watchpoint*
422Team::WatchpointAt(int32 index) const
423{
424	return fWatchpoints.ItemAt(index);
425}
426
427
428Watchpoint*
429Team::WatchpointAtAddress(target_addr_t address) const
430{
431	return fWatchpoints.BinarySearchByKey(address,
432		&Watchpoint::CompareAddressWatchpoint);
433}
434
435
436void
437Team::GetWatchpointsInAddressRange(TargetAddressRange range,
438	BObjectList<Watchpoint>& watchpoints) const
439{
440	int32 index = fWatchpoints.FindBinaryInsertionIndex(
441		WatchpointByAddressPredicate(range.Start()));
442	for (; Watchpoint* watchpoint = fWatchpoints.ItemAt(index); index++) {
443		if (watchpoint->Address() > range.End())
444			break;
445
446		watchpoints.AddItem(watchpoint);
447	}
448}
449
450
451status_t
452Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function,
453	Statement*& _statement)
454{
455	TRACE_CODE("Team::GetStatementAtAddress(%#" B_PRIx64 ")\n", address);
456
457	// get the image at the address
458	Image* image = ImageByAddress(address);
459	if (image == NULL) {
460		TRACE_CODE("  -> no image\n");
461		return B_ENTRY_NOT_FOUND;
462	}
463
464	ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
465	if (imageDebugInfo == NULL) {
466		TRACE_CODE("  -> no image debug info\n");
467		return B_ENTRY_NOT_FOUND;
468	}
469
470	// get the function
471	FunctionInstance* functionInstance
472		= imageDebugInfo->FunctionAtAddress(address);
473	if (functionInstance == NULL) {
474		TRACE_CODE("  -> no function instance\n");
475		return B_ENTRY_NOT_FOUND;
476	}
477
478	// If the function instance has disassembled code attached, we can get the
479	// statement directly.
480	if (DisassembledCode* code = functionInstance->GetSourceCode()) {
481		Statement* statement = code->StatementAtAddress(address);
482		if (statement == NULL)
483			return B_ENTRY_NOT_FOUND;
484
485		statement->AcquireReference();
486		_statement = statement;
487		_function = functionInstance;
488		return B_OK;
489	}
490
491	// get the statement from the image debug info
492	FunctionDebugInfo* functionDebugInfo
493		= functionInstance->GetFunctionDebugInfo();
494	status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
495		->GetStatement(functionDebugInfo, address, _statement);
496	if (error != B_OK) {
497		TRACE_CODE("  -> no statement from the specific image debug info\n");
498		return error;
499	}
500
501	_function = functionInstance;
502	return B_OK;
503}
504
505
506status_t
507Team::GetStatementAtSourceLocation(SourceCode* sourceCode,
508	const SourceLocation& location, Statement*& _statement)
509{
510	TRACE_CODE("Team::GetStatementAtSourceLocation(%p, (%" B_PRId32 ", %"
511		B_PRId32 "))\n", sourceCode, location.Line(), location.Column());
512
513	// If we're lucky the source code can provide us with a statement.
514	if (DisassembledCode* code = dynamic_cast<DisassembledCode*>(sourceCode)) {
515		Statement* statement = code->StatementAtLocation(location);
516		if (statement == NULL)
517			return B_ENTRY_NOT_FOUND;
518
519		statement->AcquireReference();
520		_statement = statement;
521		return B_OK;
522	}
523
524	// Go the long and stony way over the source file and the team debug info.
525	// get the source file for the source code
526	LocatableFile* sourceFile = sourceCode->GetSourceFile();
527	if (sourceFile == NULL)
528		return B_ENTRY_NOT_FOUND;
529
530	// get the function at the source location
531	Function* function = fDebugInfo->FunctionAtSourceLocation(sourceFile,
532		location);
533	if (function == NULL)
534		return B_ENTRY_NOT_FOUND;
535
536	// Get some function instance and ask its image debug info to provide us
537	// with a statement.
538	FunctionInstance* functionInstance = function->FirstInstance();
539	if (functionInstance == NULL)
540		return B_ENTRY_NOT_FOUND;
541
542	FunctionDebugInfo* functionDebugInfo
543		= functionInstance->GetFunctionDebugInfo();
544	return functionDebugInfo->GetSpecificImageDebugInfo()
545		->GetStatementAtSourceLocation(functionDebugInfo, location, _statement);
546}
547
548
549Function*
550Team::FunctionByID(FunctionID* functionID) const
551{
552	return fDebugInfo->FunctionByID(functionID);
553}
554
555
556void
557Team::AddListener(Listener* listener)
558{
559	AutoLocker<Team> locker(this);
560	fListeners.Add(listener);
561}
562
563
564void
565Team::RemoveListener(Listener* listener)
566{
567	AutoLocker<Team> locker(this);
568	fListeners.Remove(listener);
569}
570
571
572void
573Team::NotifyThreadStateChanged(Thread* thread)
574{
575	for (ListenerList::Iterator it = fListeners.GetIterator();
576			Listener* listener = it.Next();) {
577		listener->ThreadStateChanged(
578			ThreadEvent(TEAM_EVENT_THREAD_STATE_CHANGED, thread));
579	}
580}
581
582
583void
584Team::NotifyThreadCpuStateChanged(Thread* thread)
585{
586	for (ListenerList::Iterator it = fListeners.GetIterator();
587			Listener* listener = it.Next();) {
588		listener->ThreadCpuStateChanged(
589			ThreadEvent(TEAM_EVENT_THREAD_CPU_STATE_CHANGED, thread));
590	}
591}
592
593
594void
595Team::NotifyThreadStackTraceChanged(Thread* thread)
596{
597	for (ListenerList::Iterator it = fListeners.GetIterator();
598			Listener* listener = it.Next();) {
599		listener->ThreadStackTraceChanged(
600			ThreadEvent(TEAM_EVENT_THREAD_STACK_TRACE_CHANGED, thread));
601	}
602}
603
604
605void
606Team::NotifyImageDebugInfoChanged(Image* image)
607{
608	for (ListenerList::Iterator it = fListeners.GetIterator();
609			Listener* listener = it.Next();) {
610		listener->ImageDebugInfoChanged(
611			ImageEvent(TEAM_EVENT_IMAGE_DEBUG_INFO_CHANGED, image));
612	}
613}
614
615
616void
617Team::NotifyUserBreakpointChanged(UserBreakpoint* breakpoint)
618{
619	for (ListenerList::Iterator it = fListeners.GetIterator();
620			Listener* listener = it.Next();) {
621		listener->UserBreakpointChanged(UserBreakpointEvent(
622			TEAM_EVENT_USER_BREAKPOINT_CHANGED, this, breakpoint));
623	}
624}
625
626
627void
628Team::NotifyWatchpointChanged(Watchpoint* watchpoint)
629{
630	for (ListenerList::Iterator it = fListeners.GetIterator();
631			Listener* listener = it.Next();) {
632		listener->WatchpointChanged(WatchpointEvent(
633			TEAM_EVENT_WATCHPOINT_CHANGED, this, watchpoint));
634	}
635}
636
637
638void
639Team::NotifyDebugReportChanged(const char* reportPath)
640{
641	for (ListenerList::Iterator it = fListeners.GetIterator();
642			Listener* listener = it.Next();) {
643		listener->DebugReportChanged(DebugReportEvent(
644			TEAM_EVENT_DEBUG_REPORT_CHANGED, this, reportPath));
645	}
646}
647
648
649void
650Team::_NotifyThreadAdded(Thread* thread)
651{
652	for (ListenerList::Iterator it = fListeners.GetIterator();
653			Listener* listener = it.Next();) {
654		listener->ThreadAdded(ThreadEvent(TEAM_EVENT_THREAD_ADDED, thread));
655	}
656}
657
658
659void
660Team::_NotifyThreadRemoved(Thread* thread)
661{
662	for (ListenerList::Iterator it = fListeners.GetIterator();
663			Listener* listener = it.Next();) {
664		listener->ThreadRemoved(ThreadEvent(TEAM_EVENT_THREAD_REMOVED, thread));
665	}
666}
667
668
669void
670Team::_NotifyImageAdded(Image* image)
671{
672	for (ListenerList::Iterator it = fListeners.GetIterator();
673			Listener* listener = it.Next();) {
674		listener->ImageAdded(ImageEvent(TEAM_EVENT_IMAGE_ADDED, image));
675	}
676}
677
678
679void
680Team::_NotifyImageRemoved(Image* image)
681{
682	for (ListenerList::Iterator it = fListeners.GetIterator();
683			Listener* listener = it.Next();) {
684		listener->ImageRemoved(ImageEvent(TEAM_EVENT_IMAGE_REMOVED, image));
685	}
686}
687
688
689// #pragma mark - Event
690
691
692Team::Event::Event(uint32 type, Team* team)
693	:
694	fEventType(type),
695	fTeam(team)
696{
697}
698
699
700// #pragma mark - ThreadEvent
701
702
703Team::ThreadEvent::ThreadEvent(uint32 type, Thread* thread)
704	:
705	Event(type, thread->GetTeam()),
706	fThread(thread)
707{
708}
709
710
711// #pragma mark - ImageEvent
712
713
714Team::ImageEvent::ImageEvent(uint32 type, Image* image)
715	:
716	Event(type, image->GetTeam()),
717	fImage(image)
718{
719}
720
721
722// #pragma mark - BreakpointEvent
723
724
725Team::BreakpointEvent::BreakpointEvent(uint32 type, Team* team,
726	Breakpoint* breakpoint)
727	:
728	Event(type, team),
729	fBreakpoint(breakpoint)
730{
731}
732
733
734// #pragma mark - DebugReportEvent
735
736
737Team::DebugReportEvent::DebugReportEvent(uint32 type, Team* team,
738	const char* reportPath)
739	:
740	Event(type, team),
741	fReportPath(reportPath)
742{
743}
744
745
746// #pragma mark - WatchpointEvent
747
748
749Team::WatchpointEvent::WatchpointEvent(uint32 type, Team* team,
750	Watchpoint* watchpoint)
751	:
752	Event(type, team),
753	fWatchpoint(watchpoint)
754{
755}
756
757
758// #pragma mark - UserBreakpointEvent
759
760
761Team::UserBreakpointEvent::UserBreakpointEvent(uint32 type, Team* team,
762	UserBreakpoint* breakpoint)
763	:
764	Event(type, team),
765	fBreakpoint(breakpoint)
766{
767}
768
769
770// #pragma mark - Listener
771
772
773Team::Listener::~Listener()
774{
775}
776
777
778void
779Team::Listener::ThreadAdded(const Team::ThreadEvent& event)
780{
781}
782
783
784void
785Team::Listener::ThreadRemoved(const Team::ThreadEvent& event)
786{
787}
788
789
790void
791Team::Listener::ImageAdded(const Team::ImageEvent& event)
792{
793}
794
795
796void
797Team::Listener::ImageRemoved(const Team::ImageEvent& event)
798{
799}
800
801
802void
803Team::Listener::ThreadStateChanged(const Team::ThreadEvent& event)
804{
805}
806
807
808void
809Team::Listener::ThreadCpuStateChanged(const Team::ThreadEvent& event)
810{
811}
812
813
814void
815Team::Listener::ThreadStackTraceChanged(const Team::ThreadEvent& event)
816{
817}
818
819
820void
821Team::Listener::ImageDebugInfoChanged(const Team::ImageEvent& event)
822{
823}
824
825
826void
827Team::Listener::BreakpointAdded(const Team::BreakpointEvent& event)
828{
829}
830
831
832void
833Team::Listener::BreakpointRemoved(const Team::BreakpointEvent& event)
834{
835}
836
837
838void
839Team::Listener::UserBreakpointChanged(const Team::UserBreakpointEvent& event)
840{
841}
842
843
844void
845Team::Listener::WatchpointAdded(const Team::WatchpointEvent& event)
846{
847}
848
849
850void
851Team::Listener::WatchpointRemoved(const Team::WatchpointEvent& event)
852{
853}
854
855
856void
857Team::Listener::WatchpointChanged(const Team::WatchpointEvent& event)
858{
859}
860
861
862void
863Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
864{
865}
866