1/*
2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "SharedImage.h"
8
9#include <stdio.h>
10
11#include <algorithm>
12#include <new>
13
14#include <debug_support.h>
15#include <ObjectList.h>
16
17#include "Options.h"
18
19
20SharedImage::SharedImage()
21	:
22	fSymbols(NULL),
23	fSymbolCount(0)
24{
25}
26
27
28SharedImage::~SharedImage()
29{
30	if (fSymbols != NULL) {
31		for (int32 i = 0; i < fSymbolCount; i++)
32			delete fSymbols[i];
33		delete[] fSymbols;
34	}
35}
36
37
38status_t
39SharedImage::Init(team_id owner, image_id imageID)
40{
41	// we need a temporary symbol lookup context
42	debug_symbol_lookup_context* lookupContext;
43	status_t error = debug_create_symbol_lookup_context(owner, imageID,
44		&lookupContext);
45	if (error != B_OK) {
46		fprintf(stderr, "%s: Failed to create symbol lookup context "
47			"for team %" B_PRId32 ": %s\n",
48			kCommandName, owner, strerror(error));
49		return error;
50	}
51
52	// TODO: Creating a symbol lookup just for loading the symbols of a single
53	// image is unnecessarily expensive.
54
55	// create a symbol iterator
56	debug_symbol_iterator* iterator;
57	error = debug_create_image_symbol_iterator(lookupContext, imageID,
58		&iterator);
59	if (error != B_OK) {
60		fprintf(stderr,
61			"Failed to init symbol iterator for image %" B_PRId32 ": %s\n",
62			imageID, strerror(error));
63		debug_delete_symbol_lookup_context(lookupContext);
64		return error;
65	}
66
67	// init
68	error = _Init(iterator);
69
70	// cleanup
71	debug_delete_symbol_iterator(iterator);
72	debug_delete_symbol_lookup_context(lookupContext);
73
74	return error;
75}
76
77
78status_t
79SharedImage::Init(const char* path)
80{
81	// create a symbol iterator
82	debug_symbol_iterator* iterator;
83	status_t error = debug_create_file_symbol_iterator(path, &iterator);
84	if (error != B_OK) {
85		fprintf(stderr, "Failed to init symbol iterator for \"%s\": %s\n",
86			path, strerror(error));
87		return error;
88	}
89
90	error = _Init(iterator);
91
92	debug_delete_symbol_iterator(iterator);
93
94	return error;
95}
96
97
98int32
99SharedImage::FindSymbol(addr_t address) const
100{
101	// binary search the function
102	int32 lower = 0;
103	int32 upper = fSymbolCount;
104
105	while (lower < upper) {
106		int32 mid = (lower + upper) / 2;
107		if (address >= fSymbols[mid]->base + fSymbols[mid]->size)
108			lower = mid + 1;
109		else
110			upper = mid;
111	}
112
113	if (lower == fSymbolCount)
114		return -1;
115
116	const Symbol* symbol = fSymbols[lower];
117	if (address >= symbol->base && address < symbol->base + symbol->size)
118		return lower;
119	return -1;
120}
121
122
123status_t
124SharedImage::_Init(debug_symbol_iterator* iterator)
125{
126	// get an image info
127	status_t error = debug_get_symbol_iterator_image_info(iterator, &fInfo);
128	if (error != B_OK)
129		return error;
130
131	// iterate through the symbols
132	BObjectList<Symbol>	symbols(512, true);
133	char symbolName[1024];
134	int32 symbolType;
135	void* symbolLocation;
136	size_t symbolSize;
137	while (debug_next_image_symbol(iterator, symbolName, sizeof(symbolName),
138			&symbolType, &symbolLocation, &symbolSize) == B_OK) {
139//		printf("  %s %p (%6lu) %s\n",
140//			symbolType == B_SYMBOL_TYPE_TEXT ? "text" : "data",
141//			symbolLocation, symbolSize, symbolName);
142		if (symbolSize > 0 && symbolType == B_SYMBOL_TYPE_TEXT) {
143			Symbol* symbol = new(std::nothrow) Symbol(this,
144				(addr_t)symbolLocation, symbolSize, symbolName);
145			if (symbol == NULL || !symbols.AddItem(symbol)) {
146				delete symbol;
147				fprintf(stderr, "%s: Out of memory\n", kCommandName);
148				return B_NO_MEMORY;
149			}
150		}
151	}
152
153	// sort the symbols
154	fSymbolCount = symbols.CountItems();
155	fSymbols = new(std::nothrow) Symbol*[fSymbolCount];
156	if (fSymbols == NULL)
157		return B_NO_MEMORY;
158
159	for (int32 i = fSymbolCount - 1; i >= 0 ; i--)
160		fSymbols[i] = symbols.RemoveItemAt(i);
161
162	std::sort(fSymbols, fSymbols + fSymbolCount, SymbolComparator());
163
164	return B_OK;
165}
166