xref: /haiku/src/kits/debug/debug_support.cpp (revision 981f1b1135291a4fca290fbdf69910dc2f24abdd)
1 /*
2  * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <new>
7 
8 #include <string.h>
9 
10 #include <AutoDeleter.h>
11 #include <debug_support.h>
12 
13 #include "arch_debug_support.h"
14 #include "Image.h"
15 #include "SymbolLookup.h"
16 
17 
18 using std::nothrow;
19 
20 
21 struct debug_symbol_lookup_context {
22 	SymbolLookup*	lookup;
23 };
24 
25 struct debug_symbol_iterator : BPrivate::Debug::SymbolIterator {
26 	bool	ownsImage;
27 
28 	debug_symbol_iterator()
29 		:
30 		ownsImage(false)
31 	{
32 	}
33 
34 	~debug_symbol_iterator()
35 	{
36 		if (ownsImage)
37 			delete image;
38 	}
39 };
40 
41 
42 // init_debug_context
43 status_t
44 init_debug_context(debug_context *context, team_id team, port_id nubPort)
45 {
46 	if (!context || team < 0 || nubPort < 0)
47 		return B_BAD_VALUE;
48 
49 	context->team = team;
50 	context->nub_port = nubPort;
51 
52 	// create the reply port
53 	context->reply_port = create_port(1, "debug reply port");
54 	if (context->reply_port < 0)
55 		return context->reply_port;
56 
57 	return B_OK;
58 }
59 
60 // destroy_debug_context
61 void
62 destroy_debug_context(debug_context *context)
63 {
64 	if (context) {
65 		if (context->reply_port >= 0)
66 			delete_port(context->reply_port);
67 
68 		context->team = -1;
69 		context->nub_port = -1;
70 		context->reply_port = -1;
71 	}
72 }
73 
74 // send_debug_message
75 status_t
76 send_debug_message(debug_context *context, int32 messageCode,
77 	const void *message, int32 messageSize, void *reply, int32 replySize)
78 {
79 	if (!context)
80 		return B_BAD_VALUE;
81 
82 	// send message
83 	while (true) {
84 		status_t result = write_port(context->nub_port, messageCode, message,
85 			messageSize);
86 		if (result == B_OK)
87 			break;
88 		if (result != B_INTERRUPTED)
89 			return result;
90 	}
91 
92 	if (!reply)
93 		return B_OK;
94 
95 	// read reply
96 	while (true) {
97 		int32 code;
98 		ssize_t bytesRead = read_port(context->reply_port, &code, reply,
99 			replySize);
100 		if (bytesRead > 0)
101 			return B_OK;
102 		if (bytesRead != B_INTERRUPTED)
103 			return bytesRead;
104 	}
105 }
106 
107 // debug_read_memory_partial
108 ssize_t
109 debug_read_memory_partial(debug_context *context, const void *address,
110 	void *buffer, size_t size)
111 {
112 	if (!context)
113 		return B_BAD_VALUE;
114 
115 	if (size == 0)
116 		return 0;
117 	if (size > B_MAX_READ_WRITE_MEMORY_SIZE)
118 		size = B_MAX_READ_WRITE_MEMORY_SIZE;
119 
120 	// prepare the message
121 	debug_nub_read_memory message;
122 	message.reply_port = context->reply_port;
123 	message.address = (void*)address;
124 	message.size = size;
125 
126 	// send the message
127 	debug_nub_read_memory_reply reply;
128 	status_t error = send_debug_message(context, B_DEBUG_MESSAGE_READ_MEMORY,
129 		&message, sizeof(message), &reply, sizeof(reply));
130 
131 	if (error != B_OK)
132 		return error;
133 	if (reply.error != B_OK)
134 		return reply.error;
135 
136 	// copy the read data
137 	memcpy(buffer, reply.data, reply.size);
138 	return reply.size;
139 }
140 
141 // debug_read_memory
142 ssize_t
143 debug_read_memory(debug_context *context, const void *_address, void *_buffer,
144 	size_t size)
145 {
146 	const char *address = (const char *)_address;
147 	char *buffer = (char*)_buffer;
148 
149 	// check parameters
150 	if (!context || !address || !buffer)
151 		return B_BAD_VALUE;
152 	if (size == 0)
153 		return 0;
154 
155 	// read as long as we can read data
156 	ssize_t sumRead = 0;
157 	while (size > 0) {
158 		ssize_t bytesRead = debug_read_memory_partial(context, address, buffer,
159 			size);
160 		if (bytesRead < 0) {
161 			if (sumRead > 0)
162 				return sumRead;
163 			return bytesRead;
164 		}
165 
166 		address += bytesRead;
167 		buffer += bytesRead;
168 		sumRead += bytesRead;
169 		size -= bytesRead;
170 	}
171 
172 	return sumRead;
173 }
174 
175 // debug_read_string
176 ssize_t
177 debug_read_string(debug_context *context, const void *_address, char *buffer,
178 	size_t size)
179 {
180 	const char *address = (const char *)_address;
181 
182 	// check parameters
183 	if (!context || !address || !buffer || size == 0)
184 		return B_BAD_VALUE;
185 
186 	// read as long as we can read data
187 	ssize_t sumRead = 0;
188 	while (size > 0) {
189 		ssize_t bytesRead = debug_read_memory_partial(context, address, buffer,
190 			size);
191 		if (bytesRead < 0) {
192 			// always null-terminate what we have (even, if it is an empty
193 			// string) and be done
194 			*buffer = '\0';
195 			return (sumRead > 0 ? sumRead : bytesRead);
196 		}
197 
198 		int chunkSize = strnlen(buffer, bytesRead);
199 		if (chunkSize < bytesRead) {
200 			// we found a terminating null
201 			sumRead += chunkSize;
202 			return sumRead;
203 		}
204 
205 		address += bytesRead;
206 		buffer += bytesRead;
207 		sumRead += bytesRead;
208 		size -= bytesRead;
209 	}
210 
211 	// We filled the complete buffer without encountering a terminating null
212 	// replace the last char. But nevertheless return the full size to indicate
213 	// that the buffer was too small.
214 	buffer[-1] = '\0';
215 
216 	return sumRead;
217 }
218 
219 // debug_get_cpu_state
220 status_t
221 debug_get_cpu_state(debug_context *context, thread_id thread,
222 	debug_debugger_message *messageCode, debug_cpu_state *cpuState)
223 {
224 	if (!context || !cpuState)
225 		return B_BAD_VALUE;
226 
227 	// prepare message
228 	debug_nub_get_cpu_state message;
229 	message.reply_port = context->reply_port;
230 	message.thread = thread;
231 
232 	// send message
233 	debug_nub_get_cpu_state_reply reply;
234 	status_t error = send_debug_message(context, B_DEBUG_MESSAGE_GET_CPU_STATE,
235 		&message, sizeof(message), &reply, sizeof(reply));
236 	if (error == B_OK)
237 		error = reply.error;
238 
239 	// get state
240 	if (error == B_OK) {
241 		*cpuState = reply.cpu_state;
242 		if (messageCode)
243 			*messageCode = reply.message;
244 	}
245 
246 	return error;
247 }
248 
249 
250 // #pragma mark -
251 
252 // debug_get_instruction_pointer
253 status_t
254 debug_get_instruction_pointer(debug_context *context, thread_id thread,
255 	void **ip, void **stackFrameAddress)
256 {
257 	if (!context || !ip || !stackFrameAddress)
258 		return B_BAD_VALUE;
259 
260 	return arch_debug_get_instruction_pointer(context, thread, ip,
261 		stackFrameAddress);
262 }
263 
264 // debug_get_stack_frame
265 status_t
266 debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
267 	debug_stack_frame_info *stackFrameInfo)
268 {
269 	if (!context || !stackFrameAddress || !stackFrameInfo)
270 		return B_BAD_VALUE;
271 
272 	return arch_debug_get_stack_frame(context, stackFrameAddress,
273 		stackFrameInfo);
274 }
275 
276 
277 // #pragma mark -
278 
279 // debug_create_symbol_lookup_context
280 status_t
281 debug_create_symbol_lookup_context(team_id team,
282 	debug_symbol_lookup_context **_lookupContext)
283 {
284 	if (team < 0 || !_lookupContext)
285 		return B_BAD_VALUE;
286 
287 	// create the lookup context
288 	debug_symbol_lookup_context *lookupContext
289 		= new(nothrow) debug_symbol_lookup_context;
290 	ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext);
291 
292 	// create and init symbol lookup
293 	SymbolLookup *lookup = new(nothrow) SymbolLookup(team);
294 	if (!lookup)
295 		return B_NO_MEMORY;
296 
297 	status_t error = lookup->Init();
298 	if (error != B_OK) {
299 		delete lookup;
300 		return error;
301 	}
302 
303 	// everything went fine: return the result
304 	lookupContext->lookup = lookup;
305 	*_lookupContext = lookupContext;
306 	contextDeleter.Detach();
307 
308 	return B_OK;
309 }
310 
311 // debug_delete_symbol_lookup_context
312 void
313 debug_delete_symbol_lookup_context(debug_symbol_lookup_context *lookupContext)
314 {
315 	if (lookupContext) {
316 		delete lookupContext->lookup;
317 		delete lookupContext;
318 	}
319 }
320 
321 
322 // debug_get_symbol
323 status_t
324 debug_get_symbol(debug_symbol_lookup_context* lookupContext, image_id image,
325 	const char* name, int32 symbolType, void** _symbolLocation,
326 	size_t* _symbolSize, int32* _symbolType)
327 {
328 	if (!lookupContext || !lookupContext->lookup)
329 		return B_BAD_VALUE;
330 	SymbolLookup* lookup = lookupContext->lookup;
331 
332 	return lookup->GetSymbol(image, name, symbolType, _symbolLocation,
333 		_symbolSize, _symbolType);
334 }
335 
336 
337 // debug_lookup_symbol_address
338 status_t
339 debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext,
340 	const void *address, void **baseAddress, char *symbolName,
341 	int32 symbolNameSize, char *imageName, int32 imageNameSize,
342 	bool *exactMatch)
343 {
344 	if (!lookupContext || !lookupContext->lookup)
345 		return B_BAD_VALUE;
346 	SymbolLookup *lookup = lookupContext->lookup;
347 
348 	// find the symbol
349 	addr_t _baseAddress;
350 	const char *_symbolName;
351 	size_t _symbolNameLen;
352 	const char *_imageName;
353 	try {
354 		status_t error = lookup->LookupSymbolAddress((addr_t)address,
355 			&_baseAddress, &_symbolName, &_symbolNameLen, &_imageName,
356 			exactMatch);
357 		if (error != B_OK)
358 			return error;
359 	} catch (BPrivate::Debug::Exception exception) {
360 		return exception.Error();
361 	}
362 
363 	// translate/copy the results
364 	if (baseAddress)
365 		*baseAddress = (void*)_baseAddress;
366 
367 	if (symbolName && symbolNameSize > 0) {
368 		if (_symbolName && _symbolNameLen > 0) {
369 			strlcpy(symbolName, _symbolName,
370 				min_c((size_t)symbolNameSize, _symbolNameLen + 1));
371 		} else
372 			symbolName[0] = '\0';
373 	}
374 
375 	if (imageName) {
376 		if (imageNameSize > B_PATH_NAME_LENGTH)
377 			imageNameSize = B_PATH_NAME_LENGTH;
378 		strlcpy(imageName, _imageName, imageNameSize);
379 	}
380 
381 	return B_OK;
382 }
383 
384 
385 status_t
386 debug_create_image_symbol_iterator(debug_symbol_lookup_context* lookupContext,
387 	image_id imageID, debug_symbol_iterator** _iterator)
388 {
389 	if (!lookupContext || !lookupContext->lookup)
390 		return B_BAD_VALUE;
391 	SymbolLookup *lookup = lookupContext->lookup;
392 
393 	debug_symbol_iterator* iterator = new(std::nothrow) debug_symbol_iterator;
394 	if (iterator == NULL)
395 		return B_NO_MEMORY;
396 
397 	status_t error;
398 	try {
399 		error = lookup->InitSymbolIterator(imageID, *iterator);
400 	} catch (BPrivate::Debug::Exception exception) {
401 		error = exception.Error();
402 	}
403 
404 	// Work-around for a runtime loader problem. A freshly fork()ed child does
405 	// still have image_t structures with the parent's image ID's, so we
406 	// wouldn't find the image in this case.
407 	if (error != B_OK) {
408 		// Get the image info and re-try looking with the text base address.
409 		// Note, that we can't easily check whether the image is part of the
410 		// target team at all (there's no image_info::team, we'd have to
411 		// iterate through all images).
412 		image_info imageInfo;
413 		error = get_image_info(imageID, &imageInfo);
414 		if (error == B_OK) {
415 			try {
416 				error = lookup->InitSymbolIteratorByAddress(
417 					(addr_t)imageInfo.text, *iterator);
418 			} catch (BPrivate::Debug::Exception exception) {
419 				error = exception.Error();
420 			}
421 		}
422 	}
423 
424 	if (error != B_OK) {
425 		delete iterator;
426 		return error;
427 	}
428 
429 	*_iterator = iterator;
430 	return B_OK;
431 }
432 
433 
434 status_t
435 debug_create_file_symbol_iterator(const char* path,
436 	debug_symbol_iterator** _iterator)
437 {
438 	if (path == NULL)
439 		return B_BAD_VALUE;
440 
441 	// create the iterator
442 	debug_symbol_iterator* iterator = new(std::nothrow) debug_symbol_iterator;
443 	if (iterator == NULL)
444 		return B_NO_MEMORY;
445 	ObjectDeleter<debug_symbol_iterator> iteratorDeleter(iterator);
446 
447 	// create the image file
448 	ImageFile* imageFile = new(std::nothrow) ImageFile;
449 	if (imageFile == NULL)
450 		return B_NO_MEMORY;
451 
452 	// init the iterator
453 	iterator->image = imageFile;
454 	iterator->ownsImage = true;
455 	iterator->currentIndex = -1;
456 
457 	// init the image file
458 	status_t error = imageFile->Init(path);
459 	if (error != B_OK)
460 		return error;
461 
462 	iteratorDeleter.Detach();
463 	*_iterator = iterator;
464 
465 	return B_OK;
466 }
467 
468 
469 void
470 debug_delete_symbol_iterator(debug_symbol_iterator* iterator)
471 {
472 	delete iterator;
473 }
474 
475 
476 // debug_next_image_symbol
477 status_t
478 debug_next_image_symbol(debug_symbol_iterator* iterator, char* nameBuffer,
479 	size_t nameBufferLength, int32* _symbolType, void** _symbolLocation,
480 	size_t* _symbolSize)
481 {
482 	if (iterator == NULL || iterator->image == NULL)
483 		return B_BAD_VALUE;
484 
485 	const char* symbolName;
486 	size_t symbolNameLen;
487 	addr_t symbolLocation;
488 
489 	try {
490 		status_t error = iterator->image->NextSymbol(iterator->currentIndex,
491 			&symbolName, &symbolNameLen, &symbolLocation, _symbolSize,
492 			_symbolType);
493 		if (error != B_OK)
494 			return error;
495 	} catch (BPrivate::Debug::Exception exception) {
496 		return exception.Error();
497 	}
498 
499 	*_symbolLocation = (void*)symbolLocation;
500 
501 	if (symbolName != NULL && symbolNameLen > 0) {
502 		strlcpy(nameBuffer, symbolName,
503 			min_c(nameBufferLength, symbolNameLen + 1));
504 	} else
505 		nameBuffer[0] = '\0';
506 
507 	return B_OK;
508 }
509 
510 
511 status_t
512 debug_get_symbol_iterator_image_info(debug_symbol_iterator* iterator,
513 	image_info* info)
514 {
515 	if (iterator == NULL || iterator->image == NULL || info == NULL)
516 		return B_BAD_VALUE;
517 
518 	*info = iterator->image->Info();
519 	return B_OK;
520 }
521