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