1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <string.h> 8 9 #include <debug_support.h> 10 11 #include "arch_debug_support.h" 12 13 14 // init_debug_context 15 status_t 16 init_debug_context(debug_context *context, port_id nubPort) 17 { 18 if (!context || nubPort < 0) 19 return B_BAD_VALUE; 20 21 context->nub_port = nubPort; 22 23 // create the reply port 24 context->reply_port = create_port(1, "debug reply port"); 25 if (context->reply_port < 0) 26 return context->reply_port; 27 28 return B_OK; 29 } 30 31 // destroy_debug_context 32 void 33 destroy_debug_context(debug_context *context) 34 { 35 if (context) { 36 if (context->reply_port >= 0) 37 delete_port(context->reply_port); 38 } 39 } 40 41 // send_debug_message 42 status_t 43 send_debug_message(debug_context *context, int32 messageCode, 44 const void *message, int32 messageSize, void *reply, int32 replySize) 45 { 46 if (!context) 47 return B_BAD_VALUE; 48 49 // send message 50 while (true) { 51 status_t result = write_port(context->nub_port, messageCode, message, 52 messageSize); 53 if (result == B_OK) 54 break; 55 if (result != B_INTERRUPTED) 56 return result; 57 } 58 59 if (!reply) 60 return B_OK; 61 62 // read reply 63 while (true) { 64 int32 code; 65 ssize_t bytesRead = read_port(context->reply_port, &code, reply, 66 replySize); 67 if (bytesRead > 0) 68 return B_OK; 69 if (bytesRead != B_INTERRUPTED) 70 return bytesRead; 71 } 72 } 73 74 // debug_read_memory_partial 75 ssize_t 76 debug_read_memory_partial(debug_context *context, const void *address, 77 void *buffer, size_t size) 78 { 79 if (!context) 80 return B_BAD_VALUE; 81 82 if (size == 0) 83 return 0; 84 if (size > B_MAX_READ_WRITE_MEMORY_SIZE) 85 size = B_MAX_READ_WRITE_MEMORY_SIZE; 86 87 // prepare the message 88 debug_nub_read_memory message; 89 message.reply_port = context->reply_port; 90 message.address = (void*)address; 91 message.size = size; 92 93 // send the message 94 debug_nub_read_memory_reply reply; 95 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_READ_MEMORY, 96 &message, sizeof(message), &reply, sizeof(reply)); 97 98 if (error != B_OK) 99 return error; 100 if (reply.error != B_OK) 101 return reply.error; 102 103 // copy the read data 104 memcpy(buffer, reply.data, reply.size); 105 return reply.size; 106 } 107 108 // debug_read_memory 109 ssize_t 110 debug_read_memory(debug_context *context, const void *_address, void *_buffer, 111 size_t size) 112 { 113 const char *address = (const char *)_address; 114 char *buffer = (char*)_buffer; 115 116 // check parameters 117 if (!context || !address || !buffer) 118 return B_BAD_VALUE; 119 if (size == 0) 120 return 0; 121 122 // read as long as we can read data 123 ssize_t sumRead = 0; 124 while (size > 0) { 125 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 126 size); 127 if (bytesRead < 0) { 128 if (sumRead > 0) 129 return sumRead; 130 return bytesRead; 131 } 132 133 address += bytesRead; 134 buffer += bytesRead; 135 sumRead += bytesRead; 136 size -= bytesRead; 137 } 138 139 return sumRead; 140 } 141 142 // debug_read_string 143 ssize_t 144 debug_read_string(debug_context *context, const void *_address, char *buffer, 145 size_t size) 146 { 147 const char *address = (const char *)_address; 148 149 // check parameters 150 if (!context || !address || !buffer || size == 0) 151 return B_BAD_VALUE; 152 153 // read as long as we can read data 154 ssize_t sumRead = 0; 155 while (size > 0) { 156 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 157 size); 158 if (bytesRead < 0) { 159 // always null-terminate what we have (even, if it is an empty 160 // string) and be done 161 *buffer = '\0'; 162 return (sumRead > 0 ? sumRead : bytesRead); 163 } 164 165 int chunkSize = strnlen(buffer, bytesRead); 166 if (chunkSize < bytesRead) { 167 // we found a terminating null 168 sumRead += chunkSize; 169 return sumRead; 170 } 171 172 address += bytesRead; 173 buffer += bytesRead; 174 sumRead += bytesRead; 175 size -= bytesRead; 176 } 177 178 // We filled the complete buffer without encountering a terminating null 179 // replace the last char. But nevertheless return the full size to indicate 180 // that the buffer was too small. 181 buffer[-1] = '\0'; 182 183 return sumRead; 184 } 185 186 187 status_t 188 debug_get_cpu_state(debug_context *context, thread_id thread, 189 debug_debugger_message *messageCode, debug_cpu_state *cpuState) 190 { 191 if (!context || !cpuState) 192 return B_BAD_VALUE; 193 194 // prepare message 195 debug_nub_get_cpu_state message; 196 message.reply_port = context->reply_port; 197 message.thread = thread; 198 199 // send message 200 debug_nub_get_cpu_state_reply reply; 201 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_GET_CPU_STATE, 202 &message, sizeof(message), &reply, sizeof(reply)); 203 if (error == B_OK) 204 error = reply.error; 205 206 // get state 207 if (error == B_OK) { 208 *cpuState = reply.cpu_state; 209 if (messageCode) 210 *messageCode = reply.message; 211 } 212 213 return error; 214 } 215 216 217 status_t 218 debug_get_instruction_pointer(debug_context *context, thread_id thread, 219 void **ip, void **stackFrameAddress) 220 { 221 if (!context || !ip || !stackFrameAddress) 222 return B_BAD_VALUE; 223 224 return arch_debug_get_instruction_pointer(context, thread, ip, 225 stackFrameAddress); 226 } 227 228 229 status_t 230 debug_get_stack_frame(debug_context *context, void *stackFrameAddress, 231 debug_stack_frame_info *stackFrameInfo) 232 { 233 if (!context || !stackFrameAddress || !stackFrameInfo) 234 return B_BAD_VALUE; 235 236 return arch_debug_get_stack_frame(context, stackFrameAddress, 237 stackFrameInfo); 238 } 239