vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debug / debug_support.cpp
blobfdc231d3a9dfde6a4b6e3ff4f1303530540e6f64
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 */
7 #include <new>
9 #include <string.h>
11 #include <AutoDeleter.h>
12 #include <debug_support.h>
14 #include "arch_debug_support.h"
15 #include "Image.h"
16 #include "SymbolLookup.h"
19 using std::nothrow;
22 struct debug_symbol_lookup_context {
23 SymbolLookup* lookup;
26 struct debug_symbol_iterator : BPrivate::Debug::SymbolIterator {
27 bool ownsImage;
29 debug_symbol_iterator()
31 ownsImage(false)
35 ~debug_symbol_iterator()
37 if (ownsImage)
38 delete image;
43 // init_debug_context
44 status_t
45 init_debug_context(debug_context *context, team_id team, port_id nubPort)
47 if (!context || team < 0 || nubPort < 0)
48 return B_BAD_VALUE;
50 context->team = team;
51 context->nub_port = nubPort;
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;
58 return B_OK;
61 // destroy_debug_context
62 void
63 destroy_debug_context(debug_context *context)
65 if (context) {
66 if (context->reply_port >= 0)
67 delete_port(context->reply_port);
69 context->team = -1;
70 context->nub_port = -1;
71 context->reply_port = -1;
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)
80 if (!context)
81 return B_BAD_VALUE;
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;
93 if (!reply)
94 return B_OK;
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;
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)
113 if (!context)
114 return B_BAD_VALUE;
116 if (size == 0)
117 return 0;
118 if (size > B_MAX_READ_WRITE_MEMORY_SIZE)
119 size = B_MAX_READ_WRITE_MEMORY_SIZE;
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;
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));
132 if (error != B_OK)
133 return error;
134 if (reply.error != B_OK)
135 return reply.error;
137 // copy the read data
138 memcpy(buffer, reply.data, reply.size);
139 return reply.size;
142 // debug_read_memory
143 ssize_t
144 debug_read_memory(debug_context *context, const void *_address, void *_buffer,
145 size_t size)
147 const char *address = (const char *)_address;
148 char *buffer = (char*)_buffer;
150 // check parameters
151 if (!context || !address || !buffer)
152 return B_BAD_VALUE;
153 if (size == 0)
154 return 0;
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;
167 address += bytesRead;
168 buffer += bytesRead;
169 sumRead += bytesRead;
170 size -= bytesRead;
173 return sumRead;
176 // debug_read_string
177 ssize_t
178 debug_read_string(debug_context *context, const void *_address, char *buffer,
179 size_t size)
181 const char *address = (const char *)_address;
183 // check parameters
184 if (!context || !address || !buffer || size == 0)
185 return B_BAD_VALUE;
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);
199 int chunkSize = strnlen(buffer, bytesRead);
200 if (chunkSize < bytesRead) {
201 // we found a terminating null
202 sumRead += chunkSize;
203 return sumRead;
206 address += bytesRead;
207 buffer += bytesRead;
208 sumRead += bytesRead;
209 size -= bytesRead;
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';
217 return sumRead;
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)
225 if (!context)
226 return B_BAD_VALUE;
228 if (size == 0)
229 return 0;
230 if (size > B_MAX_READ_WRITE_MEMORY_SIZE)
231 size = B_MAX_READ_WRITE_MEMORY_SIZE;
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);
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));
245 if (error != B_OK)
246 return error;
247 if (reply.error != B_OK)
248 return reply.error;
250 return reply.size;
253 // debug_write_memory
254 ssize_t
255 debug_write_memory(debug_context *context, const void *_address, void *_buffer,
256 size_t size)
258 const char *address = (const char *)_address;
259 char *buffer = (char*)_buffer;
261 // check parameters
262 if (!context || !address || !buffer)
263 return B_BAD_VALUE;
264 if (size == 0)
265 return 0;
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;
277 address += bytesWritten;
278 buffer += bytesWritten;
279 sumWritten += bytesWritten;
280 size -= bytesWritten;
283 return sumWritten;
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)
291 if (!context || !cpuState)
292 return B_BAD_VALUE;
294 // prepare message
295 debug_nub_get_cpu_state message;
296 message.reply_port = context->reply_port;
297 message.thread = thread;
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;
306 // get state
307 if (error == B_OK) {
308 *cpuState = reply.cpu_state;
309 if (messageCode)
310 *messageCode = reply.message;
313 return error;
317 // #pragma mark -
319 // debug_get_instruction_pointer
320 status_t
321 debug_get_instruction_pointer(debug_context *context, thread_id thread,
322 void **ip, void **stackFrameAddress)
324 if (!context || !ip || !stackFrameAddress)
325 return B_BAD_VALUE;
327 return arch_debug_get_instruction_pointer(context, thread, ip,
328 stackFrameAddress);
331 // debug_get_stack_frame
332 status_t
333 debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
334 debug_stack_frame_info *stackFrameInfo)
336 if (!context || !stackFrameAddress || !stackFrameInfo)
337 return B_BAD_VALUE;
339 return arch_debug_get_stack_frame(context, stackFrameAddress,
340 stackFrameInfo);
344 // #pragma mark -
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)
351 if (team < 0 || !_lookupContext)
352 return B_BAD_VALUE;
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);
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);
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();
375 // everything went fine: return the result
376 lookupContext->lookup = lookup;
377 *_lookupContext = lookupContext;
378 contextDeleter.Detach();
379 lookupDeleter.Detach();
381 return B_OK;
384 // debug_delete_symbol_lookup_context
385 void
386 debug_delete_symbol_lookup_context(debug_symbol_lookup_context *lookupContext)
388 if (lookupContext) {
389 delete lookupContext->lookup;
390 delete lookupContext;
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)
401 if (!lookupContext || !lookupContext->lookup)
402 return B_BAD_VALUE;
403 SymbolLookup* lookup = lookupContext->lookup;
405 return lookup->GetSymbol(image, name, symbolType, _symbolLocation,
406 _symbolSize, _symbolType);
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)
417 if (!lookupContext || !lookupContext->lookup)
418 return B_BAD_VALUE;
419 SymbolLookup *lookup = lookupContext->lookup;
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();
436 // translate/copy the results
437 if (baseAddress)
438 *baseAddress = (void*)_baseAddress;
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';
448 if (imageName) {
449 if (imageNameSize > B_PATH_NAME_LENGTH)
450 imageNameSize = B_PATH_NAME_LENGTH;
451 strlcpy(imageName, _imageName, imageNameSize);
454 return B_OK;
458 status_t
459 debug_create_image_symbol_iterator(debug_symbol_lookup_context* lookupContext,
460 image_id imageID, debug_symbol_iterator** _iterator)
462 if (!lookupContext || !lookupContext->lookup)
463 return B_BAD_VALUE;
464 SymbolLookup *lookup = lookupContext->lookup;
466 debug_symbol_iterator* iterator = new(std::nothrow) debug_symbol_iterator;
467 if (iterator == NULL)
468 return B_NO_MEMORY;
470 status_t error;
471 try {
472 error = lookup->InitSymbolIterator(imageID, *iterator);
473 } catch (BPrivate::Debug::Exception exception) {
474 error = exception.Error();
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();
497 if (error != B_OK) {
498 delete iterator;
499 return error;
502 *_iterator = iterator;
503 return B_OK;
507 status_t
508 debug_create_file_symbol_iterator(const char* path,
509 debug_symbol_iterator** _iterator)
511 if (path == NULL)
512 return B_BAD_VALUE;
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);
520 // create the image file
521 ImageFile* imageFile = new(std::nothrow) ImageFile;
522 if (imageFile == NULL)
523 return B_NO_MEMORY;
525 // init the iterator
526 iterator->image = imageFile;
527 iterator->ownsImage = true;
528 iterator->currentIndex = -1;
530 // init the image file
531 status_t error = imageFile->Init(path);
532 if (error != B_OK)
533 return error;
535 iteratorDeleter.Detach();
536 *_iterator = iterator;
538 return B_OK;
542 void
543 debug_delete_symbol_iterator(debug_symbol_iterator* iterator)
545 delete iterator;
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)
555 if (iterator == NULL || iterator->image == NULL)
556 return B_BAD_VALUE;
558 const char* symbolName;
559 size_t symbolNameLen;
560 addr_t symbolLocation;
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();
572 *_symbolLocation = (void*)symbolLocation;
574 if (symbolName != NULL && symbolNameLen > 0) {
575 strlcpy(nameBuffer, symbolName,
576 min_c(nameBufferLength, symbolNameLen + 1));
577 } else
578 nameBuffer[0] = '\0';
580 return B_OK;
584 status_t
585 debug_get_symbol_iterator_image_info(debug_symbol_iterator* iterator,
586 image_info* info)
588 if (iterator == NULL || iterator->image == NULL || info == NULL)
589 return B_BAD_VALUE;
591 *info = iterator->image->Info();
592 return B_OK;