Rev 2870 | Rev 2886 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2870 | Rev 2885 | ||
---|---|---|---|
Line 45... | Line 45... | ||
45 | 45 | ||
46 | return taskid; |
46 | return taskid; |
47 | } |
47 | } |
48 | 48 | ||
49 | /** |
49 | /** |
50 | * Get and lock a phone's callee task. |
- | |
51 | * |
- | |
52 | * This will return a pointer to the task to which the phone |
- | |
53 | * is connected. It will lock the task, making sure it exists. |
- | |
54 | * |
- | |
55 | * Interrupts must be already disabled. |
- | |
56 | */ |
- | |
57 | static task_t *get_lock_callee_task(phone_t *phone) |
- | |
58 | { |
- | |
59 | task_t *ta; |
- | |
60 | task_id_t taskid; |
- | |
61 | - | ||
62 | taskid = get_callee_task_id(phone); |
- | |
63 | - | ||
64 | spinlock_lock(&tasks_lock); |
- | |
65 | ta = task_find_by_id(taskid); |
- | |
66 | if (ta == NULL) { |
- | |
67 | spinlock_unlock(&tasks_lock); |
- | |
68 | return NULL; |
- | |
69 | } |
- | |
70 | - | ||
71 | spinlock_lock(&ta->lock); |
- | |
72 | spinlock_unlock(&tasks_lock); |
- | |
73 | - | ||
74 | return ta; |
- | |
75 | } |
- | |
76 | - | ||
77 | /** |
- | |
78 | * Prepare a thread for a debugging operation. |
50 | * Prepare a thread for a debugging operation. |
79 | * |
51 | * |
80 | * Simply put, return thread t with t->debug_lock held, |
52 | * Simply put, return thread t with t->debug_lock held, |
81 | * but only if it verifies all conditions. |
53 | * but only if it verifies all conditions. |
82 | * |
54 | * |
Line 163... | Line 135... | ||
163 | static void _thread_op_end(thread_t *t) |
135 | static void _thread_op_end(thread_t *t) |
164 | { |
136 | { |
165 | spinlock_unlock(&t->debug_lock); |
137 | spinlock_unlock(&t->debug_lock); |
166 | } |
138 | } |
167 | 139 | ||
168 | static int udebug_rp_begin(call_t *call, phone_t *phone) |
- | |
169 | { |
- | |
170 | task_t *ta; |
- | |
171 | ipl_t ipl; |
- | |
172 | int rc; |
- | |
173 | - | ||
174 | thread_t *t; |
- | |
175 | link_t *cur; |
- | |
176 | - | ||
177 | klog_printf("debug_begin()"); |
- | |
178 | - | ||
179 | ipl = interrupts_disable(); |
- | |
180 | ta = get_lock_callee_task(phone); |
- | |
181 | klog_printf("debugging task %llu", ta->taskid); |
- | |
182 | - | ||
183 | if (ta->dt_state != UDEBUG_TS_INACTIVE) { |
- | |
184 | spinlock_unlock(&ta->lock); |
- | |
185 | interrupts_restore(ipl); |
- | |
186 | klog_printf("debug_begin(): busy error"); |
- | |
187 | return EBUSY; |
- | |
188 | } |
- | |
189 | - | ||
190 | ta->dt_state = UDEBUG_TS_BEGINNING; |
- | |
191 | ta->debug_begin_call = call; |
- | |
192 | ta->debugger = call->sender; |
- | |
193 | - | ||
194 | if (ta->not_stoppable_count == 0) { |
- | |
195 | ta->dt_state = UDEBUG_TS_ACTIVE; |
- | |
196 | ta->debug_begin_call = NULL; |
- | |
197 | rc = 1; /* actually we need backsend with 0 retval */ |
- | |
198 | } else { |
- | |
199 | rc = 0; /* no backsend */ |
- | |
200 | } |
- | |
201 | - | ||
202 | /* Set debug_active on all of the task's userspace threads */ |
- | |
203 | - | ||
204 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
- | |
205 | t = list_get_instance(cur, thread_t, th_link); |
- | |
206 | - | ||
207 | spinlock_lock(&t->debug_lock); |
- | |
208 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
- | |
209 | t->debug_active = true; |
- | |
210 | spinlock_unlock(&t->debug_lock); |
- | |
211 | } |
- | |
212 | - | ||
213 | spinlock_unlock(&ta->lock); |
- | |
214 | interrupts_restore(ipl); |
- | |
215 | - | ||
216 | klog_printf("debug_begin() done (%s)", |
- | |
217 | rc ? "backsend" : "stoppability wait"); |
- | |
218 | - | ||
219 | return rc; |
- | |
220 | } |
- | |
221 | - | ||
222 | static int udebug_rp_end(call_t *call, phone_t *phone) |
- | |
223 | { |
- | |
224 | task_t *ta; |
- | |
225 | ipl_t ipl; |
- | |
226 | int rc; |
- | |
227 | - | ||
228 | klog_printf("udebug_rp_end()"); |
- | |
229 | - | ||
230 | ipl = interrupts_disable(); |
- | |
231 | ta = get_lock_callee_task(phone); |
- | |
232 | - | ||
233 | rc = udebug_task_cleanup(ta); |
- | |
234 | - | ||
235 | klog_printf("task %llu", ta->taskid); |
- | |
236 | - | ||
237 | spinlock_unlock(&ta->lock); |
- | |
238 | interrupts_restore(ipl); |
- | |
239 | - | ||
240 | if (rc < 0) { |
- | |
241 | return EINVAL; |
- | |
242 | } |
- | |
243 | - | ||
244 | IPC_SET_RETVAL(call->data, 0); |
- | |
245 | - | ||
246 | klog_printf("udebug_rp_end() done\n"); |
- | |
247 | - | ||
248 | return 1; |
- | |
249 | } |
- | |
250 | - | ||
251 | - | ||
252 | static int udebug_rp_go(call_t *call, phone_t *phone) |
140 | static int udebug_rp_go(call_t *call, phone_t *phone) |
253 | { |
141 | { |
254 | thread_t *t; |
142 | thread_t *t; |
255 | ipl_t ipl; |
143 | ipl_t ipl; |
256 | int rc; |
144 | int rc; |
Line 442... | Line 330... | ||
442 | 330 | ||
443 | klog_printf("debug_regs_write() done"); |
331 | klog_printf("debug_regs_write() done"); |
444 | return 1; /* actually need becksend with retval 0 */ |
332 | return 1; /* actually need becksend with retval 0 */ |
445 | } |
333 | } |
446 | 334 | ||
447 | static int udebug_rp_thread_read(call_t *call, phone_t *phone) |
335 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
- | 336 | { |
|
- | 337 | void *uspace_data; |
|
- | 338 | unative_t to_copy; |
|
- | 339 | int rc; |
|
- | 340 | void *buffer; |
|
- | 341 | ||
- | 342 | klog_printf("udebug_rp_mem_write()"); |
|
- | 343 | ||
- | 344 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
|
- | 345 | to_copy = IPC_GET_ARG4(call->data); |
|
- | 346 | ||
- | 347 | buffer = malloc(to_copy, 0); // ??? |
|
- | 348 | ||
- | 349 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
|
- | 350 | if (rc != 0) { |
|
- | 351 | klog_printf(" - copy failed"); |
|
- | 352 | return rc; |
|
- | 353 | } |
|
- | 354 | ||
- | 355 | call->buffer = buffer; |
|
- | 356 | ||
- | 357 | klog_printf(" - done"); |
|
- | 358 | return 1; /* actually need becksend with retval 0 */ |
|
- | 359 | } |
|
- | 360 | ||
- | 361 | ||
- | 362 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
|
448 | { |
363 | { |
- | 364 | int rc; |
|
- | 365 | ||
- | 366 | 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: |
|
- | 377 | rc = udebug_rp_regs_write(call, phone); |
|
- | 378 | return rc; |
|
- | 379 | case UDEBUG_M_MEM_WRITE: |
|
- | 380 | rc = udebug_rp_mem_write(call, phone); |
|
- | 381 | return rc; |
|
- | 382 | default: |
|
- | 383 | break; |
|
- | 384 | } |
|
- | 385 | ||
- | 386 | return 0; |
|
- | 387 | } |
|
- | 388 | ||
- | 389 | static void udebug_receive_begin(call_t *call) |
|
- | 390 | { |
|
- | 391 | ipl_t ipl; |
|
- | 392 | int reply; |
|
- | 393 | ||
449 | thread_t *t; |
394 | thread_t *t; |
450 | link_t *cur; |
395 | link_t *cur; |
- | 396 | ||
- | 397 | klog_printf("debug_begin()"); |
|
- | 398 | ||
- | 399 | ipl = interrupts_disable(); |
|
- | 400 | klog_printf("debugging task %llu", TASK->taskid); |
|
- | 401 | ||
- | 402 | spinlock_lock(&TASK->lock); |
|
- | 403 | ||
- | 404 | if (TASK->dt_state != UDEBUG_TS_INACTIVE) { |
|
- | 405 | spinlock_unlock(&TASK->lock); |
|
- | 406 | interrupts_restore(ipl); |
|
- | 407 | klog_printf("debug_begin(): busy error"); |
|
- | 408 | ||
- | 409 | IPC_SET_RETVAL(call->data, EBUSY); |
|
- | 410 | ipc_answer(&TASK->kernel_box, call); |
|
- | 411 | } |
|
- | 412 | ||
- | 413 | TASK->dt_state = UDEBUG_TS_BEGINNING; |
|
- | 414 | TASK->debug_begin_call = call; |
|
- | 415 | TASK->debugger = call->sender; |
|
- | 416 | ||
- | 417 | if (TASK->not_stoppable_count == 0) { |
|
- | 418 | TASK->dt_state = UDEBUG_TS_ACTIVE; |
|
- | 419 | TASK->debug_begin_call = NULL; |
|
- | 420 | reply = 1; /* immediate reply */ |
|
451 | task_t *ta; |
421 | } else { |
- | 422 | reply = 0; /* no reply */ |
|
- | 423 | } |
|
- | 424 | ||
- | 425 | /* Set debug_active on all of the task's userspace threads */ |
|
- | 426 | ||
- | 427 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
|
- | 428 | t = list_get_instance(cur, thread_t, th_link); |
|
- | 429 | ||
- | 430 | spinlock_lock(&t->debug_lock); |
|
- | 431 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
|
- | 432 | t->debug_active = true; |
|
- | 433 | spinlock_unlock(&t->debug_lock); |
|
- | 434 | } |
|
- | 435 | ||
- | 436 | spinlock_unlock(&TASK->lock); |
|
452 | unative_t *uspace_buffer; |
437 | interrupts_restore(ipl); |
- | 438 | ||
- | 439 | klog_printf("debug_begin() done (%s)", |
|
- | 440 | reply ? "reply" : "stoppability wait"); |
|
- | 441 | ||
- | 442 | if (reply) ipc_answer(&TASK->kernel_box, call); |
|
- | 443 | } |
|
- | 444 | ||
- | 445 | static void udebug_receive_end(call_t *call) |
|
- | 446 | { |
|
453 | unative_t to_copy; |
447 | ipl_t ipl; |
454 | int rc; |
448 | int rc; |
- | 449 | ||
- | 450 | klog_printf("udebug_receive_end()"); |
|
- | 451 | ||
- | 452 | ipl = interrupts_disable(); |
|
- | 453 | spinlock_lock(&TASK->lock); |
|
- | 454 | ||
- | 455 | rc = udebug_task_cleanup(TASK); |
|
- | 456 | ||
- | 457 | klog_printf("task %llu", TASK->taskid); |
|
- | 458 | ||
- | 459 | spinlock_unlock(&TASK->lock); |
|
- | 460 | interrupts_restore(ipl); |
|
- | 461 | ||
- | 462 | if (rc < 0) { |
|
- | 463 | IPC_SET_RETVAL(call->data, EINVAL); |
|
- | 464 | ipc_answer(&TASK->kernel_box, call); |
|
- | 465 | return; |
|
- | 466 | } |
|
- | 467 | ||
- | 468 | IPC_SET_RETVAL(call->data, 0); |
|
- | 469 | ipc_answer(&TASK->kernel_box, call); |
|
- | 470 | } |
|
- | 471 | ||
- | 472 | static void udebug_receive_thread_read(call_t *call) |
|
- | 473 | { |
|
- | 474 | thread_t *t; |
|
- | 475 | link_t *cur; |
|
- | 476 | unative_t uspace_addr; |
|
- | 477 | unative_t to_copy; |
|
455 | unsigned total_bytes; |
478 | unsigned total_bytes; |
456 | unsigned buf_size; |
479 | unsigned buf_size; |
457 | unative_t tid; |
480 | unative_t tid; |
458 | unsigned num_threads, copied_ids; |
481 | unsigned num_threads, copied_ids; |
459 | ipl_t ipl; |
482 | ipl_t ipl; |
Line 461... | Line 484... | ||
461 | int flags; |
484 | int flags; |
462 | 485 | ||
463 | klog_printf("debug_thread_read()"); |
486 | klog_printf("debug_thread_read()"); |
464 | 487 | ||
465 | ipl = interrupts_disable(); |
488 | ipl = interrupts_disable(); |
466 | ta = get_lock_callee_task(phone); |
489 | spinlock_lock(&TASK->lock); |
467 | 490 | ||
468 | /* Verify task state */ |
491 | /* Verify task state */ |
469 | if (ta->dt_state != UDEBUG_TS_ACTIVE) { |
492 | if (TASK->dt_state != UDEBUG_TS_ACTIVE) { |
470 | spinlock_unlock(&ta->lock); |
493 | spinlock_unlock(&TASK->lock); |
471 | interrupts_restore(ipl); |
494 | interrupts_restore(ipl); |
- | 495 | ||
- | 496 | IPC_SET_RETVAL(call->data, EINVAL); |
|
- | 497 | ipc_answer(&TASK->kernel_box, call); |
|
472 | return EBUSY; |
498 | return; |
473 | } |
499 | } |
474 | 500 | ||
475 | /* Count the threads first */ |
501 | /* Count the threads first */ |
476 | 502 | ||
477 | num_threads = 0; |
503 | num_threads = 0; |
478 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
504 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
479 | /* Count all threads, to be on the safe side */ |
505 | /* Count all threads, to be on the safe side */ |
480 | ++num_threads; |
506 | ++num_threads; |
481 | } |
507 | } |
482 | 508 | ||
483 | /* Allocate a buffer and copy down the threads' ids */ |
509 | /* Allocate a buffer and copy down the threads' ids */ |
484 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
510 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
485 | 511 | ||
486 | copied_ids = 0; |
512 | copied_ids = 0; |
487 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
513 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
488 | t = list_get_instance(cur, thread_t, th_link); |
514 | t = list_get_instance(cur, thread_t, th_link); |
489 | 515 | ||
490 | spinlock_lock(&t->lock); |
516 | spinlock_lock(&t->lock); |
491 | flags = t->flags; |
517 | flags = t->flags; |
492 | spinlock_unlock(&t->lock); |
518 | spinlock_unlock(&t->lock); |
Line 497... | Line 523... | ||
497 | tid = (unative_t) t; |
523 | tid = (unative_t) t; |
498 | buffer[copied_ids++] = tid; |
524 | buffer[copied_ids++] = tid; |
499 | } |
525 | } |
500 | } |
526 | } |
501 | 527 | ||
502 | spinlock_unlock(&ta->lock); |
528 | spinlock_unlock(&TASK->lock); |
503 | interrupts_restore(ipl); |
529 | interrupts_restore(ipl); |
504 | 530 | ||
- | 531 | /* |
|
505 | /* Now copy to userspace */ |
532 | * Prepare data and send it back through call->buffer |
- | 533 | */ |
|
506 | 534 | ||
507 | uspace_buffer = (void *)IPC_GET_ARG2(call->data); |
535 | uspace_addr = IPC_GET_ARG2(call->data); |
508 | buf_size = IPC_GET_ARG3(call->data); |
536 | buf_size = IPC_GET_ARG3(call->data); |
509 | 537 | ||
510 | total_bytes = copied_ids * sizeof(unative_t); |
538 | total_bytes = copied_ids * sizeof(unative_t); |
511 | 539 | ||
512 | if (buf_size > total_bytes) |
540 | if (buf_size > total_bytes) |
513 | to_copy = total_bytes; |
541 | to_copy = total_bytes; |
514 | else |
542 | else |
515 | to_copy = buf_size; |
543 | to_copy = buf_size; |
516 | 544 | ||
517 | rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
- | |
518 | free(buffer); |
- | |
519 | - | ||
520 | if (rc != 0) { |
- | |
521 | klog_printf("debug_thread_read() - copy failed"); |
- | |
522 | return rc; |
- | |
523 | } |
- | |
524 | - | ||
525 | IPC_SET_ARG1(call->data, to_copy); |
545 | IPC_SET_RETVAL(call->data, 0); |
526 | IPC_SET_ARG2(call->data, total_bytes); |
546 | /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
527 | - | ||
528 | klog_printf("debug_thread_read() done"); |
547 | same code in process_answer() can be used |
529 | return 1; /* actually need becksend with retval 0 */ |
548 | (no way to distinguish method in answer) */ |
530 | } |
- | |
531 | - | ||
532 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
- | |
533 | { |
- | |
534 | void *uspace_data; |
- | |
535 | unative_t to_copy; |
- | |
536 | int rc; |
- | |
537 | void *buffer; |
- | |
538 | - | ||
539 | klog_printf("udebug_rp_mem_write()"); |
- | |
540 | - | ||
541 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
- | |
542 | to_copy = IPC_GET_ARG4(call->data); |
549 | IPC_SET_ARG1(call->data, uspace_addr); |
543 | - | ||
544 | buffer = malloc(to_copy, 0); // ??? |
- | |
545 | - | ||
546 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
550 | IPC_SET_ARG2(call->data, to_copy); |
547 | if (rc != 0) { |
- | |
548 | klog_printf(" - copy failed"); |
- | |
549 | return rc; |
- | |
550 | } |
- | |
551 | 551 | ||
- | 552 | IPC_SET_ARG3(call->data, total_bytes); |
|
552 | call->buffer = buffer; |
553 | call->buffer = (void *)buffer; |
553 | 554 | ||
554 | klog_printf(" - done"); |
555 | ipc_answer(&TASK->kernel_box, call); |
555 | return 1; /* actually need becksend with retval 0 */ |
- | |
556 | } |
556 | } |
557 | 557 | ||
558 | 558 | ||
559 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
- | |
560 | { |
- | |
561 | int rc; |
- | |
562 | - | ||
563 | switch (IPC_GET_ARG1(call->data)) { |
- | |
564 | case UDEBUG_M_BEGIN: |
- | |
565 | rc = udebug_rp_begin(call, phone); |
- | |
566 | return rc; |
- | |
567 | case UDEBUG_M_END: |
- | |
568 | rc = udebug_rp_end(call, phone); |
- | |
569 | return rc; |
- | |
570 | case UDEBUG_M_GO: |
- | |
571 | rc = udebug_rp_go(call, phone); |
- | |
572 | return rc; |
- | |
573 | case UDEBUG_M_ARGS_READ: |
- | |
574 | rc = udebug_rp_args_read(call, phone); |
- | |
575 | return rc; |
- | |
576 | case UDEBUG_M_REGS_READ: |
- | |
577 | rc = udebug_rp_regs_read(call, phone); |
- | |
578 | return rc; |
- | |
579 | case UDEBUG_M_REGS_WRITE: |
- | |
580 | rc = udebug_rp_regs_write(call, phone); |
- | |
581 | return rc; |
- | |
582 | case UDEBUG_M_THREAD_READ: |
- | |
583 | rc = udebug_rp_thread_read(call, phone); |
- | |
584 | return rc; |
- | |
585 | case UDEBUG_M_MEM_WRITE: |
- | |
586 | rc = udebug_rp_mem_write(call, phone); |
- | |
587 | return rc; |
- | |
588 | default: |
- | |
589 | break; |
- | |
590 | } |
- | |
591 | - | ||
592 | return 0; |
- | |
593 | } |
- | |
594 | - | ||
595 | static void udebug_receive_mem_read(call_t *call) |
559 | static void udebug_receive_mem_read(call_t *call) |
596 | { |
560 | { |
597 | unative_t uspace_dst; |
561 | unative_t uspace_dst; |
598 | void *uspace_ptr; |
562 | void *uspace_ptr; |
599 | unsigned size; |
563 | unsigned size; |
Line 684... | Line 648... | ||
684 | int debug_method; |
648 | int debug_method; |
685 | 649 | ||
686 | debug_method = IPC_GET_ARG1(call->data); |
650 | debug_method = IPC_GET_ARG1(call->data); |
687 | 651 | ||
688 | switch (debug_method) { |
652 | switch (debug_method) { |
- | 653 | case UDEBUG_M_BEGIN: |
|
- | 654 | udebug_receive_begin(call); |
|
- | 655 | break; |
|
- | 656 | case UDEBUG_M_END: |
|
- | 657 | udebug_receive_end(call); |
|
- | 658 | break; |
|
- | 659 | case UDEBUG_M_THREAD_READ: |
|
- | 660 | udebug_receive_thread_read(call); |
|
- | 661 | break; |
|
689 | case UDEBUG_M_MEM_READ: |
662 | case UDEBUG_M_MEM_READ: |
690 | udebug_receive_mem_read(call); |
663 | udebug_receive_mem_read(call); |
691 | break; |
664 | break; |
692 | case UDEBUG_M_MEM_WRITE: |
665 | case UDEBUG_M_MEM_WRITE: |
693 | udebug_receive_mem_write(call); |
666 | udebug_receive_mem_write(call); |