xref: /haiku/src/kits/debug/SymbolLookup.cpp (revision 5e14f5dae0e5255cd617e013b202dee5bca984db)
1 /*
2  * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <string.h>
7 #include <runtime_loader.h>
8 
9 #include "SymbolLookup.h"
10 
11 using namespace BPrivate;
12 
13 // PrepareAddress
14 const void *
15 Area::PrepareAddress(const void *address)
16 {
17 	TRACE(("Area::PrepareAddress(%p): area: %ld\n", address, fRemoteID));
18 
19 	// clone the area, if not done already
20 	if (fLocalID < 0) {
21 		fLocalID = clone_area("cloned area", &fLocalAddress, B_ANY_ADDRESS,
22 			B_READ_AREA, fRemoteID);
23 		if (fLocalID < 0) {
24 			TRACE(("Area::PrepareAddress(): Failed to clone area %ld: %s\n",
25 				fRemoteID, strerror(fLocalID)));
26 			throw Exception(fLocalID);
27 		}
28 	}
29 
30 	// translate the address
31 	const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress
32 		+ (addr_t)fLocalAddress);
33 
34 	TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result));
35 
36 	return result;
37 }
38 
39 
40 // #pragma mark -
41 
42 // constructor
43 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team)
44 	: fTeam(team),
45 	  fAreas()
46 {
47 }
48 
49 // destructor
50 RemoteMemoryAccessor::~RemoteMemoryAccessor()
51 {
52 	// delete the areas
53 	while (Area *area = fAreas.Head()) {
54 		fAreas.Remove(area);
55 		delete area;
56 	}
57 }
58 
59 // Init
60 status_t
61 RemoteMemoryAccessor::Init()
62 {
63 	// get a list of the team's areas
64 	area_info areaInfo;
65 	int32 cookie = 0;
66 	status_t error;
67 	while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) {
68 
69 		TRACE(("area %ld: address: %p, size: %ld, name: %s\n", areaInfo.area,
70 			areaInfo.address, areaInfo.size, areaInfo.name));
71 
72 		Area *area = new(nothrow) Area(areaInfo.area, areaInfo.address,
73 			areaInfo.size);
74 		if (!area)
75 			return B_NO_MEMORY;
76 
77 		fAreas.Add(area);
78 	}
79 
80 	if (fAreas.IsEmpty())
81 		return error;
82 
83 	return B_OK;
84 }
85 
86 // PrepareAddress
87 const void *
88 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
89 {
90 	TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
91 		size));
92 
93 	if (!remoteAddress) {
94 		TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n"));
95 		throw Exception(B_BAD_VALUE);
96 	}
97 
98 	return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
99 }
100 
101 // _FindArea
102 Area &
103 RemoteMemoryAccessor::_FindArea(const void *address, int32 size)
104 {
105 	TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size));
106 
107 	for (AreaList::Iterator it = fAreas.GetIterator(); it.HasNext();) {
108 		Area *area = it.Next();
109 		if (area->ContainsAddress(address, size))
110 			return *area;
111 	}
112 
113 	TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n",
114 		address));
115 	throw Exception(B_ENTRY_NOT_FOUND);
116 }
117 
118 
119 // #pragma mark -
120 
121 // constructor
122 SymbolLookup::SymbolLookup(team_id team)
123 	: RemoteMemoryAccessor(team),
124 	  fDebugArea(NULL)
125 {
126 }
127 
128 // destructor
129 SymbolLookup::~SymbolLookup()
130 {
131 }
132 
133 // Init
134 status_t
135 SymbolLookup::Init()
136 {
137 	TRACE(("SymbolLookup::Init()\n"));
138 
139 	status_t error = RemoteMemoryAccessor::Init();
140 	if (error != B_OK)
141 		return error;
142 
143 	TRACE(("SymbolLookup::Init(): searching debug area...\n"));
144 
145 	// find the runtime loader debug area
146 	runtime_loader_debug_area *remoteDebugArea = NULL;
147 	int32 cookie = 0;
148 	area_info areaInfo;
149 	while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) {
150 		if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) {
151 			remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address;
152 			break;
153 		}
154 	}
155 
156 	if (!remoteDebugArea) {
157 		TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n"));
158 		return B_ERROR;
159 	}
160 
161 	TRACE(("SymbolLookup::Init(): found debug area, translating address...\n"));
162 
163 	// translate the address
164 	try {
165 		fDebugArea = &Read(*remoteDebugArea);
166 
167 		TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
168 			"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
169 
170 	} catch (Exception exception) {
171 		return exception.Error();
172 	}
173 
174 	return B_OK;
175 }
176 
177 // LookupSymbolAddress
178 status_t
179 SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
180 	const char **_symbolName, const char **_imageName, bool *_exactMatch)
181 {
182 	// Note, that this function doesn't find all symbols that we would like
183 	// to find. E.g. static functions do not appear in the symbol table
184 	// as function symbols, but as sections without name and size. The .symtab
185 	// section together with the .strtab section, which apparently differ from
186 	// the tables referred to by the .dynamic section, also contain proper names
187 	// and sizes for those symbols. Therefore, to get completely satisfying
188 	// results, we would need to read those tables from the shared object.
189 
190 	TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address));
191 
192 	// get the image for the address
193 	const image_t *image = _FindImageAtAddress(address);
194 	if (!image)
195 		return B_ENTRY_NOT_FOUND;
196 
197 	TRACE(("SymbolLookup::LookupSymbolAddress(): found image: ID: %ld, text: "
198 		"address: %p, size: %ld\n",
199 		image->id, (void*)image->regions[0].vmstart, image->regions[0].size));
200 
201 	// search the image for the symbol
202 	const struct Elf32_Sym *symbolFound = NULL;
203 	addr_t deltaFound = INT_MAX;
204 	bool exactMatch = false;
205 	const char *symbolName = NULL;	// remote
206 
207 	int32 hashTabSize = Read(image->symhash[0]);
208 	const uint32 *hashBuckets = image->symhash + 2;					// remote
209 	const uint32 *hashChains = image->symhash + 2 + hashTabSize;	// remote
210 	const elf_region_t *textRegion = image->regions;				// local
211 
212 	for (int32 i = 0; i < hashTabSize; i++) {
213 		for (int32 j = Read(hashBuckets[i]);
214 			 j != STN_UNDEF;
215 			 j = Read(hashChains[j])) {
216 
217 			const struct Elf32_Sym *symbol = &Read(image->syms[j]);
218 
219 			// The symbol table contains not only symbols referring to functions
220 			// and data symbols within the shared object, but also referenced
221 			// symbols of other shared objects, as well as section and file
222 			// references. We ignore everything but function and data symbols
223 			// that have an st_value != 0 (0 seems to be an indication for a
224 			// symbol defined elsewhere -- couldn't verify that in the specs
225 			// though).
226 			if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
227 					&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
228 				|| symbol->st_value == 0
229 				|| symbol->st_value + symbol->st_size + textRegion->delta
230 					> textRegion->vmstart + textRegion->size) {
231 				continue;
232 			}
233 
234 			// skip symbols starting after the given address
235 			addr_t symbolAddress = symbol->st_value + textRegion->delta;
236 
237 			if (symbolAddress > address)
238 				continue;
239 			addr_t symbolDelta = address - symbolAddress;
240 
241 			if (!symbolFound || symbolDelta < deltaFound) {
242 				deltaFound = symbolDelta;
243 				symbolFound = symbol;
244 				symbolName = SYMNAME(image, symbol);
245 
246 				if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
247 					// exact match
248 					exactMatch = true;
249 					break;
250 				}
251 			}
252 		}
253 	}
254 
255 	TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
256 		"%s, exact match: %d\n", symbolFound, image->name, exactMatch));
257 
258 	if (_baseAddress) {
259 		if (symbolFound)
260 			*_baseAddress = symbolFound->st_value + textRegion->delta;
261 		else
262 			*_baseAddress = textRegion->vmstart;
263 	}
264 
265 	if (_imageName)
266 		*_imageName = image->name;
267 
268 	if (_symbolName)
269 		*_symbolName = symbolName;	// remote address
270 
271 	if (_exactMatch)
272 		*_exactMatch = exactMatch;
273 
274 	return B_OK;
275 }
276 
277 // _FindImageAtAddress
278 const image_t *
279 SymbolLookup::_FindImageAtAddress(addr_t address)
280 {
281 	TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
282 
283 	// iterate through the images
284 	for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
285 		 image;
286 		 image = &Read(*image->next)) {
287 		if (image->regions[0].vmstart <= address
288 			&& address < image->regions[0].vmstart + image->regions[0].size) {
289 			return image;
290 		}
291 	}
292 
293 	return NULL;
294 }
295 
296