/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include #include #include "host_task.h" #include "host_test.h" #include "timer.h" #define SIGNAL_TRACE_DUMP SIGTERM #define MAX_TRACE 30 /* * When trace dump is requested from signal handler, skip: * _task_dump_trace_impl * _task_dump_trace_dispath * A function in libc */ #define SIGNAL_TRACE_OFFSET 3 /* * When trace dump is requested from task_dump_trace(), skip: * task_dump_trace * _task_dump_trace_impl */ #define DIRECT_TRACE_OFFSET 2 static pthread_t main_thread; static void __attribute__((noinline)) _task_dump_trace_impl(int offset) { void *trace[MAX_TRACE]; size_t sz; char **messages; char buf[256]; FILE *file; int i, nb; sz = backtrace(trace, MAX_TRACE); messages = backtrace_symbols(trace + offset, sz - offset); for (i = 0; i < sz - offset; ++i) { fprintf(stderr, "#%-2d %s\n", i, messages[i]); sprintf(buf, "addr2line %p -e %s", trace[i + offset], __get_prog_name()); file = popen(buf, "r"); if (file) { nb = fread(buf, 1, sizeof(buf) - 1, file); buf[nb] = '\0'; fprintf(stderr, " %s", buf); pclose(file); } } fflush(stderr); free(messages); } void __attribute__((noinline)) task_dump_trace(void) { _task_dump_trace_impl(DIRECT_TRACE_OFFSET); } static void __attribute__((noinline)) _task_dump_trace_dispatch(int sig) { int need_dispatch = 1; task_id_t running = task_get_running(); if (!pthread_equal(pthread_self(), main_thread)) { need_dispatch = 0; } else if (!task_start_called()) { fprintf(stderr, "Stack trace of main thread:\n"); need_dispatch = 0; } else if (in_interrupt_context()) { fprintf(stderr, "Stack trace of ISR:\n"); } else { fprintf(stderr, "Stack trace of task %d (%s):\n", running, task_get_name(running)); } if (need_dispatch) { pthread_kill(task_get_thread(running), SIGNAL_TRACE_DUMP); } else { _task_dump_trace_impl(SIGNAL_TRACE_OFFSET); exit(1); } } void task_register_tracedump(void) { /* Trace dumper MUST be registered from main thread */ main_thread = pthread_self(); signal(SIGNAL_TRACE_DUMP, _task_dump_trace_dispatch); }