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