Rev 2885 | Rev 2887 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2885 | Rev 2886 | ||
|---|---|---|---|
| Line 16... | Line 16... | ||
| 16 | #include <syscall/copy.h> |
16 | #include <syscall/copy.h> |
| 17 | #include <udebug/udebug.h> |
17 | #include <udebug/udebug.h> |
| 18 | #include <udebug/udebug_ipc.h> |
18 | #include <udebug/udebug_ipc.h> |
| 19 | 19 | ||
| 20 | /** |
20 | /** |
| 21 | * Get a phone's callee task id. |
- | |
| 22 | * |
- | |
| 23 | * This will return the id of the task to which the phone |
- | |
| 24 | * is connected. |
- | |
| 25 | * |
- | |
| 26 | * Interrupts must be already disabled. |
- | |
| 27 | */ |
- | |
| 28 | static task_id_t get_callee_task_id(phone_t *phone) |
- | |
| 29 | { |
- | |
| 30 | answerbox_t *box; |
- | |
| 31 | task_id_t taskid; |
- | |
| 32 | - | ||
| 33 | spinlock_lock(&phone->lock); |
- | |
| 34 | if (phone->state != IPC_PHONE_CONNECTED) { |
- | |
| 35 | spinlock_unlock(&phone->lock); |
- | |
| 36 | return NULL; |
- | |
| 37 | } |
- | |
| 38 | - | ||
| 39 | box = phone->callee; |
- | |
| 40 | - | ||
| 41 | spinlock_lock(&box->lock); |
- | |
| 42 | taskid = box->task->taskid; |
- | |
| 43 | spinlock_unlock(&box->lock); |
- | |
| 44 | spinlock_unlock(&phone->lock); |
- | |
| 45 | - | ||
| 46 | return taskid; |
- | |
| 47 | } |
- | |
| 48 | - | ||
| 49 | /** |
- | |
| 50 | * Prepare a thread for a debugging operation. |
21 | * Prepare a thread for a debugging operation. |
| 51 | * |
22 | * |
| 52 | * Simply put, return thread t with t->debug_lock held, |
23 | * Simply put, return thread t with t->debug_lock held, |
| 53 | * but only if it verifies all conditions. |
24 | * but only if it verifies all conditions. |
| 54 | * |
25 | * |
| 55 | * Specifically, verifies that thread t exists, is a userspace thread, |
26 | * Specifically, verifies that thread t exists, is a userspace thread, |
| 56 | * belongs to the callee of 'phone'. It also locks t->debug_lock, |
27 | * and belongs to the current task (TASK). It also locks t->debug_lock, |
| 57 | * making sure that t->debug_active is true - that the thread is |
28 | * making sure that t->debug_active is true - that the thread is |
| 58 | * in a valid debugging session. |
29 | * in a valid debugging session. |
| 59 | * |
30 | * |
| 60 | * Returns EOK if all went well, or an error code otherwise. |
31 | * Returns EOK if all went well, or an error code otherwise. |
| 61 | * Interrupts must be already disabled when calling this function. |
32 | * Interrupts must be already disabled when calling this function. |
| 62 | * |
33 | * |
| 63 | * Note: This function sports complicated locking. |
34 | * Note: This function sports complicated locking. |
| 64 | */ |
35 | */ |
| 65 | static int _thread_op_begin(phone_t *phone, thread_t *t) |
36 | static int _thread_op_begin(thread_t *t) |
| 66 | { |
37 | { |
| 67 | int rc; |
38 | int rc; |
| 68 | task_id_t taskid; |
39 | task_id_t taskid; |
| 69 | int task_match; |
- | |
| 70 | DEADLOCK_PROBE_INIT(p_tasklock); |
- | |
| 71 | 40 | ||
| 72 | taskid = get_callee_task_id(phone); |
41 | taskid = TASK->taskid; |
| 73 | 42 | ||
| 74 | /* Need to lock down the thread and than it's owner task */ |
43 | /* Must lock threads_lock to ensure continued existence of the thread */ |
| 75 | grab_locks: |
- | |
| 76 | spinlock_lock(&threads_lock); |
44 | spinlock_lock(&threads_lock); |
| 77 | 45 | ||
| 78 | if (!thread_exists(t)) { |
46 | if (!thread_exists(t)) { |
| 79 | spinlock_unlock(&threads_lock); |
47 | spinlock_unlock(&threads_lock); |
| 80 | return ENOENT; |
48 | return ENOENT; |
| 81 | } |
49 | } |
| 82 | 50 | ||
| 83 | spinlock_lock(&t->debug_lock); |
51 | spinlock_lock(&t->debug_lock); |
| 84 | spinlock_lock(&t->lock); |
52 | spinlock_lock(&t->lock); |
| 85 | 53 | ||
| 86 | if (!spinlock_trylock(&t->task->lock)) { |
- | |
| 87 | spinlock_unlock(&t->lock); |
- | |
| 88 | spinlock_unlock(&t->debug_lock); |
- | |
| 89 | DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD); |
- | |
| 90 | goto grab_locks; /* avoid deadlock */ |
- | |
| 91 | } |
- | |
| 92 | - | ||
| 93 | /* Now verify that it's the callee */ |
54 | /* Now verify that it's the current task */ |
| 94 | task_match = (t->task->taskid == taskid); |
- | |
| 95 | - | ||
| 96 | spinlock_unlock(&t->task->lock); |
- | |
| 97 | - | ||
| 98 | if (!task_match) { |
55 | if (t->task != TASK) { |
| 99 | /* No such thread belonging to callee */ |
56 | /* No such thread belonging to callee */ |
| 100 | rc = ENOENT; |
57 | rc = ENOENT; |
| 101 | goto error_exit; |
58 | goto error_exit; |
| 102 | } |
59 | } |
| 103 | 60 | ||
| Line 130... | Line 87... | ||
| 130 | 87 | ||
| 131 | /* No locks left here */ |
88 | /* No locks left here */ |
| 132 | return rc; /* Some errors occured */ |
89 | return rc; /* Some errors occured */ |
| 133 | } |
90 | } |
| 134 | 91 | ||
| - | 92 | ||
| 135 | static void _thread_op_end(thread_t *t) |
93 | static void _thread_op_end(thread_t *t) |
| 136 | { |
94 | { |
| 137 | spinlock_unlock(&t->debug_lock); |
95 | spinlock_unlock(&t->debug_lock); |
| 138 | } |
96 | } |
| 139 | 97 | ||
| 140 | static int udebug_rp_go(call_t *call, phone_t *phone) |
- | |
| 141 | { |
- | |
| 142 | thread_t *t; |
- | |
| 143 | ipl_t ipl; |
- | |
| 144 | int rc; |
- | |
| 145 | - | ||
| 146 | klog_printf("debug_go()"); |
- | |
| 147 | - | ||
| 148 | t = (thread_t *)IPC_GET_ARG2(call->data); |
- | |
| 149 | - | ||
| 150 | ipl = interrupts_disable(); |
- | |
| 151 | - | ||
| 152 | /* On success, this will lock t->debug_lock */ |
- | |
| 153 | rc = _thread_op_begin(phone, t); |
- | |
| 154 | if (rc != EOK) { |
- | |
| 155 | interrupts_restore(ipl); |
- | |
| 156 | return rc; |
- | |
| 157 | } |
- | |
| 158 | - | ||
| 159 | t->debug_go_call = call; |
- | |
| 160 | t->debug_stop = false; |
- | |
| 161 | t->cur_event = 0; /* none */ |
- | |
| 162 | - | ||
| 163 | /* |
- | |
| 164 | * Neither t's lock nor threads_lock may be held during wakeup |
- | |
| 165 | */ |
- | |
| 166 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
- | |
| 167 | - | ||
| 168 | _thread_op_end(t); |
- | |
| 169 | interrupts_restore(ipl); |
- | |
| 170 | - | ||
| 171 | return 0; /* no backsend */ |
- | |
| 172 | } |
- | |
| 173 | - | ||
| 174 | static int udebug_rp_args_read(call_t *call, phone_t *phone) |
- | |
| 175 | { |
- | |
| 176 | thread_t *t; |
- | |
| 177 | void *uspace_buffer; |
- | |
| 178 | int rc; |
- | |
| 179 | ipl_t ipl; |
- | |
| 180 | unative_t buffer[6]; |
- | |
| 181 | - | ||
| 182 | klog_printf("debug_args_read()"); |
- | |
| 183 | - | ||
| 184 | t = (thread_t *)IPC_GET_ARG2(call->data); |
- | |
| 185 | - | ||
| 186 | ipl = interrupts_disable(); |
- | |
| 187 | - | ||
| 188 | /* On success, this will lock t->debug_lock */ |
- | |
| 189 | rc = _thread_op_begin(phone, t); |
- | |
| 190 | if (rc != EOK) { |
- | |
| 191 | interrupts_restore(ipl); |
- | |
| 192 | return rc; |
- | |
| 193 | } |
- | |
| 194 | - | ||
| 195 | /* Additionally we need to verify that we are inside a syscall */ |
- | |
| 196 | if (t->cur_event != UDEBUG_EVENT_SYSCALL) { |
- | |
| 197 | _thread_op_end(t); |
- | |
| 198 | interrupts_restore(ipl); |
- | |
| 199 | return EINVAL; |
- | |
| 200 | } |
- | |
| 201 | - | ||
| 202 | /* Copy to a local buffer before releasing the lock */ |
- | |
| 203 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
- | |
| 204 | - | ||
| 205 | _thread_op_end(t); |
- | |
| 206 | interrupts_restore(ipl); |
- | |
| 207 | - | ||
| 208 | /* Now copy to userspace */ |
- | |
| 209 | - | ||
| 210 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
- | |
| 211 | - | ||
| 212 | rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t)); |
- | |
| 213 | if (rc != 0) { |
- | |
| 214 | klog_printf("debug_args_read() - copy failed"); |
- | |
| 215 | return rc; |
- | |
| 216 | } |
- | |
| 217 | - | ||
| 218 | klog_printf("debug_args_read() done"); |
- | |
| 219 | return 1; /* actually need becksend with retval 0 */ |
- | |
| 220 | } |
- | |
| 221 | - | ||
| 222 | static int udebug_rp_regs_read(call_t *call, phone_t *phone) |
- | |
| 223 | { |
- | |
| 224 | thread_t *t; |
- | |
| 225 | void *uspace_buffer; |
- | |
| 226 | unative_t to_copy; |
- | |
| 227 | int rc; |
- | |
| 228 | istate_t *state; |
- | |
| 229 | istate_t state_copy; |
- | |
| 230 | ipl_t ipl; |
- | |
| 231 | - | ||
| 232 | klog_printf("debug_regs_read()"); |
- | |
| 233 | - | ||
| 234 | t = (thread_t *) IPC_GET_ARG2(call->data); |
- | |
| 235 | - | ||
| 236 | ipl = interrupts_disable(); |
- | |
| 237 | - | ||
| 238 | /* On success, this will lock t->debug_lock */ |
- | |
| 239 | rc = _thread_op_begin(phone, t); |
- | |
| 240 | if (rc != EOK) { |
- | |
| 241 | interrupts_restore(ipl); |
- | |
| 242 | return rc; |
- | |
| 243 | } |
- | |
| 244 | - | ||
| 245 | state = t->uspace_state; |
- | |
| 246 | if (state == NULL) { |
- | |
| 247 | _thread_op_end(t); |
- | |
| 248 | interrupts_restore(ipl); |
- | |
| 249 | klog_printf("debug_regs_read() - istate not available"); |
- | |
| 250 | return EBUSY; |
- | |
| 251 | } |
- | |
| 252 | - | ||
| 253 | /* Copy to a local buffer so that we can release the lock */ |
- | |
| 254 | memcpy(&state_copy, state, sizeof(state_copy)); |
- | |
| 255 | _thread_op_end(t); |
- | |
| 256 | interrupts_restore(ipl); |
- | |
| 257 | - | ||
| 258 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
- | |
| 259 | to_copy = IPC_GET_ARG4(call->data); |
- | |
| 260 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
- | |
| 261 | - | ||
| 262 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
- | |
| 263 | if (rc != 0) { |
- | |
| 264 | klog_printf("debug_regs_read() - copy failed"); |
- | |
| 265 | return rc; |
- | |
| 266 | } |
- | |
| 267 | - | ||
| 268 | IPC_SET_ARG1(call->data, to_copy); |
- | |
| 269 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
- | |
| 270 | - | ||
| 271 | klog_printf("debug_regs_read() done"); |
- | |
| 272 | return 1; /* actually need becksend with retval 0 */ |
- | |
| 273 | } |
- | |
| 274 | - | ||
| 275 | - | ||
| 276 | - | ||
| 277 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
98 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
| 278 | { |
99 | { |
| 279 | thread_t *t; |
- | |
| 280 | void *uspace_data; |
100 | void *uspace_data; |
| 281 | unative_t to_copy; |
101 | unative_t to_copy; |
| 282 | int rc; |
102 | int rc; |
| 283 | istate_t *state; |
103 | void *buffer; |
| 284 | istate_t data_copy; |
- | |
| 285 | ipl_t ipl; |
- | |
| 286 | 104 | ||
| 287 | klog_printf("debug_regs_write()"); |
105 | klog_printf("debug_regs_write()"); |
| 288 | 106 | ||
| 289 | /* First copy to a local buffer */ |
- | |
| 290 | - | ||
| 291 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
107 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
| 292 | to_copy = IPC_GET_ARG4(call->data); |
108 | to_copy = IPC_GET_ARG4(call->data); |
| 293 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
109 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
| 294 | 110 | ||
| - | 111 | buffer = malloc(to_copy, 0); // ??? |
|
| - | 112 | ||
| 295 | rc = copy_from_uspace(&data_copy, uspace_data, to_copy); |
113 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
| 296 | if (rc != 0) { |
114 | if (rc != 0) { |
| 297 | klog_printf("debug_regs_write() - copy failed"); |
115 | klog_printf("debug_regs_write() - copy failed"); |
| 298 | return rc; |
116 | return rc; |
| 299 | } |
117 | } |
| 300 | 118 | ||
| 301 | /* Now try to change the thread's uspace_state */ |
- | |
| 302 | - | ||
| 303 | ipl = interrupts_disable(); |
- | |
| 304 | t = (thread_t *) IPC_GET_ARG2(call->data); |
- | |
| 305 | - | ||
| 306 | /* On success, this will lock t->debug_lock */ |
- | |
| 307 | rc = _thread_op_begin(phone, t); |
- | |
| 308 | if (rc != EOK) { |
- | |
| 309 | interrupts_restore(ipl); |
- | |
| 310 | return rc; |
- | |
| 311 | } |
- | |
| 312 | - | ||
| 313 | state = t->uspace_state; |
- | |
| 314 | if (state == NULL) { |
- | |
| 315 | _thread_op_end(t); |
- | |
| 316 | interrupts_restore(ipl); |
- | |
| 317 | klog_printf("debug_regs_write() - istate not available"); |
- | |
| 318 | return EBUSY; |
- | |
| 319 | } |
- | |
| 320 | - | ||
| 321 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
- | |
| 322 | - | ||
| 323 | _thread_op_end(t); |
- | |
| 324 | interrupts_restore(ipl); |
- | |
| 325 | - | ||
| 326 | /* Set answer values */ |
119 | call->buffer = buffer; |
| 327 | - | ||
| 328 | IPC_SET_ARG1(call->data, to_copy); |
- | |
| 329 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
- | |
| 330 | 120 | ||
| 331 | klog_printf("debug_regs_write() done"); |
121 | klog_printf(" - done"); |
| 332 | return 1; /* actually need becksend with retval 0 */ |
122 | return 0; /* No backsend */ |
| 333 | } |
123 | } |
| 334 | 124 | ||
| 335 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
125 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
| 336 | { |
126 | { |
| 337 | void *uspace_data; |
127 | void *uspace_data; |
| Line 362... | Line 152... | ||
| 362 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
152 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
| 363 | { |
153 | { |
| 364 | int rc; |
154 | int rc; |
| 365 | 155 | ||
| 366 | switch (IPC_GET_ARG1(call->data)) { |
156 | switch (IPC_GET_ARG1(call->data)) { |
| 367 | case UDEBUG_M_GO: |
- | |
| 368 | rc = udebug_rp_go(call, phone); |
- | |
| 369 | return rc; |
- | |
| 370 | case UDEBUG_M_ARGS_READ: |
- | |
| 371 | rc = udebug_rp_args_read(call, phone); |
- | |
| 372 | return rc; |
- | |
| 373 | case UDEBUG_M_REGS_READ: |
- | |
| 374 | rc = udebug_rp_regs_read(call, phone); |
- | |
| 375 | return rc; |
- | |
| 376 | case UDEBUG_M_REGS_WRITE: |
157 | case UDEBUG_M_REGS_WRITE: |
| 377 | rc = udebug_rp_regs_write(call, phone); |
158 | rc = udebug_rp_regs_write(call, phone); |
| 378 | return rc; |
159 | return rc; |
| 379 | case UDEBUG_M_MEM_WRITE: |
160 | case UDEBUG_M_MEM_WRITE: |
| 380 | rc = udebug_rp_mem_write(call, phone); |
161 | rc = udebug_rp_mem_write(call, phone); |
| Line 467... | Line 248... | ||
| 467 | 248 | ||
| 468 | IPC_SET_RETVAL(call->data, 0); |
249 | IPC_SET_RETVAL(call->data, 0); |
| 469 | ipc_answer(&TASK->kernel_box, call); |
250 | ipc_answer(&TASK->kernel_box, call); |
| 470 | } |
251 | } |
| 471 | 252 | ||
| - | 253 | static void udebug_receive_go(call_t *call) |
|
| - | 254 | { |
|
| - | 255 | thread_t *t; |
|
| - | 256 | ipl_t ipl; |
|
| - | 257 | int rc; |
|
| - | 258 | ||
| - | 259 | klog_printf("debug_go()"); |
|
| - | 260 | ||
| - | 261 | t = (thread_t *)IPC_GET_ARG2(call->data); |
|
| - | 262 | ||
| - | 263 | ipl = interrupts_disable(); |
|
| - | 264 | ||
| - | 265 | /* On success, this will lock t->debug_lock */ |
|
| - | 266 | rc = _thread_op_begin(t); |
|
| - | 267 | if (rc != EOK) { |
|
| - | 268 | interrupts_restore(ipl); |
|
| - | 269 | ||
| - | 270 | IPC_SET_RETVAL(call->data, rc); |
|
| - | 271 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 272 | return; |
|
| - | 273 | } |
|
| - | 274 | ||
| - | 275 | t->debug_go_call = call; |
|
| - | 276 | t->debug_stop = false; |
|
| - | 277 | t->cur_event = 0; /* none */ |
|
| - | 278 | ||
| - | 279 | /* |
|
| - | 280 | * Neither t's lock nor threads_lock may be held during wakeup |
|
| - | 281 | */ |
|
| - | 282 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
|
| - | 283 | ||
| - | 284 | _thread_op_end(t); |
|
| - | 285 | interrupts_restore(ipl); |
|
| - | 286 | ||
| - | 287 | /* No reply */ |
|
| - | 288 | } |
|
| - | 289 | ||
| - | 290 | ||
| 472 | static void udebug_receive_thread_read(call_t *call) |
291 | static void udebug_receive_thread_read(call_t *call) |
| 473 | { |
292 | { |
| 474 | thread_t *t; |
293 | thread_t *t; |
| 475 | link_t *cur; |
294 | link_t *cur; |
| 476 | unative_t uspace_addr; |
295 | unative_t uspace_addr; |
| Line 553... | Line 372... | ||
| 553 | call->buffer = (void *)buffer; |
372 | call->buffer = (void *)buffer; |
| 554 | 373 | ||
| 555 | ipc_answer(&TASK->kernel_box, call); |
374 | ipc_answer(&TASK->kernel_box, call); |
| 556 | } |
375 | } |
| 557 | 376 | ||
| - | 377 | static void udebug_receive_args_read(call_t *call) |
|
| - | 378 | { |
|
| - | 379 | thread_t *t; |
|
| - | 380 | unative_t uspace_addr; |
|
| - | 381 | int rc; |
|
| - | 382 | ipl_t ipl; |
|
| - | 383 | unative_t *buffer; |
|
| - | 384 | ||
| - | 385 | klog_printf("debug_args_read()"); |
|
| - | 386 | ||
| - | 387 | t = (thread_t *)IPC_GET_ARG2(call->data); |
|
| - | 388 | ||
| - | 389 | ipl = interrupts_disable(); |
|
| - | 390 | ||
| - | 391 | /* On success, this will lock t->debug_lock */ |
|
| - | 392 | rc = _thread_op_begin(t); |
|
| - | 393 | if (rc != EOK) { |
|
| - | 394 | interrupts_restore(ipl); |
|
| - | 395 | IPC_SET_RETVAL(call->data, rc); |
|
| - | 396 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 397 | return; |
|
| - | 398 | } |
|
| - | 399 | ||
| - | 400 | /* Additionally we need to verify that we are inside a syscall */ |
|
| - | 401 | if (t->cur_event != UDEBUG_EVENT_SYSCALL) { |
|
| - | 402 | _thread_op_end(t); |
|
| - | 403 | interrupts_restore(ipl); |
|
| - | 404 | ||
| - | 405 | IPC_SET_RETVAL(call->data, EINVAL); |
|
| - | 406 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 407 | return; |
|
| - | 408 | } |
|
| - | 409 | ||
| - | 410 | /* Copy to a local buffer before releasing the lock */ |
|
| - | 411 | buffer = malloc(6 * sizeof(unative_t), 0); // ??? |
|
| - | 412 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
|
| - | 413 | ||
| - | 414 | _thread_op_end(t); |
|
| - | 415 | interrupts_restore(ipl); |
|
| - | 416 | ||
| - | 417 | /* |
|
| - | 418 | * Make use of call->buffer to transfer data to caller's userspace |
|
| - | 419 | */ |
|
| - | 420 | ||
| - | 421 | uspace_addr = IPC_GET_ARG3(call->data); |
|
| - | 422 | ||
| - | 423 | IPC_SET_RETVAL(call->data, 0); |
|
| - | 424 | /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
|
| - | 425 | same code in process_answer() can be used |
|
| - | 426 | (no way to distinguish method in answer) */ |
|
| - | 427 | IPC_SET_ARG1(call->data, uspace_addr); |
|
| - | 428 | IPC_SET_ARG2(call->data, 6 * sizeof(unative_t)); |
|
| - | 429 | call->buffer = (void *)buffer; |
|
| - | 430 | ||
| - | 431 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 432 | } |
|
| - | 433 | ||
| - | 434 | static void udebug_receive_regs_read(call_t *call) |
|
| - | 435 | { |
|
| - | 436 | thread_t *t; |
|
| - | 437 | unative_t uspace_addr; |
|
| - | 438 | unative_t to_copy; |
|
| - | 439 | unative_t buf_size; |
|
| - | 440 | unative_t total_bytes; |
|
| - | 441 | istate_t *state; |
|
| - | 442 | void *buffer; |
|
| - | 443 | int rc; |
|
| - | 444 | ipl_t ipl; |
|
| - | 445 | ||
| - | 446 | klog_printf("debug_regs_read()"); |
|
| - | 447 | ||
| - | 448 | t = (thread_t *) IPC_GET_ARG2(call->data); |
|
| - | 449 | ||
| - | 450 | ipl = interrupts_disable(); |
|
| - | 451 | ||
| - | 452 | /* On success, this will lock t->debug_lock */ |
|
| - | 453 | rc = _thread_op_begin(t); |
|
| - | 454 | if (rc != EOK) { |
|
| - | 455 | interrupts_restore(ipl); |
|
| - | 456 | ||
| - | 457 | IPC_SET_RETVAL(call->data, rc); |
|
| - | 458 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 459 | return; |
|
| - | 460 | } |
|
| - | 461 | ||
| - | 462 | state = t->uspace_state; |
|
| - | 463 | if (state == NULL) { |
|
| - | 464 | _thread_op_end(t); |
|
| - | 465 | interrupts_restore(ipl); |
|
| - | 466 | klog_printf("debug_regs_read() - istate not available"); |
|
| - | 467 | ||
| - | 468 | IPC_SET_RETVAL(call->data, EBUSY); |
|
| - | 469 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 470 | return; |
|
| - | 471 | } |
|
| - | 472 | ||
| - | 473 | /* Copy to an allocated buffer */ |
|
| - | 474 | buffer = malloc(sizeof(istate_t), 0); // ??? |
|
| - | 475 | memcpy(buffer, state, sizeof(istate_t)); |
|
| - | 476 | ||
| - | 477 | _thread_op_end(t); |
|
| - | 478 | interrupts_restore(ipl); |
|
| - | 479 | ||
| - | 480 | /* |
|
| - | 481 | * Make use of call->buffer to transfer data to caller's userspace |
|
| - | 482 | */ |
|
| - | 483 | ||
| - | 484 | uspace_addr = IPC_GET_ARG3(call->data); |
|
| - | 485 | buf_size = IPC_GET_ARG4(call->data); |
|
| - | 486 | ||
| - | 487 | total_bytes = sizeof(istate_t); |
|
| - | 488 | ||
| - | 489 | if (buf_size > total_bytes) |
|
| - | 490 | to_copy = total_bytes; |
|
| - | 491 | else |
|
| - | 492 | to_copy = buf_size; |
|
| - | 493 | ||
| - | 494 | IPC_SET_RETVAL(call->data, 0); |
|
| - | 495 | /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
|
| - | 496 | same code in process_answer() can be used |
|
| - | 497 | (no way to distinguish method in answer) */ |
|
| - | 498 | IPC_SET_ARG1(call->data, uspace_addr); |
|
| - | 499 | IPC_SET_ARG2(call->data, to_copy); |
|
| - | 500 | ||
| - | 501 | IPC_SET_ARG3(call->data, total_bytes); |
|
| - | 502 | call->buffer = (void *)buffer; |
|
| - | 503 | ||
| - | 504 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 505 | } |
|
| - | 506 | ||
| - | 507 | static void udebug_receive_regs_write(call_t *call) |
|
| - | 508 | { |
|
| - | 509 | thread_t *t; |
|
| - | 510 | void *uspace_data; |
|
| - | 511 | unative_t to_copy; |
|
| - | 512 | int rc; |
|
| - | 513 | istate_t *state; |
|
| - | 514 | ipl_t ipl; |
|
| - | 515 | ||
| - | 516 | klog_printf("debug_regs_write()"); |
|
| - | 517 | ||
| - | 518 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
|
| - | 519 | to_copy = IPC_GET_ARG4(call->data); |
|
| - | 520 | ||
| - | 521 | /* Try to change the thread's uspace_state */ |
|
| - | 522 | ||
| - | 523 | ipl = interrupts_disable(); |
|
| - | 524 | t = (thread_t *) IPC_GET_ARG2(call->data); |
|
| - | 525 | ||
| - | 526 | /* On success, this will lock t->debug_lock */ |
|
| - | 527 | rc = _thread_op_begin(t); |
|
| - | 528 | if (rc != EOK) { |
|
| - | 529 | interrupts_restore(ipl); |
|
| - | 530 | ||
| - | 531 | IPC_SET_RETVAL(call->data, rc); |
|
| - | 532 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 533 | return; |
|
| - | 534 | } |
|
| - | 535 | ||
| - | 536 | state = t->uspace_state; |
|
| - | 537 | if (state == NULL) { |
|
| - | 538 | _thread_op_end(t); |
|
| - | 539 | interrupts_restore(ipl); |
|
| - | 540 | klog_printf("debug_regs_write() - istate not available"); |
|
| - | 541 | ||
| - | 542 | IPC_SET_RETVAL(call->data, EBUSY); |
|
| - | 543 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 544 | return; |
|
| - | 545 | } |
|
| - | 546 | ||
| - | 547 | memcpy(t->uspace_state, call->buffer, sizeof(t->uspace_state)); |
|
| - | 548 | ||
| - | 549 | _thread_op_end(t); |
|
| - | 550 | interrupts_restore(ipl); |
|
| - | 551 | ||
| - | 552 | /* Set answer values */ |
|
| - | 553 | ||
| - | 554 | IPC_SET_ARG1(call->data, to_copy); |
|
| - | 555 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
|
| - | 556 | ||
| - | 557 | IPC_SET_RETVAL(call->data, 0); |
|
| - | 558 | ipc_answer(&TASK->kernel_box, call); |
|
| - | 559 | ||
| - | 560 | klog_printf("debug_regs_write() done"); |
|
| - | 561 | } |
|
| - | 562 | ||
| 558 | 563 | ||
| 559 | static void udebug_receive_mem_read(call_t *call) |
564 | static void udebug_receive_mem_read(call_t *call) |
| 560 | { |
565 | { |
| 561 | unative_t uspace_dst; |
566 | unative_t uspace_dst; |
| 562 | void *uspace_ptr; |
567 | void *uspace_ptr; |
| Line 575... | Line 580... | ||
| 575 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
580 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
| 576 | * be a problem */ |
581 | * be a problem */ |
| 577 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
582 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
| 578 | if (rc) { |
583 | if (rc) { |
| 579 | IPC_SET_RETVAL(call->data, rc); |
584 | IPC_SET_RETVAL(call->data, rc); |
| - | 585 | ipc_answer(&TASK->kernel_box, call); |
|
| 580 | return; |
586 | return; |
| 581 | } |
587 | } |
| 582 | 588 | ||
| 583 | klog_printf("first word: %u", *((unative_t *)buffer)); |
589 | klog_printf("first word: %u", *((unative_t *)buffer)); |
| 584 | 590 | ||
| Line 654... | Line 660... | ||
| 654 | udebug_receive_begin(call); |
660 | udebug_receive_begin(call); |
| 655 | break; |
661 | break; |
| 656 | case UDEBUG_M_END: |
662 | case UDEBUG_M_END: |
| 657 | udebug_receive_end(call); |
663 | udebug_receive_end(call); |
| 658 | break; |
664 | break; |
| - | 665 | case UDEBUG_M_GO: |
|
| - | 666 | udebug_receive_go(call); |
|
| - | 667 | break; |
|
| 659 | case UDEBUG_M_THREAD_READ: |
668 | case UDEBUG_M_THREAD_READ: |
| 660 | udebug_receive_thread_read(call); |
669 | udebug_receive_thread_read(call); |
| 661 | break; |
670 | break; |
| - | 671 | case UDEBUG_M_ARGS_READ: |
|
| - | 672 | udebug_receive_args_read(call); |
|
| - | 673 | break; |
|
| - | 674 | case UDEBUG_M_REGS_READ: |
|
| - | 675 | udebug_receive_regs_read(call); |
|
| - | 676 | break; |
|
| - | 677 | case UDEBUG_M_REGS_WRITE: |
|
| - | 678 | udebug_receive_regs_write(call); |
|
| - | 679 | break; |
|
| 662 | case UDEBUG_M_MEM_READ: |
680 | case UDEBUG_M_MEM_READ: |
| 663 | udebug_receive_mem_read(call); |
681 | udebug_receive_mem_read(call); |
| 664 | break; |
682 | break; |
| 665 | case UDEBUG_M_MEM_WRITE: |
683 | case UDEBUG_M_MEM_WRITE: |
| 666 | udebug_receive_mem_write(call); |
684 | udebug_receive_mem_write(call); |