00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <async.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040 #include <udebug.h>
00041 #include <task.h>
00042 #include <as.h>
00043 #include <sys/types.h>
00044 #include <sys/typefmt.h>
00045 #include <libarch/istate.h>
00046 #include <macros.h>
00047 #include <assert.h>
00048 #include <bool.h>
00049
00050 #include <symtab.h>
00051 #include <elf_core.h>
00052 #include <stacktrace.h>
00053
00054 #define LINE_BYTES 16
00055
00056 static int phoneid;
00057 static task_id_t task_id;
00058 static bool write_core_file;
00059 static char *core_file_name;
00060 static char *app_name;
00061 static symtab_t *app_symtab;
00062
00063 static int connect_task(task_id_t task_id);
00064 static int parse_args(int argc, char *argv[]);
00065 static void print_syntax(void);
00066 static int threads_dump(void);
00067 static int thread_dump(uintptr_t thash);
00068 static int areas_dump(void);
00069 static int td_read_uintptr(void *arg, uintptr_t addr, uintptr_t *value);
00070
00071 static void autoload_syms(void);
00072 static char *get_app_task_name(void);
00073 static char *fmt_sym_address(uintptr_t addr);
00074
00075 int main(int argc, char *argv[])
00076 {
00077 int rc;
00078
00079 printf("Task Dump Utility\n");
00080 write_core_file = false;
00081
00082 if (parse_args(argc, argv) < 0)
00083 return 1;
00084
00085 rc = connect_task(task_id);
00086 if (rc < 0) {
00087 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
00088 return 1;
00089 }
00090
00091 app_name = get_app_task_name();
00092 app_symtab = NULL;
00093
00094 printf("Dumping task '%s' (task ID %" PRIu64 ").\n", app_name, task_id);
00095 autoload_syms();
00096 putchar('\n');
00097
00098 rc = threads_dump();
00099 if (rc < 0)
00100 printf("Failed dumping threads.\n");
00101
00102 rc = areas_dump();
00103 if (rc < 0)
00104 printf("Failed dumping address space areas.\n");
00105
00106 udebug_end(phoneid);
00107 async_hangup(phoneid);
00108
00109 return 0;
00110 }
00111
00112 static int connect_task(task_id_t task_id)
00113 {
00114 int rc;
00115
00116 rc = async_connect_kbox(task_id);
00117
00118 if (rc == ENOTSUP) {
00119 printf("You do not have userspace debugging support "
00120 "compiled in the kernel.\n");
00121 printf("Compile kernel with 'Support for userspace debuggers' "
00122 "(CONFIG_UDEBUG) enabled.\n");
00123 return rc;
00124 }
00125
00126 if (rc < 0) {
00127 printf("Error connecting\n");
00128 printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, rc);
00129 return rc;
00130 }
00131
00132 phoneid = rc;
00133
00134 rc = udebug_begin(phoneid);
00135 if (rc < 0) {
00136 printf("udebug_begin() -> %d\n", rc);
00137 return rc;
00138 }
00139
00140 return 0;
00141 }
00142
00143 static int parse_args(int argc, char *argv[])
00144 {
00145 char *arg;
00146 char *err_p;
00147
00148 task_id = 0;
00149
00150 --argc; ++argv;
00151
00152 while (argc > 0) {
00153 arg = *argv;
00154 if (arg[0] == '-') {
00155 if (arg[1] == 't' && arg[2] == '\0') {
00156
00157 --argc; ++argv;
00158 task_id = strtol(*argv, &err_p, 10);
00159 if (*err_p) {
00160 printf("Task ID syntax error\n");
00161 print_syntax();
00162 return -1;
00163 }
00164 } else if (arg[1] == 'c' && arg[2] == '\0') {
00165 write_core_file = true;
00166
00167 --argc; ++argv;
00168 core_file_name = *argv;
00169 } else {
00170 printf("Uknown option '%c'\n", arg[0]);
00171 print_syntax();
00172 return -1;
00173 }
00174 } else {
00175 break;
00176 }
00177
00178 --argc; ++argv;
00179 }
00180
00181 if (task_id == 0) {
00182 printf("Missing task ID argument\n");
00183 print_syntax();
00184 return -1;
00185 }
00186
00187 if (argc != 0) {
00188 printf("Extra arguments\n");
00189 print_syntax();
00190 return -1;
00191 }
00192
00193 return 0;
00194 }
00195
00196 static void print_syntax(void)
00197 {
00198 printf("Syntax: taskdump [-c <core_file>] -t <task_id>\n");
00199 printf("\t-c <core_file_id>\tName of core file to write.\n");
00200 printf("\t-t <task_id>\tWhich task to dump.\n");
00201 }
00202
00203 static int threads_dump(void)
00204 {
00205 uintptr_t *thash_buf;
00206 uintptr_t dummy_buf;
00207 size_t buf_size, n_threads;
00208
00209 size_t copied;
00210 size_t needed;
00211 size_t i;
00212 int rc;
00213
00214
00215 rc = udebug_thread_read(phoneid, &dummy_buf, 0, &copied, &needed);
00216 if (rc < 0) {
00217 printf("udebug_thread_read() -> %d\n", rc);
00218 return rc;
00219 }
00220
00221 if (needed == 0) {
00222 printf("No threads.\n\n");
00223 return 0;
00224 }
00225
00226 buf_size = needed;
00227 thash_buf = malloc(buf_size);
00228
00229 rc = udebug_thread_read(phoneid, thash_buf, buf_size, &copied, &needed);
00230 if (rc < 0) {
00231 printf("udebug_thread_read() -> %d\n", rc);
00232 return rc;
00233 }
00234
00235 assert(copied == buf_size);
00236 assert(needed == buf_size);
00237
00238 n_threads = copied / sizeof(uintptr_t);
00239
00240 printf("Threads:\n");
00241 for (i = 0; i < n_threads; i++) {
00242 printf(" [%zu] hash: %p\n", 1 + i, (void *) thash_buf[i]);
00243
00244 thread_dump(thash_buf[i]);
00245 }
00246 putchar('\n');
00247
00248 free(thash_buf);
00249
00250 return 0;
00251 }
00252
00253 static int areas_dump(void)
00254 {
00255 as_area_info_t *ainfo_buf;
00256 as_area_info_t dummy_buf;
00257 size_t buf_size, n_areas;
00258
00259 size_t copied;
00260 size_t needed;
00261 size_t i;
00262 int rc;
00263
00264 rc = udebug_areas_read(phoneid, &dummy_buf, 0, &copied, &needed);
00265 if (rc < 0) {
00266 printf("udebug_areas_read() -> %d\n", rc);
00267 return rc;
00268 }
00269
00270 buf_size = needed;
00271 ainfo_buf = malloc(buf_size);
00272
00273 rc = udebug_areas_read(phoneid, ainfo_buf, buf_size, &copied, &needed);
00274 if (rc < 0) {
00275 printf("udebug_areas_read() -> %d\n", rc);
00276 return rc;
00277 }
00278
00279 assert(copied == buf_size);
00280 assert(needed == buf_size);
00281
00282 n_areas = copied / sizeof(as_area_info_t);
00283
00284 printf("Address space areas:\n");
00285 for (i = 0; i < n_areas; i++) {
00286 printf(" [%zu] flags: %c%c%c%c base: %p size: %zu\n", 1 + i,
00287 (ainfo_buf[i].flags & AS_AREA_READ) ? 'R' : '-',
00288 (ainfo_buf[i].flags & AS_AREA_WRITE) ? 'W' : '-',
00289 (ainfo_buf[i].flags & AS_AREA_EXEC) ? 'X' : '-',
00290 (ainfo_buf[i].flags & AS_AREA_CACHEABLE) ? 'C' : '-',
00291 (void *) ainfo_buf[i].start_addr, ainfo_buf[i].size);
00292 }
00293
00294 putchar('\n');
00295
00296 if (write_core_file) {
00297 printf("Writing core file '%s'\n", core_file_name);
00298 rc = elf_core_save(core_file_name, ainfo_buf, n_areas, phoneid);
00299 if (rc != EOK) {
00300 printf("Failed writing core file.\n");
00301 return EIO;
00302 }
00303 }
00304
00305 free(ainfo_buf);
00306
00307 return 0;
00308 }
00309
00310 static int thread_dump(uintptr_t thash)
00311 {
00312 istate_t istate;
00313 uintptr_t pc, fp, nfp;
00314 stacktrace_t st;
00315 char *sym_pc;
00316 int rc;
00317
00318 rc = udebug_regs_read(phoneid, thash, &istate);
00319 if (rc < 0) {
00320 printf("Failed reading registers (%d).\n", rc);
00321 return EIO;
00322 }
00323
00324 pc = istate_get_pc(&istate);
00325 fp = istate_get_fp(&istate);
00326
00327 sym_pc = fmt_sym_address(pc);
00328 printf("Thread %p: PC = %s. FP = %p\n", (void *) thash,
00329 sym_pc, (void *) fp);
00330 free(sym_pc);
00331
00332 st.op_arg = NULL;
00333 st.read_uintptr = td_read_uintptr;
00334
00335 while (stacktrace_fp_valid(&st, fp)) {
00336 sym_pc = fmt_sym_address(pc);
00337 printf(" %p: %s\n", (void *) fp, sym_pc);
00338 free(sym_pc);
00339
00340 rc = stacktrace_ra_get(&st, fp, &pc);
00341 if (rc != EOK)
00342 return rc;
00343
00344 rc = stacktrace_fp_prev(&st, fp, &nfp);
00345 if (rc != EOK)
00346 return rc;
00347
00348 fp = nfp;
00349 }
00350
00351 return EOK;
00352 }
00353
00354 static int td_read_uintptr(void *arg, uintptr_t addr, uintptr_t *value)
00355 {
00356 uintptr_t data;
00357 int rc;
00358
00359 (void) arg;
00360
00361 rc = udebug_mem_read(phoneid, &data, addr, sizeof(data));
00362 if (rc < 0) {
00363 printf("Warning: udebug_mem_read() failed.\n");
00364 return rc;
00365 }
00366
00367 *value = data;
00368 return EOK;
00369 }
00370
00372 static void autoload_syms(void)
00373 {
00374 char *file_name;
00375 int rc;
00376
00377 assert(app_name != NULL);
00378 assert(app_symtab == NULL);
00379
00380 rc = asprintf(&file_name, "/app/%s", app_name);
00381 if (rc < 0) {
00382 printf("Memory allocation failure.\n");
00383 exit(1);
00384 }
00385
00386 rc = symtab_load(file_name, &app_symtab);
00387 if (rc == EOK) {
00388 printf("Loaded symbol table from %s\n", file_name);
00389 free(file_name);
00390 return;
00391 }
00392
00393 free(file_name);
00394
00395 rc = asprintf(&file_name, "/srv/%s", app_name);
00396 if (rc < 0) {
00397 printf("Memory allocation failure.\n");
00398 exit(1);
00399 }
00400
00401 rc = symtab_load(file_name, &app_symtab);
00402 if (rc == EOK) {
00403 printf("Loaded symbol table from %s\n", file_name);
00404 free(file_name);
00405 return;
00406 }
00407
00408 rc = asprintf(&file_name, "/drv/%s/%s", app_name, app_name);
00409 if (rc < 0) {
00410 printf("Memory allocation failure.\n");
00411 exit(1);
00412 }
00413
00414 rc = symtab_load(file_name, &app_symtab);
00415 if (rc == EOK) {
00416 printf("Loaded symbol table from %s\n", file_name);
00417 free(file_name);
00418 return;
00419 }
00420
00421 free(file_name);
00422 printf("Failed autoloading symbol table.\n");
00423 }
00424
00425 static char *get_app_task_name(void)
00426 {
00427 char dummy_buf;
00428 size_t copied, needed, name_size;
00429 char *name;
00430 int rc;
00431
00432 rc = udebug_name_read(phoneid, &dummy_buf, 0, &copied, &needed);
00433 if (rc < 0)
00434 return NULL;
00435
00436 name_size = needed;
00437 name = malloc(name_size + 1);
00438 rc = udebug_name_read(phoneid, name, name_size, &copied, &needed);
00439 if (rc < 0) {
00440 free(name);
00441 return NULL;
00442 }
00443
00444 assert(copied == name_size);
00445 assert(copied == needed);
00446 name[copied] = '\0';
00447
00448 return name;
00449 }
00450
00459 static char *fmt_sym_address(uintptr_t addr)
00460 {
00461 char *name;
00462 size_t offs;
00463 int rc;
00464 char *str;
00465
00466 if (app_symtab != NULL) {
00467 rc = symtab_addr_to_name(app_symtab, addr, &name, &offs);
00468 } else {
00469 rc = ENOTSUP;
00470 }
00471
00472 if (rc == EOK) {
00473 rc = asprintf(&str, "%p (%s+%zu)", (void *) addr, name, offs);
00474 } else {
00475 rc = asprintf(&str, "%p", (void *) addr);
00476 }
00477
00478 if (rc < 0) {
00479 printf("Memory allocation error.\n");
00480 exit(1);
00481 }
00482
00483 return str;
00484 }
00485