Subversion Repositories HelenOS

Rev

Rev 2936 | Rev 2938 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup debug
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <unistd.h>
  38. #include <syscall.h>
  39. #include <ipc/ipc.h>
  40. #include <fibril.h>
  41. #include <errno.h>
  42. #include <udebug.h>
  43. #include <async.h>
  44. #include <string.h>
  45.  
  46. #include "cmd.h"
  47. #include "cons.h"
  48. #include "include/arch.h"
  49. #include "fib_synch.h"
  50. #include "main.h"
  51.  
  52. void thread_debug_start(unsigned thread_hash);
  53.  
  54. #define IN_BUF_SIZE 64
  55. static char in_buf[IN_BUF_SIZE];
  56.  
  57. #define MAX_ARGC 10
  58. int cmd_argc;
  59. char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
  60.  
  61. #define THBUF_SIZE 64
  62. thash_t thread_hash_buf[THBUF_SIZE];
  63.  
  64. #define MAX_THREADS 64
  65. thash_t thread_hash[MAX_THREADS];
  66. int thread_id[MAX_THREADS];
  67. unsigned n_threads;
  68. int cwt; /* index into thread_hash/thread_id */
  69.  
  70. int next_thread_id;
  71.  
  72. int app_phone;
  73. volatile bool abort_debug;
  74.  
  75. thash_t thash;
  76. volatile int paused;
  77.  
  78. breakpoint_t brk_list[MAX_BRKPTS];
  79. int lifted_brkpt;
  80.  
  81. fcv_t go_cv;
  82.  
  83. void command_split(char *cmd_str)
  84. {
  85.     char *p = cmd_str;
  86.  
  87.     if (*p == '\0') {
  88.         cmd_argc = 0;
  89.         return;
  90.     }
  91.  
  92.     cmd_argc = 1;
  93.     cmd_argv[0] = p;
  94.  
  95.     while (*p != '\0') {
  96.         if (*p == ' ') {
  97.             cmd_argv[cmd_argc++] = p + 1;
  98.             *p = '\0';
  99.         }
  100.         ++p;
  101.     }
  102. }
  103.  
  104. void command_run(void)
  105. {
  106.     int i;
  107.     int cmp_len;
  108.     int len;
  109.  
  110.     int idx_found;
  111.     int num_found;
  112.  
  113.     len = strlen(cmd_argv[0]);
  114.     cmp_len = 1;
  115.  
  116.     while (cmp_len <= len + 1) {
  117.  
  118.         num_found = 0;
  119.         i = 0;
  120.         while (cmd_table[i].name != NULL) {
  121.             if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
  122.                 idx_found = i;
  123.                 ++num_found;
  124.             }
  125.             ++i;
  126.         }
  127.  
  128.         if (num_found < 2) break;
  129.  
  130.         --cmp_len;
  131.     }
  132.  
  133.     if (num_found == 0) {
  134.         cons_printf("Unknown command. Try one of:\n");
  135.         cmd_help(0, NULL);
  136.         return;
  137.     }
  138.  
  139.     if (cmd_argc - 1 != cmd_table[idx_found].argc) {
  140.         cons_printf("Command '%s' expects %d arguments\n",
  141.         cmd_table[idx_found].name, cmd_table[idx_found].argc);
  142.         return;
  143.     }
  144.  
  145.     (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
  146. }
  147.  
  148. void thread_stop(void)
  149. {
  150.     cons_printf("[t] stopped\n");
  151.     fcv_wait(&go_cv);
  152.     cons_printf("[t] go\n");
  153. }
  154.  
  155. /*
  156.  * Called by a fibril (from arch code) when a breakpoint is hit.
  157.  */
  158. void breakpoint_hit(void)
  159. {
  160.     cons_printf("breakpoint hit\n");
  161.     thread_stop();
  162. }
  163.  
  164. int task_connect(int taskid)
  165. {
  166.     int rc;
  167.     unsigned evmask;
  168.  
  169.     cons_printf("ipc_connect_kbox(%d)... ", taskid);
  170.     rc = ipc_connect_kbox(taskid);
  171.     cons_printf("-> %d\n", rc);
  172.     app_phone = rc;
  173.     if (rc < 0) return rc;
  174.  
  175.     cons_printf("udebug_begin()... ");
  176.     rc = udebug_begin(app_phone);
  177.     cons_printf("-> %d\n", rc);
  178.     if (rc < 0) return rc;
  179.  
  180.     evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
  181.     cons_printf("udebug_set_evmask(0x%x)... ", evmask);
  182.     rc = udebug_set_evmask(app_phone, evmask);
  183.     cons_printf("-> %d\n", rc);
  184.     if (rc < 0) return rc;
  185.  
  186.     return 0;
  187. }
  188.  
  189. int get_thread_list(void)
  190. {
  191.     int rc;
  192.     int tb_copied;
  193.     int tb_needed;
  194.     int i;
  195.     int n;
  196.  
  197.     cons_printf("send IPC_M_DEBUG_THREAD_READ message\n");
  198.     rc = udebug_thread_read(app_phone, (unsigned)thread_hash_buf,
  199.         THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
  200.     cons_printf("-> %d\n", rc);
  201.     if (rc < 0) return rc;
  202.  
  203.     n = tb_copied / sizeof(unsigned);
  204.  
  205.     cons_printf("thread IDs:");
  206.     for (i=0; i<n; i++) {
  207.         cons_printf(" %u", thread_hash_buf[i]);
  208.     }
  209.     cons_printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
  210.  
  211.     return n;
  212. }
  213.  
  214. void event_thread_b(unsigned hash)
  215. {
  216.     async_serialize_start();
  217.     cons_printf("new thread, hash 0x%x\n", hash);
  218.     async_serialize_end();
  219.  
  220.     thread_debug_start(hash);
  221. }
  222.  
  223. static unsigned buffer[1024];
  224.  
  225. static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
  226. {
  227.     switch (ev_type) {
  228.     case UDEBUG_EVENT_STOP:
  229.         cons_printf("stop event\n");
  230.         cons_printf("waiting for resume\n");
  231.         while (paused) {
  232.             usleep(1000000);
  233.             fibril_yield();
  234.             cons_printf(".");
  235.         }
  236.         cons_printf("resumed\n");
  237.         break;
  238.     case UDEBUG_EVENT_THREAD_B:
  239.         event_thread_b(val0);
  240.         break;
  241.     case UDEBUG_EVENT_THREAD_E:
  242.         cons_printf("thread 0x%x exited\n", val0);
  243.         abort_debug = true;
  244.         break;
  245.     case UDEBUG_EVENT_BREAKPOINT:
  246.         arch_event_breakpoint(thash);
  247.         break;
  248.     case UDEBUG_EVENT_TRAP:
  249.         arch_event_trap(thash);
  250.         break;
  251.     default:
  252.         cons_printf("unknown event type %d\n", ev_type);
  253.         break;
  254.     }
  255. }
  256.  
  257. void debug_loop(void *thread_buf_idx_arg)
  258. {
  259.     int rc;
  260.     udebug_event_t ev_type;
  261.     unsigned thread_buf_idx;
  262.     thash_t thash;
  263.     int tid;
  264.     unsigned val0, val1;
  265.  
  266.     thread_buf_idx = (unsigned)thread_buf_idx_arg;
  267.  
  268.     thash = thread_hash[thread_buf_idx];
  269.     tid = thread_id[thread_buf_idx];
  270.  
  271.     cons_printf("debug_loop(%d)\n", tid);
  272.  
  273.     while (!abort_debug) {
  274.  
  275.         /* Run thread until an event occurs */
  276.         rc = udebug_go(app_phone, thash,
  277.             &ev_type, &val0, &val1);
  278.  
  279.         if (ev_type == UDEBUG_EVENT_FINISHED) {
  280.             cons_printf("thread %u debugging finished\n", tid);
  281.             break;
  282.         }
  283.         if (rc >= 0) debug_event(thash, ev_type, val0);
  284.     }
  285.  
  286.     cons_printf("debug_loop(%d) exiting\n", thread_id);
  287. }
  288.  
  289. void thread_debug_start(unsigned thash)
  290. {
  291.     fid_t fid;
  292.  
  293.     thread_hash[n_threads] = thash;
  294.     thread_id[n_threads] = next_thread_id++;
  295.  
  296.     fid = fibril_create(debug_loop, (void *)n_threads++);
  297.     if (fid == 0) {
  298.         cons_printf("Warning: Failed creating fibril\n");
  299.     }
  300.     fibril_add_ready(fid);
  301. }
  302.  
  303. void debug_active_task(void)
  304. {
  305.     int taskid;
  306.     int i;
  307.     int rc;
  308.     int c;
  309.  
  310.     cons_printf("Breakpoint Debugger\n");
  311.     cons_printf("Press 'c' to connect\n");
  312.     while ((i = getchar()) != 'c')
  313.         putchar(i);
  314.  
  315.     taskid = 14;
  316.     rc = task_connect(taskid);
  317.     if (rc < 0) {
  318.         cons_printf("Failed to connect to task %d\n", taskid);
  319.         return;
  320.     }
  321.  
  322.     cons_printf("Connected to task %d\n", taskid);
  323.  
  324.     rc = get_thread_list();
  325.     if (rc < 0) {
  326.         cons_printf("Failed to get thread list (error %d)\n", rc);
  327.         return;
  328.     }
  329.  
  330.     abort_debug = false;
  331.  
  332.     for (i = 0; i < rc; i++) {
  333.         thread_debug_start(thread_hash_buf[i]);
  334.     }
  335.  
  336.     while (!quit) {
  337.         cons_read_line(in_buf, IN_BUF_SIZE);
  338.         command_split(in_buf);
  339.         if (cmd_argc == 0) continue;
  340.  
  341.         command_run();
  342.     }
  343.  
  344.     cons_printf("terminate debugging session...\n");
  345.     abort_debug = true;
  346.     udebug_end(app_phone);
  347.     ipc_hangup(app_phone);
  348.  
  349.     cons_printf("done\n");
  350.     return;
  351. }
  352.  
  353. static void main_init(void)
  354. {
  355.     next_thread_id = 1;
  356.     paused = 0;
  357.  
  358.     fcv_init(&go_cv);
  359. }
  360.  
  361. int main(void)
  362. {
  363.     main_init();
  364.  
  365.     while (1) {
  366.         debug_active_task();
  367.     }
  368. }
  369.  
  370. /** @}
  371.  */
  372.