source: mainline/uspace/app/taskdump/taskdump.c@ 4d4988e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4d4988e was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2010 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 taskdump
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <errno.h>
40#include <udebug.h>
41#include <task.h>
42#include <as.h>
43#include <sys/types.h>
44#include <sys/typefmt.h>
45#include <libarch/istate.h>
46#include <macros.h>
47#include <assert.h>
48#include <bool.h>
49
50#include <symtab.h>
51#include <elf_core.h>
52#include <stacktrace.h>
53
54#define LINE_BYTES 16
55
56static async_sess_t *sess;
57static task_id_t task_id;
58static bool write_core_file;
59static char *core_file_name;
60static char *app_name;
61static symtab_t *app_symtab;
62
63static int connect_task(task_id_t task_id);
64static int parse_args(int argc, char *argv[]);
65static void print_syntax(void);
66static int threads_dump(void);
67static int thread_dump(uintptr_t thash);
68static int areas_dump(void);
69static int td_read_uintptr(void *arg, uintptr_t addr, uintptr_t *value);
70
71static void autoload_syms(void);
72static char *get_app_task_name(void);
73static char *fmt_sym_address(uintptr_t addr);
74
75int main(int argc, char *argv[])
76{
77 int rc;
78
79 printf("Task Dump Utility\n");
80 write_core_file = false;
81
82 if (parse_args(argc, argv) < 0)
83 return 1;
84
85 rc = connect_task(task_id);
86 if (rc < 0) {
87 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
88 return 1;
89 }
90
91 app_name = get_app_task_name();
92 app_symtab = NULL;
93
94 printf("Dumping task '%s' (task ID %" PRIu64 ").\n", app_name, task_id);
95 autoload_syms();
96 putchar('\n');
97
98 rc = threads_dump();
99 if (rc < 0)
100 printf("Failed dumping threads.\n");
101
102 rc = areas_dump();
103 if (rc < 0)
104 printf("Failed dumping address space areas.\n");
105
106 udebug_end(sess);
107 async_hangup(sess);
108
109 return 0;
110}
111
112static int connect_task(task_id_t task_id)
113{
114 async_sess_t *ksess = async_connect_kbox(task_id);
115
116 if (!ksess) {
117 if (errno == ENOTSUP) {
118 printf("You do not have userspace debugging support "
119 "compiled in the kernel.\n");
120 printf("Compile kernel with 'Support for userspace debuggers' "
121 "(CONFIG_UDEBUG) enabled.\n");
122 return errno;
123 }
124
125 printf("Error connecting\n");
126 printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, errno);
127 return errno;
128 }
129
130 int rc = udebug_begin(ksess);
131 if (rc < 0) {
132 printf("udebug_begin() -> %d\n", rc);
133 return rc;
134 }
135
136 sess = ksess;
137 return 0;
138}
139
140static int parse_args(int argc, char *argv[])
141{
142 char *arg;
143 char *err_p;
144
145 task_id = 0;
146
147 --argc; ++argv;
148
149 while (argc > 0) {
150 arg = *argv;
151 if (arg[0] == '-') {
152 if (arg[1] == 't' && arg[2] == '\0') {
153 /* Task ID */
154 --argc; ++argv;
155 task_id = strtol(*argv, &err_p, 10);
156 if (*err_p) {
157 printf("Task ID syntax error\n");
158 print_syntax();
159 return -1;
160 }
161 } else if (arg[1] == 'c' && arg[2] == '\0') {
162 write_core_file = true;
163
164 --argc; ++argv;
165 core_file_name = *argv;
166 } else {
167 printf("Uknown option '%c'\n", arg[0]);
168 print_syntax();
169 return -1;
170 }
171 } else {
172 break;
173 }
174
175 --argc; ++argv;
176 }
177
178 if (task_id == 0) {
179 printf("Missing task ID argument\n");
180 print_syntax();
181 return -1;
182 }
183
184 if (argc != 0) {
185 printf("Extra arguments\n");
186 print_syntax();
187 return -1;
188 }
189
190 return 0;
191}
192
193static void print_syntax(void)
194{
195 printf("Syntax: taskdump [-c <core_file>] -t <task_id>\n");
196 printf("\t-c <core_file_id>\tName of core file to write.\n");
197 printf("\t-t <task_id>\tWhich task to dump.\n");
198}
199
200static int threads_dump(void)
201{
202 uintptr_t *thash_buf;
203 uintptr_t dummy_buf;
204 size_t buf_size, n_threads;
205
206 size_t copied;
207 size_t needed;
208 size_t i;
209 int rc;
210
211 /* TODO: See why NULL does not work. */
212 rc = udebug_thread_read(sess, &dummy_buf, 0, &copied, &needed);
213 if (rc < 0) {
214 printf("udebug_thread_read() -> %d\n", rc);
215 return rc;
216 }
217
218 if (needed == 0) {
219 printf("No threads.\n\n");
220 return 0;
221 }
222
223 buf_size = needed;
224 thash_buf = malloc(buf_size);
225
226 rc = udebug_thread_read(sess, thash_buf, buf_size, &copied, &needed);
227 if (rc < 0) {
228 printf("udebug_thread_read() -> %d\n", rc);
229 return rc;
230 }
231
232 assert(copied == buf_size);
233 assert(needed == buf_size);
234
235 n_threads = copied / sizeof(uintptr_t);
236
237 printf("Threads:\n");
238 for (i = 0; i < n_threads; i++) {
239 printf(" [%zu] hash: %p\n", 1 + i, (void *) thash_buf[i]);
240
241 thread_dump(thash_buf[i]);
242 }
243 putchar('\n');
244
245 free(thash_buf);
246
247 return 0;
248}
249
250static int areas_dump(void)
251{
252 as_area_info_t *ainfo_buf;
253 as_area_info_t dummy_buf;
254 size_t buf_size, n_areas;
255
256 size_t copied;
257 size_t needed;
258 size_t i;
259 int rc;
260
261 rc = udebug_areas_read(sess, &dummy_buf, 0, &copied, &needed);
262 if (rc < 0) {
263 printf("udebug_areas_read() -> %d\n", rc);
264 return rc;
265 }
266
267 buf_size = needed;
268 ainfo_buf = malloc(buf_size);
269
270 rc = udebug_areas_read(sess, ainfo_buf, buf_size, &copied, &needed);
271 if (rc < 0) {
272 printf("udebug_areas_read() -> %d\n", rc);
273 return rc;
274 }
275
276 assert(copied == buf_size);
277 assert(needed == buf_size);
278
279 n_areas = copied / sizeof(as_area_info_t);
280
281 printf("Address space areas:\n");
282 for (i = 0; i < n_areas; i++) {
283 printf(" [%zu] flags: %c%c%c%c base: %p size: %zu\n", 1 + i,
284 (ainfo_buf[i].flags & AS_AREA_READ) ? 'R' : '-',
285 (ainfo_buf[i].flags & AS_AREA_WRITE) ? 'W' : '-',
286 (ainfo_buf[i].flags & AS_AREA_EXEC) ? 'X' : '-',
287 (ainfo_buf[i].flags & AS_AREA_CACHEABLE) ? 'C' : '-',
288 (void *) ainfo_buf[i].start_addr, ainfo_buf[i].size);
289 }
290
291 putchar('\n');
292
293 if (write_core_file) {
294 printf("Writing core file '%s'\n", core_file_name);
295 rc = elf_core_save(core_file_name, ainfo_buf, n_areas, sess);
296 if (rc != EOK) {
297 printf("Failed writing core file.\n");
298 return EIO;
299 }
300 }
301
302 free(ainfo_buf);
303
304 return 0;
305}
306
307static int thread_dump(uintptr_t thash)
308{
309 istate_t istate;
310 uintptr_t pc, fp, nfp;
311 stacktrace_t st;
312 char *sym_pc;
313 int rc;
314
315 rc = udebug_regs_read(sess, thash, &istate);
316 if (rc < 0) {
317 printf("Failed reading registers (%d).\n", rc);
318 return EIO;
319 }
320
321 pc = istate_get_pc(&istate);
322 fp = istate_get_fp(&istate);
323
324 sym_pc = fmt_sym_address(pc);
325 printf("Thread %p: PC = %s. FP = %p\n", (void *) thash,
326 sym_pc, (void *) fp);
327 free(sym_pc);
328
329 st.op_arg = NULL;
330 st.read_uintptr = td_read_uintptr;
331
332 while (stacktrace_fp_valid(&st, fp)) {
333 sym_pc = fmt_sym_address(pc);
334 printf(" %p: %s\n", (void *) fp, sym_pc);
335 free(sym_pc);
336
337 rc = stacktrace_ra_get(&st, fp, &pc);
338 if (rc != EOK)
339 return rc;
340
341 rc = stacktrace_fp_prev(&st, fp, &nfp);
342 if (rc != EOK)
343 return rc;
344
345 fp = nfp;
346 }
347
348 return EOK;
349}
350
351static int td_read_uintptr(void *arg, uintptr_t addr, uintptr_t *value)
352{
353 uintptr_t data;
354 int rc;
355
356 (void) arg;
357
358 rc = udebug_mem_read(sess, &data, addr, sizeof(data));
359 if (rc < 0) {
360 printf("Warning: udebug_mem_read() failed.\n");
361 return rc;
362 }
363
364 *value = data;
365 return EOK;
366}
367
368/** Attempt to find the right executable file and load the symbol table. */
369static void autoload_syms(void)
370{
371 char *file_name;
372 int rc;
373
374 assert(app_name != NULL);
375 assert(app_symtab == NULL);
376
377 rc = asprintf(&file_name, "/app/%s", app_name);
378 if (rc < 0) {
379 printf("Memory allocation failure.\n");
380 exit(1);
381 }
382
383 rc = symtab_load(file_name, &app_symtab);
384 if (rc == EOK) {
385 printf("Loaded symbol table from %s\n", file_name);
386 free(file_name);
387 return;
388 }
389
390 free(file_name);
391
392 rc = asprintf(&file_name, "/srv/%s", app_name);
393 if (rc < 0) {
394 printf("Memory allocation failure.\n");
395 exit(1);
396 }
397
398 rc = symtab_load(file_name, &app_symtab);
399 if (rc == EOK) {
400 printf("Loaded symbol table from %s\n", file_name);
401 free(file_name);
402 return;
403 }
404
405 rc = asprintf(&file_name, "/drv/%s/%s", app_name, app_name);
406 if (rc < 0) {
407 printf("Memory allocation failure.\n");
408 exit(1);
409 }
410
411 rc = symtab_load(file_name, &app_symtab);
412 if (rc == EOK) {
413 printf("Loaded symbol table from %s\n", file_name);
414 free(file_name);
415 return;
416 }
417
418 free(file_name);
419 printf("Failed autoloading symbol table.\n");
420}
421
422static char *get_app_task_name(void)
423{
424 char dummy_buf;
425 size_t copied, needed, name_size;
426 char *name;
427 int rc;
428
429 rc = udebug_name_read(sess, &dummy_buf, 0, &copied, &needed);
430 if (rc < 0)
431 return NULL;
432
433 name_size = needed;
434 name = malloc(name_size + 1);
435 rc = udebug_name_read(sess, name, name_size, &copied, &needed);
436 if (rc < 0) {
437 free(name);
438 return NULL;
439 }
440
441 assert(copied == name_size);
442 assert(copied == needed);
443 name[copied] = '\0';
444
445 return name;
446}
447
448/** Format address in symbolic form.
449 *
450 * Formats address as <symbol_name>+<offset> (<address>), if possible,
451 * otherwise as <address>.
452 *
453 * @param addr Address to format.
454 * @return Newly allocated string, address in symbolic form.
455 */
456static char *fmt_sym_address(uintptr_t addr)
457{
458 char *name;
459 size_t offs;
460 int rc;
461 char *str;
462
463 if (app_symtab != NULL) {
464 rc = symtab_addr_to_name(app_symtab, addr, &name, &offs);
465 } else {
466 rc = ENOTSUP;
467 }
468
469 if (rc == EOK) {
470 rc = asprintf(&str, "%p (%s+%zu)", (void *) addr, name, offs);
471 } else {
472 rc = asprintf(&str, "%p", (void *) addr);
473 }
474
475 if (rc < 0) {
476 printf("Memory allocation error.\n");
477 exit(1);
478 }
479
480 return str;
481}
482
483/** @}
484 */
Note: See TracBrowser for help on using the repository browser.