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
19using std::nothrow;
20
21
22struct debug_symbol_lookup_context {
23	SymbolLookup*	lookup;
24};
25
26struct 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
44status_t
45init_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
62void
63destroy_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
76status_t
77send_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
109ssize_t
110debug_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
143ssize_t
144debug_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
177ssize_t
178debug_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
221ssize_t
222debug_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
254ssize_t
255debug_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
287status_t
288debug_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
320status_t
321debug_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
332status_t
333debug_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
347status_t
348debug_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
385void
386debug_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
396status_t
397debug_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
411status_t
412debug_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
458status_t
459debug_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
507status_t
508debug_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
542void
543debug_delete_symbol_iterator(debug_symbol_iterator* iterator)
544{
545	delete iterator;
546}
547
548
549// debug_next_image_symbol
550status_t
551debug_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
584status_t
585debug_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