diff options
Diffstat (limited to 'pstack/pstack.c')
-rw-r--r-- | pstack/pstack.c | 2746 |
1 files changed, 0 insertions, 2746 deletions
diff --git a/pstack/pstack.c b/pstack/pstack.c deleted file mode 100644 index 4cdd80d68b5..00000000000 --- a/pstack/pstack.c +++ /dev/null @@ -1,2746 +0,0 @@ -/* - pstack.c -- asynchronous stack trace of a running process - Copyright (c) 1999 Ross Thompson - Author: Ross Thompson <ross@whatsis.com> - Critical bug fix: Tim Waugh -*/ - -/* - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* RESTRICTIONS: - - pstack currently works only on Linux, only on an x86 machine running - 32 bit ELF binaries (64 bit not supported). Also, for symbolic - information, you need to use a GNU compiler to generate your - program, and you can't strip symbols from the binaries. For thread - information to be dumped, you have to use the debug-aware version - of libpthread.so. (To check, run 'nm' on your libpthread.so, and - make sure that the symbol "__pthread_threads_debug" is defined.) - - The details of pulling stuff out of ELF files and running through - program images is very platform specific, and I don't want to - try to support modes or machine types I can't test in or on. - If someone wants to generalize this to other architectures, I would - be happy to help and coordinate the activity. Please send me whatever - changes you make to support these machines, so that I can own the - central font of all truth (at least as regards this program). - - Thanks -*/ - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <sys/ptrace.h> -#include <asm/ptrace.h> - -#include <assert.h> -#include <fcntl.h> -#include <link.h> -#include <malloc.h> -#include <string.h> -#include <stdarg.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <signal.h> -#include <pthread.h> -#include <limits.h> /* PTHREAD_THREADS_MAX */ - - -#include <bfd.h> - -#include "libiberty.h" - -#include "pstack.h" /* just one function */ -#include "budbg.h" /* binutils stuff related to debugging symbols. */ -#include "bucomm.h" /* some common stuff */ -#include "debug.h" /* and more binutils stuff... */ -#include "budbg.h" -#include "linuxthreads.h" /* LinuxThreads specific stuff... */ - - -/* - * fprintf for file descriptors :) NOTE: we have to use fixed-size buffer :)( - * due to malloc's unavalaibility. - */ -int -fdprintf( int fd, - const char* fmt,...) -{ - char xbuf[2048];// FIXME: enough? - va_list ap; - int r; - if (fd<0) - return -1; - va_start(ap, fmt); - r = vsnprintf(xbuf, sizeof(xbuf), fmt, ap); - va_end(ap); - return write(fd, xbuf, r); -} - -int -fdputc( char c, - int fd) -{ - if (fd<0) - return -1; - return write(fd, &c, sizeof(c)); -} - -int -fdputs( const char* s, - int fd) -{ - if (fd<0) - return -1; - return write(fd, s, strlen(s)); -} - -/* - * Use this function to open log file. - * Flags: truncate on opening. - */ -static const char* path_format = "stack-trace-on-segv-%d.txt"; -static int -open_log_file( const pthread_t tid, - const pid_t pid) -{ - char fname[PATH_MAX]; - int r; - snprintf(fname, sizeof(fname), path_format, tid, pid); - r = open(fname, O_WRONLY|O_CREAT|O_TRUNC, - S_IRUSR|S_IWUSR); - if (r<0) - perror("open"); - return r; -} -/* - * Add additional debugging information for functions. - */ - -/* - * Lineno - */ -typedef struct { - int lineno; - bfd_vma addr; -} debug_lineno_t; - -/* - * Block - a {} pair. - */ -typedef struct debug_block_st { - bfd_vma begin_addr; /* where did it start */ - bfd_vma end_addr; /* where did it end */ - struct debug_block_st* parent; - struct debug_block_st* childs; - int childs_count; -} debug_block_t; - -/* - * Function parameter. - */ -typedef struct { - bfd_vma offset; /* Offset in the stack */ - const char* name; /* And name. */ -} debug_parameter_t; - -/* - * Extra information about functions. - */ -typedef struct { - asymbol* symbol; /* mangled function name, addr */ - debug_lineno_t* lines; - int lines_count; - int max_lines_count; - const char* name; - const char* filename;/* a file name it occured in... */ - debug_block_t* block; /* each function has a block, or not, you know */ - debug_parameter_t* argv; /* argument types. */ - int argc; - int max_argc; -} debug_function_t; - -/* This is the structure we use as a handle for these routines. */ -struct pr_handle -{ - /* File to print information to. */ - FILE *f; - /* Current indentation level. */ - unsigned int indent; - /* Type stack. */ - struct pr_stack *stack; - /* Parameter number we are about to output. */ - int parameter; - debug_block_t* block; /* current block */ - debug_function_t* function; /* current function */ - debug_function_t* functions; /* all functions */ - int functions_size; /* current size */ - int functions_maxsize; /* maximum size */ -}; - -/* The type stack. */ - -struct pr_stack -{ - /* Next element on the stack. */ - struct pr_stack *next; - /* This element. */ - char *type; - /* Current visibility of fields if this is a class. */ - enum debug_visibility visibility; - /* Name of the current method we are handling. */ - const char *method; -}; - -static void indent PARAMS ((struct pr_handle *)); -static boolean push_type PARAMS ((struct pr_handle *, const char *)); -static boolean prepend_type PARAMS ((struct pr_handle *, const char *)); -static boolean append_type PARAMS ((struct pr_handle *, const char *)); -static boolean substitute_type PARAMS ((struct pr_handle *, const char *)); -static boolean indent_type PARAMS ((struct pr_handle *)); -static char *pop_type PARAMS ((struct pr_handle *)); -static void print_vma PARAMS ((bfd_vma, char *, boolean, boolean)); -static boolean pr_fix_visibility - PARAMS ((struct pr_handle *, enum debug_visibility)); - -static boolean pr_start_compilation_unit PARAMS ((PTR, const char *)); -static boolean pr_start_source PARAMS ((PTR, const char *)); -static boolean pr_empty_type PARAMS ((PTR)); -static boolean pr_void_type PARAMS ((PTR)); -static boolean pr_int_type PARAMS ((PTR, unsigned int, boolean)); -static boolean pr_float_type PARAMS ((PTR, unsigned int)); -static boolean pr_complex_type PARAMS ((PTR, unsigned int)); -static boolean pr_bool_type PARAMS ((PTR, unsigned int)); -static boolean pr_enum_type - PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); -static boolean pr_pointer_type PARAMS ((PTR)); -static boolean pr_function_type PARAMS ((PTR, int, boolean)); -static boolean pr_reference_type PARAMS ((PTR)); -static boolean pr_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); -static boolean pr_array_type - PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean)); -static boolean pr_set_type PARAMS ((PTR, boolean)); -static boolean pr_offset_type PARAMS ((PTR)); -static boolean pr_method_type PARAMS ((PTR, boolean, int, boolean)); -static boolean pr_const_type PARAMS ((PTR)); -static boolean pr_volatile_type PARAMS ((PTR)); -static boolean pr_start_struct_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int)); -static boolean pr_struct_field - PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); -static boolean pr_end_struct_type PARAMS ((PTR)); -static boolean pr_start_class_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean, - boolean)); -static boolean pr_class_static_member - PARAMS ((PTR, const char *, const char *, enum debug_visibility)); -static boolean pr_class_baseclass - PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility)); -static boolean pr_class_start_method PARAMS ((PTR, const char *)); -static boolean pr_class_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean, - bfd_vma, boolean)); -static boolean pr_class_static_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean)); -static boolean pr_class_end_method PARAMS ((PTR)); -static boolean pr_end_class_type PARAMS ((PTR)); -static boolean pr_typedef_type PARAMS ((PTR, const char *)); -static boolean pr_tag_type - PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); -static boolean pr_typdef PARAMS ((PTR, const char *)); -static boolean pr_tag PARAMS ((PTR, const char *)); -static boolean pr_int_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean pr_float_constant PARAMS ((PTR, const char *, double)); -static boolean pr_typed_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean pr_variable - PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); -static boolean pr_start_function PARAMS ((PTR, const char *, boolean)); -static boolean pr_function_parameter - PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); -static boolean pr_start_block PARAMS ((PTR, bfd_vma)); -static boolean pr_end_block PARAMS ((PTR, bfd_vma)); -static boolean pr_end_function PARAMS ((PTR)); -static boolean pr_lineno PARAMS ((PTR, const char *, unsigned long, bfd_vma)); - -static const struct debug_write_fns pr_fns = -{ - pr_start_compilation_unit, - pr_start_source, - pr_empty_type, - pr_void_type, - pr_int_type, - pr_float_type, - pr_complex_type, - pr_bool_type, - pr_enum_type, - pr_pointer_type, - pr_function_type, - pr_reference_type, - pr_range_type, - pr_array_type, - pr_set_type, - pr_offset_type, - pr_method_type, - pr_const_type, - pr_volatile_type, - pr_start_struct_type, - pr_struct_field, - pr_end_struct_type, - pr_start_class_type, - pr_class_static_member, - pr_class_baseclass, - pr_class_start_method, - pr_class_method_variant, - pr_class_static_method_variant, - pr_class_end_method, - pr_end_class_type, - pr_typedef_type, - pr_tag_type, - pr_typdef, - pr_tag, - pr_int_constant, - pr_float_constant, - pr_typed_constant, - pr_variable, - pr_start_function, - pr_function_parameter, - pr_start_block, - pr_end_block, - pr_end_function, - pr_lineno -}; - - -/* Indent to the current indentation level. */ - -static void -indent (info) - struct pr_handle *info; -{ - unsigned int i; - - for (i = 0; i < info->indent; i++) - TRACE_PUTC ((' ', info->f)); -} - -/* Push a type on the type stack. */ - -static boolean -push_type (info, type) - struct pr_handle *info; - const char *type; -{ - struct pr_stack *n; - - if (type == NULL) - return false; - - n = (struct pr_stack *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->type = xstrdup (type); - n->visibility = DEBUG_VISIBILITY_IGNORE; - n->method = NULL; - n->next = info->stack; - info->stack = n; - - return true; -} - -/* Prepend a string onto the type on the top of the type stack. */ - -static boolean -prepend_type (info, s) - struct pr_handle *info; - const char *s; -{ - char *n; - - assert (info->stack != NULL); - - n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1); - sprintf (n, "%s%s", s, info->stack->type); - free (info->stack->type); - info->stack->type = n; - - return true; -} - -/* Append a string to the type on the top of the type stack. */ - -static boolean -append_type (info, s) - struct pr_handle *info; - const char *s; -{ - unsigned int len; - - if (s == NULL) - return false; - - assert (info->stack != NULL); - - len = strlen (info->stack->type); - info->stack->type = (char *) xrealloc (info->stack->type, - len + strlen (s) + 1); - strcpy (info->stack->type + len, s); - - return true; -} - -/* We use an underscore to indicate where the name should go in a type - string. This function substitutes a string for the underscore. If - there is no underscore, the name follows the type. */ - -static boolean -substitute_type (info, s) - struct pr_handle *info; - const char *s; -{ - char *u; - - assert (info->stack != NULL); - - u = strchr (info->stack->type, '|'); - if (u != NULL) - { - char *n; - - n = (char *) xmalloc (strlen (info->stack->type) + strlen (s)); - - memcpy (n, info->stack->type, u - info->stack->type); - strcpy (n + (u - info->stack->type), s); - strcat (n, u + 1); - - free (info->stack->type); - info->stack->type = n; - - return true; - } - - if (strchr (s, '|') != NULL - && (strchr (info->stack->type, '{') != NULL - || strchr (info->stack->type, '(') != NULL)) - { - if (! prepend_type (info, "(") - || ! append_type (info, ")")) - return false; - } - - if (*s == '\0') - return true; - - return (append_type (info, " ") - && append_type (info, s)); -} - -/* Indent the type at the top of the stack by appending spaces. */ - -static boolean -indent_type (info) - struct pr_handle *info; -{ - unsigned int i; - - for (i = 0; i < info->indent; i++) - { - if (! append_type (info, " ")) - return false; - } - - return true; -} - -/* Pop a type from the type stack. */ - -static char * -pop_type (info) - struct pr_handle *info; -{ - struct pr_stack *o; - char *ret; - - assert (info->stack != NULL); - - o = info->stack; - info->stack = o->next; - ret = o->type; - free (o); - - return ret; -} - -/* Print a VMA value into a string. */ - -static void -print_vma (vma, buf, unsignedp, hexp) - bfd_vma vma; - char *buf; - boolean unsignedp; - boolean hexp; -{ - if (sizeof (vma) <= sizeof (unsigned long)) - { - if (hexp) - sprintf (buf, "0x%lx", (unsigned long) vma); - else if (unsignedp) - sprintf (buf, "%lu", (unsigned long) vma); - else - sprintf (buf, "%ld", (long) vma); - } - else - { - buf[0] = '0'; - buf[1] = 'x'; - sprintf_vma (buf + 2, vma); - } -} - -/* Start a new compilation unit. */ - -static boolean -pr_start_compilation_unit (p, filename) - PTR p; - const char *filename; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->indent == 0); -/* - TRACE_FPRINTF( (info->f, "%s:\n", filename)); -*/ - return true; -} - -/* Start a source file within a compilation unit. */ - -static boolean -pr_start_source (p, filename) - PTR p; - const char *filename; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->indent == 0); -/* - TRACE_FPRINTF( (info->f, " %s:\n", filename)); -*/ - return true; -} - -/* Push an empty type onto the type stack. */ - -static boolean -pr_empty_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, "<undefined>"); -} - -/* Push a void type onto the type stack. */ - -static boolean -pr_void_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, "void"); -} - -/* Push an integer type onto the type stack. */ - -static boolean -pr_int_type (p, size, unsignedp) - PTR p; - unsigned int size; - boolean unsignedp; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8); - return push_type (info, ab); -} - -/* Push a floating type onto the type stack. */ - -static boolean -pr_float_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - if (size == 4) - return push_type (info, "float"); - else if (size == 8) - return push_type (info, "double"); - - sprintf (ab, "float%d", size * 8); - return push_type (info, ab); -} - -/* Push a complex type onto the type stack. */ - -static boolean -pr_complex_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - - if (! pr_float_type (p, size)) - return false; - - return prepend_type (info, "complex "); -} - -/* Push a boolean type onto the type stack. */ - -static boolean -pr_bool_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - sprintf (ab, "bool%d", size * 8); - - return push_type (info, ab); -} - -/* Push an enum type onto the type stack. */ - -static boolean -pr_enum_type (p, tag, names, values) - PTR p; - const char *tag; - const char **names; - bfd_signed_vma *values; -{ - struct pr_handle *info = (struct pr_handle *) p; - unsigned int i; - bfd_signed_vma val; - - if (! push_type (info, "enum ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag) - || ! append_type (info, " ")) - return false; - } - if (! append_type (info, "{ ")) - return false; - - if (names == NULL) - { - if (! append_type (info, "/* undefined */")) - return false; - } - else - { - val = 0; - for (i = 0; names[i] != NULL; i++) - { - if (i > 0) - { - if (! append_type (info, ", ")) - return false; - } - - if (! append_type (info, names[i])) - return false; - - if (values[i] != val) - { - char ab[20]; - - print_vma (values[i], ab, false, false); - if (! append_type (info, " = ") - || ! append_type (info, ab)) - return false; - val = values[i]; - } - - ++val; - } - } - - return append_type (info, " }"); -} - -/* Turn the top type on the stack into a pointer. */ - -static boolean -pr_pointer_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - assert (info->stack != NULL); - - s = strchr (info->stack->type, '|'); - if (s != NULL && s[1] == '[') - return substitute_type (info, "(*|)"); - return substitute_type (info, "*|"); -} - -/* Turn the top type on the stack into a function returning that type. */ - -static boolean -pr_function_type (p, argcount, varargs) - PTR p; - int argcount; - boolean varargs; -{ - struct pr_handle *info = (struct pr_handle *) p; - char **arg_types; - unsigned int len; - char *s; - - assert (info->stack != NULL); - - len = 10; - - if (argcount <= 0) - { - arg_types = NULL; - len += 15; - } - else - { - int i; - - arg_types = (char **) xmalloc (argcount * sizeof *arg_types); - for (i = argcount - 1; i >= 0; i--) - { - if (! substitute_type (info, "")) - return false; - arg_types[i] = pop_type (info); - if (arg_types[i] == NULL) - return false; - len += strlen (arg_types[i]) + 2; - } - if (varargs) - len += 5; - } - - /* Now the return type is on the top of the stack. */ - - s = (char *) xmalloc (len); - strcpy (s, "(|) ("); - - if (argcount < 0) - { -#if 0 - /* Turn off unknown arguments. */ - strcat (s, "/* unknown */"); -#endif - } - else - { - int i; - - for (i = 0; i < argcount; i++) - { - if (i > 0) - strcat (s, ", "); - strcat (s, arg_types[i]); - } - if (varargs) - { - if (i > 0) - strcat (s, ", "); - strcat (s, "..."); - } - if (argcount > 0) - free (arg_types); - } - - strcat (s, ")"); - - if (! substitute_type (info, s)) - return false; - - free (s); - - return true; -} - -/* Turn the top type on the stack into a reference to that type. */ - -static boolean -pr_reference_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->stack != NULL); - - return substitute_type (info, "&|"); -} - -/* Make a range type. */ - -static boolean -pr_range_type (p, lower, upper) - PTR p; - bfd_signed_vma lower; - bfd_signed_vma upper; -{ - struct pr_handle *info = (struct pr_handle *) p; - char abl[20], abu[20]; - - assert (info->stack != NULL); - - if (! substitute_type (info, "")) - return false; - - print_vma (lower, abl, false, false); - print_vma (upper, abu, false, false); - - return (prepend_type (info, "range (") - && append_type (info, "):") - && append_type (info, abl) - && append_type (info, ":") - && append_type (info, abu)); -} - -/* Make an array type. */ - -/*ARGSUSED*/ -static boolean -pr_array_type (p, lower, upper, stringp) - PTR p; - bfd_signed_vma lower; - bfd_signed_vma upper; - boolean stringp; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *range_type; - char abl[20], abu[20], ab[50]; - - range_type = pop_type (info); - if (range_type == NULL) - return false; - - if (lower == 0) - { - if (upper == -1) - sprintf (ab, "|[]"); - else - { - print_vma (upper + 1, abu, false, false); - sprintf (ab, "|[%s]", abu); - } - } - else - { - print_vma (lower, abl, false, false); - print_vma (upper, abu, false, false); - sprintf (ab, "|[%s:%s]", abl, abu); - } - - if (! substitute_type (info, ab)) - return false; - - if (strcmp (range_type, "int") != 0) - { - if (! append_type (info, ":") - || ! append_type (info, range_type)) - return false; - } - - if (stringp) - { - if (! append_type (info, " /* string */")) - return false; - } - - return true; -} - -/* Make a set type. */ - -/*ARGSUSED*/ -static boolean -pr_set_type (p, bitstringp) - PTR p; - boolean bitstringp; -{ - struct pr_handle *info = (struct pr_handle *) p; - - if (! substitute_type (info, "")) - return false; - - if (! prepend_type (info, "set { ") - || ! append_type (info, " }")) - return false; - - if (bitstringp) - { - if (! append_type (info, "/* bitstring */")) - return false; - } - - return true; -} - -/* Make an offset type. */ - -static boolean -pr_offset_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, "")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - return (substitute_type (info, "") - && prepend_type (info, " ") - && prepend_type (info, t) - && append_type (info, "::|")); -} - -/* Make a method type. */ - -static boolean -pr_method_type (p, domain, argcount, varargs) - PTR p; - boolean domain; - int argcount; - boolean varargs; -{ - struct pr_handle *info = (struct pr_handle *) p; - unsigned int len; - char *domain_type; - char **arg_types; - char *s; - - len = 10; - - if (! domain) - domain_type = NULL; - else - { - if (! substitute_type (info, "")) - return false; - domain_type = pop_type (info); - if (domain_type == NULL) - return false; - if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0 - && strchr (domain_type + sizeof "class " - 1, ' ') == NULL) - domain_type += sizeof "class " - 1; - else if (strncmp (domain_type, "union class ", - sizeof "union class ") == 0 - && (strchr (domain_type + sizeof "union class " - 1, ' ') - == NULL)) - domain_type += sizeof "union class " - 1; - len += strlen (domain_type); - } - - if (argcount <= 0) - { - arg_types = NULL; - len += 15; - } - else - { - int i; - - arg_types = (char **) xmalloc (argcount * sizeof *arg_types); - for (i = argcount - 1; i >= 0; i--) - { - if (! substitute_type (info, "")) - return false; - arg_types[i] = pop_type (info); - if (arg_types[i] == NULL) - return false; - len += strlen (arg_types[i]) + 2; - } - if (varargs) - len += 5; - } - - /* Now the return type is on the top of the stack. */ - - s = (char *) xmalloc (len); - if (! domain) - *s = '\0'; - else - strcpy (s, domain_type); - strcat (s, "::| ("); - - if (argcount < 0) - strcat (s, "/* unknown */"); - else - { - int i; - - for (i = 0; i < argcount; i++) - { - if (i > 0) - strcat (s, ", "); - strcat (s, arg_types[i]); - } - if (varargs) - { - if (i > 0) - strcat (s, ", "); - strcat (s, "..."); - } - if (argcount > 0) - free (arg_types); - } - - strcat (s, ")"); - - if (! substitute_type (info, s)) - return false; - - free (s); - - return true; -} - -/* Make a const qualified type. */ - -static boolean -pr_const_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return substitute_type (info, "const |"); -} - -/* Make a volatile qualified type. */ - -static boolean -pr_volatile_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return substitute_type (info, "volatile |"); -} - -/* Start accumulating a struct type. */ - -static boolean -pr_start_struct_type (p, tag, id, structp, size) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - - info->indent += 2; - - if (! push_type (info, structp ? "struct " : "union ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag)) - return false; - } - else - { - char idbuf[20]; - - sprintf (idbuf, "%%anon%u", id); - if (! append_type (info, idbuf)) - return false; - } - - if (! append_type (info, " {")) - return false; - if (size != 0 || tag != NULL) - { - char ab[30]; - - if (! append_type (info, " /*")) - return false; - - if (size != 0) - { - sprintf (ab, " size %u", size); - if (! append_type (info, ab)) - return false; - } - if (tag != NULL) - { - sprintf (ab, " id %u", id); - if (! append_type (info, ab)) - return false; - } - if (! append_type (info, " */")) - return false; - } - if (! append_type (info, "\n")) - return false; - - info->stack->visibility = DEBUG_VISIBILITY_PUBLIC; - - return indent_type (info); -} - -/* Output the visibility of a field in a struct. */ - -static boolean -pr_fix_visibility (info, visibility) - struct pr_handle *info; - enum debug_visibility visibility; -{ - const char *s; - char *t; - unsigned int len; - - assert (info->stack != NULL); - - if (info->stack->visibility == visibility) - return true; - - assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE); - - switch (visibility) - { - case DEBUG_VISIBILITY_PUBLIC: - s = "public"; - break; - case DEBUG_VISIBILITY_PRIVATE: - s = "private"; - break; - case DEBUG_VISIBILITY_PROTECTED: - s = "protected"; - break; - case DEBUG_VISIBILITY_IGNORE: - s = "/* ignore */"; - break; - default: - abort (); - return false; - } - - /* Trim off a trailing space in the struct string, to make the - output look a bit better, then stick on the visibility string. */ - - t = info->stack->type; - len = strlen (t); - assert (t[len - 1] == ' '); - t[len - 1] = '\0'; - - if (! append_type (info, s) - || ! append_type (info, ":\n") - || ! indent_type (info)) - return false; - - info->stack->visibility = visibility; - - return true; -} - -/* Add a field to a struct type. */ - -static boolean -pr_struct_field (p, name, bitpos, bitsize, visibility) - PTR p; - const char *name; - bfd_vma bitpos; - bfd_vma bitsize; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - char *t; - - if (! substitute_type (info, name)) - return false; - - if (! append_type (info, "; /* ")) - return false; - - if (bitsize != 0) - { - print_vma (bitsize, ab, true, false); - if (! append_type (info, "bitsize ") - || ! append_type (info, ab) - || ! append_type (info, ", ")) - return false; - } - - print_vma (bitpos, ab, true, false); - if (! append_type (info, "bitpos ") - || ! append_type (info, ab) - || ! append_type (info, " */\n") - || ! indent_type (info)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (! pr_fix_visibility (info, visibility)) - return false; - - return append_type (info, t); -} - -/* Finish a struct type. */ - -static boolean -pr_end_struct_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - assert (info->stack != NULL); - assert (info->indent >= 2); - - info->indent -= 2; - - /* Change the trailing indentation to have a close brace. */ - s = info->stack->type + strlen (info->stack->type) - 2; - assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0'); - - *s++ = '}'; - *s = '\0'; - - return true; -} - -/* Start a class type. */ - -static boolean -pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; - boolean vptr; - boolean ownvptr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *tv = NULL; - - info->indent += 2; - - if (vptr && ! ownvptr) - { - tv = pop_type (info); - if (tv == NULL) - return false; - } - - if (! push_type (info, structp ? "class " : "union class ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag)) - return false; - } - else - { - char idbuf[20]; - - sprintf (idbuf, "%%anon%u", id); - if (! append_type (info, idbuf)) - return false; - } - - if (! append_type (info, " {")) - return false; - if (size != 0 || vptr || ownvptr || tag != NULL) - { - if (! append_type (info, " /*")) - return false; - - if (size != 0) - { - char ab[20]; - - sprintf (ab, "%u", size); - if (! append_type (info, " size ") - || ! append_type (info, ab)) - return false; - } - - if (vptr) - { - if (! append_type (info, " vtable ")) - return false; - if (ownvptr) - { - if (! append_type (info, "self ")) - return false; - } - else - { - if (! append_type (info, tv) - || ! append_type (info, " ")) - return false; - } - } - - if (tag != NULL) - { - char ab[30]; - - sprintf (ab, " id %u", id); - if (! append_type (info, ab)) - return false; - } - - if (! append_type (info, " */")) - return false; - } - - info->stack->visibility = DEBUG_VISIBILITY_PRIVATE; - - return (append_type (info, "\n") - && indent_type (info)); -} - -/* Add a static member to a class. */ - -static boolean -pr_class_static_member (p, name, physname, visibility) - PTR p; - const char *name; - const char *physname; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, name)) - return false; - - if (! prepend_type (info, "static ") - || ! append_type (info, "; /* ") - || ! append_type (info, physname) - || ! append_type (info, " */\n") - || ! indent_type (info)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (! pr_fix_visibility (info, visibility)) - return false; - - return append_type (info, t); -} - -/* Add a base class to a class. */ - -static boolean -pr_class_baseclass (p, bitpos, virtual, visibility) - PTR p; - bfd_vma bitpos; - boolean virtual; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - const char *prefix; - char ab[20]; - char *s, *l, *n; - - assert (info->stack != NULL && info->stack->next != NULL); - - if (! substitute_type (info, "")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (strncmp (t, "class ", sizeof "class " - 1) == 0) - t += sizeof "class " - 1; - - /* Push it back on to take advantage of the prepend_type and - append_type routines. */ - if (! push_type (info, t)) - return false; - - if (virtual) - { - if (! prepend_type (info, "virtual ")) - return false; - } - - switch (visibility) - { - case DEBUG_VISIBILITY_PUBLIC: - prefix = "public "; - break; - case DEBUG_VISIBILITY_PROTECTED: - prefix = "protected "; - break; - case DEBUG_VISIBILITY_PRIVATE: - prefix = "private "; - break; - default: - prefix = "/* unknown visibility */ "; - break; - } - - if (! prepend_type (info, prefix)) - return false; - - if (bitpos != 0) - { - print_vma (bitpos, ab, true, false); - if (! append_type (info, " /* bitpos ") - || ! append_type (info, ab) - || ! append_type (info, " */")) - return false; - } - - /* Now the top of the stack is something like "public A / * bitpos - 10 * /". The next element on the stack is something like "class - xx { / * size 8 * /\n...". We want to substitute the top of the - stack in before the {. */ - s = strchr (info->stack->next->type, '{'); - assert (s != NULL); - --s; - - /* If there is already a ':', then we already have a baseclass, and - we must append this one after a comma. */ - for (l = info->stack->next->type; l != s; l++) - if (*l == ':') - break; - if (! prepend_type (info, l == s ? " : " : ", ")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1); - memcpy (n, info->stack->type, s - info->stack->type); - strcpy (n + (s - info->stack->type), t); - strcat (n, s); - - free (info->stack->type); - info->stack->type = n; - - free (t); - - return true; -} - -/* Start adding a method to a class. */ - -static boolean -pr_class_start_method (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->stack != NULL); - info->stack->method = name; - return true; -} - -/* Add a variant to a method. */ - -static boolean -pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset, - context) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; - bfd_vma voffset; - boolean context; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *method_type; - char *context_type; - - assert (info->stack != NULL); - assert (info->stack->next != NULL); - - /* Put the const and volatile qualifiers on the type. */ - if (volatilep) - { - if (! append_type (info, " volatile")) - return false; - } - if (constp) - { - if (! append_type (info, " const")) - return false; - } - - /* Stick the name of the method into its type. */ - if (! substitute_type (info, - (context - ? info->stack->next->next->method - : info->stack->next->method))) - return false; - - /* Get the type. */ - method_type = pop_type (info); - if (method_type == NULL) - return false; - - /* Pull off the context type if there is one. */ - if (! context) - context_type = NULL; - else - { - context_type = pop_type (info); - if (context_type == NULL) - return false; - } - - /* Now the top of the stack is the class. */ - - if (! pr_fix_visibility (info, visibility)) - return false; - - if (! append_type (info, method_type) - || ! append_type (info, " /* ") - || ! append_type (info, physname) - || ! append_type (info, " ")) - return false; - if (context || voffset != 0) - { - char ab[20]; - - if (context) - { - if (! append_type (info, "context ") - || ! append_type (info, context_type) - || ! append_type (info, " ")) - return false; - } - print_vma (voffset, ab, true, false); - if (! append_type (info, "voffset ") - || ! append_type (info, ab)) - return false; - } - - return (append_type (info, " */;\n") - && indent_type (info)); -} - -/* Add a static variant to a method. */ - -static boolean -pr_class_static_method_variant (p, physname, visibility, constp, volatilep) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *method_type; - - assert (info->stack != NULL); - assert (info->stack->next != NULL); - assert (info->stack->next->method != NULL); - - /* Put the const and volatile qualifiers on the type. */ - if (volatilep) - { - if (! append_type (info, " volatile")) - return false; - } - if (constp) - { - if (! append_type (info, " const")) - return false; - } - - /* Mark it as static. */ - if (! prepend_type (info, "static ")) - return false; - - /* Stick the name of the method into its type. */ - if (! substitute_type (info, info->stack->next->method)) - return false; - - /* Get the type. */ - method_type = pop_type (info); - if (method_type == NULL) - return false; - - /* Now the top of the stack is the class. */ - - if (! pr_fix_visibility (info, visibility)) - return false; - - return (append_type (info, method_type) - && append_type (info, " /* ") - && append_type (info, physname) - && append_type (info, " */;\n") - && indent_type (info)); -} - -/* Finish up a method. */ - -static boolean -pr_class_end_method (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - info->stack->method = NULL; - return true; -} - -/* Finish up a class. */ - -static boolean -pr_end_class_type (p) - PTR p; -{ - return pr_end_struct_type (p); -} - -/* Push a type on the stack using a typedef name. */ - -static boolean -pr_typedef_type (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, name); -} - -/* Push a type on the stack using a tag name. */ - -static boolean -pr_tag_type (p, name, id, kind) - PTR p; - const char *name; - unsigned int id; - enum debug_type_kind kind; -{ - struct pr_handle *info = (struct pr_handle *) p; - const char *t, *tag; - char idbuf[30]; - - switch (kind) - { - case DEBUG_KIND_STRUCT: - t = "struct "; - break; - case DEBUG_KIND_UNION: - t = "union "; - break; - case DEBUG_KIND_ENUM: - t = "enum "; - break; - case DEBUG_KIND_CLASS: - t = "class "; - break; - case DEBUG_KIND_UNION_CLASS: - t = "union class "; - break; - default: - abort (); - return false; - } - - if (! push_type (info, t)) - return false; - if (name != NULL) - tag = name; - else - { - sprintf (idbuf, "%%anon%u", id); - tag = idbuf; - } - - if (! append_type (info, tag)) - return false; - if (name != NULL && kind != DEBUG_KIND_ENUM) - { - sprintf (idbuf, " /* id %u */", id); - if (! append_type (info, idbuf)) - return false; - } - - return true; -} - -/* Output a typedef. */ - -static boolean -pr_typdef (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - if (! substitute_type (info, name)) - return false; - - s = pop_type (info); - if (s == NULL) - return false; -/* - indent (info); - TRACE_FPRINTF( (info->f, "typedef %s;\n", s)); -*/ - free (s); - - return true; -} - -/* Output a tag. The tag should already be in the string on the - stack, so all we have to do here is print it out. */ - -/*ARGSUSED*/ -static boolean -pr_tag (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - t = pop_type (info); - if (t == NULL) - return false; -/* - indent (info); - TRACE_FPRINTF( (info->f, "%s;\n", t)); -*/ - free (t); - - return true; -} - -/* Output an integer constant. */ - -static boolean -pr_int_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ -/* - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - indent (info); - print_vma (val, ab, false, false); - TRACE_FPRINTF( (info->f, "const int %s = %s;\n", name, ab)); - */ - return true; -} - -/* Output a floating point constant. */ - -static boolean -pr_float_constant (p, name, val) - PTR p; - const char *name; - double val; -{ -/* - struct pr_handle *info = (struct pr_handle *) p; - indent (info); - TRACE_FPRINTF( (info->f, "const double %s = %g;\n", name, val)); - */ - return true; -} - -/* Output a typed constant. */ - -static boolean -pr_typed_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - t = pop_type (info); - if (t == NULL) - return false; -/* - char ab[20]; - indent (info); - print_vma (val, ab, false, false); - TRACE_FPRINTF( (info->f, "const %s %s = %s;\n", t, name, ab)); -*/ - free (t); - - return true; -} - -/* Output a variable. */ - -static boolean -pr_variable (p, name, kind, val) - PTR p; - const char *name; - enum debug_var_kind kind; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - char ab[20]; - (void)ab; - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - indent (info); - switch (kind) - { - case DEBUG_STATIC: - case DEBUG_LOCAL_STATIC: - TRACE_FPRINTF( (info->f, "static ")); - break; - case DEBUG_REGISTER: - TRACE_FPRINTF( (info->f, "register ")); - break; - default: - break; - } - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "%s /* %s */;\n", t, ab)); -#else /* 0 */ -#if 0 - if (kind==DEBUG_STATIC || kind==DEBUG_LOCAL_STATIC) { - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "STATIC_VAR: %s /* %s */;\n", t, ab)); - } -#endif /* 0 */ -#endif /* !0 */ - - free (t); - - return true; -} - -/* Start outputting a function. */ - -static boolean -pr_start_function (p, name, global) - PTR p; - const char *name; - boolean global; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - indent (info); - if (! global) - TRACE_FPRINTF( (info->f, "static ")); - TRACE_FPRINTF( (info->f, "%s (", t)); - info->parameter = 1; -#else /* 0 */ - if (info->functions_size==info->functions_maxsize) { - info->functions_maxsize *= 2; - info->functions = xrealloc(info->functions, - info->functions_maxsize*sizeof(debug_function_t)); - assert(info->functions!=0); - } - /* info->functions[info->functions_size] = xmalloc(sizeof(debug_function_t)); */ - info->function = &info->functions[info->functions_size]; - ++info->functions_size; - info->function->symbol = NULL; - info->function->lines = NULL; - info->function->lines_count = 0; - info->function->max_lines_count = 0; - info->function->name = t; - info->function->filename = NULL; - info->function->block = NULL; - info->function->argv = NULL; - info->function->argc = 0; - info->function->max_argc = 0; -#endif /* !0 */ - return true; -} - -/* Output a function parameter. */ - -static boolean -pr_function_parameter (p, name, kind, val) - PTR p; - const char *name; - enum debug_parm_kind kind; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - debug_function_t* f = info->function; - char *t; - char ab[20]; - (void)ab; - - if (kind == DEBUG_PARM_REFERENCE - || kind == DEBUG_PARM_REF_REG) - { - if (! pr_reference_type (p)) - return false; - } - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - if (info->parameter != 1) - TRACE_FPRINTF( (info->f, ", ")); - - if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG) - TRACE_FPRINTF( (info->f, "register ")); - - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "%s /* %s */", t, ab)); - free (t); - ++info->parameter; -#else /* 0 */ - assert(f!=NULL); - if (f->argv==NULL) { - f->max_argc = 7; /* rarely anyone has more than that many args... */ - f->argv = xmalloc(sizeof(debug_parameter_t)*f->max_argc); - } else if (f->argc==f->max_argc) { - f->max_argc *= 2; - f->argv = realloc(f->argv,sizeof(debug_parameter_t)*f->max_argc); - } - f->argv[f->argc].offset = val; - f->argv[f->argc].name = t; - ++f->argc; -#endif /* !0 */ - return true; -} - -/* Start writing out a block. */ - -static boolean -pr_start_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - debug_block_t* block = 0; - (void)ab; -#if 0 - if (info->parameter > 0) - { - TRACE_FPRINTF( (info->f, ")\n")); - info->parameter = 0; - } - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "{ /* %s */\n", ab)); - info->indent += 2; -#else - if (info->block) { - if (info->block->childs_count==0) - info->block->childs = xmalloc(sizeof(debug_block_t)); - else - info->block->childs = xrealloc(info->block->childs, - info->block->childs_count*sizeof(debug_block_t)); - block = &info->block->childs[info->block->childs_count]; - } else { - block = xmalloc(sizeof(debug_block_t)); - info->function->block = block; - } - block->begin_addr = addr; - block->end_addr = 0; - block->parent = info->block; - block->childs = NULL; - block->childs_count = 0; - info->block = block; -#endif - return true; -} - -/* Write out line number information. */ - -static boolean -pr_lineno (p, filename, lineno, addr) - PTR p; - const char *filename; - unsigned long lineno; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - debug_function_t* f = info->function; - (void)ab; - -#if 0 - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab)); -#else /* 0 */ - if (f==NULL) /* FIXME: skips junk silently. */ - return true; - /* assert(f!=NULL); */ - if (f->filename==NULL) { - f->filename = filename; - assert(f->lines==0); - f->max_lines_count = 4; - f->lines = xmalloc(sizeof(debug_lineno_t)*f->max_lines_count); - } - if (f->lines_count==f->max_lines_count) { - f->max_lines_count *= 2; - f->lines = xrealloc(f->lines, sizeof(debug_lineno_t)*f->max_lines_count); - } - f->lines[f->lines_count].lineno = lineno; - f->lines[f->lines_count].addr = addr; - ++f->lines_count; -#endif /* !0 */ - - return true; -} - -/* Finish writing out a block. */ - -static boolean -pr_end_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - -#if 0 - char ab[20]; - - info->indent -= 2; - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "} /* %s */\n", ab)); -#else /* 0 */ - assert(info->block!=0); - info->block->end_addr = addr; - info->block = info->block->parent; -#endif /* !0 */ - - return true; -} - -/* Finish writing out a function. */ - -/*ARGSUSED*/ -static boolean -pr_end_function (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - assert(info->block==0); - info->function = NULL; - return true; -} - -/* third parameter to segv_action. */ -/* Got it after a bit of head scratching and stack dumping. */ -typedef struct { - u_int32_t foo1; /* +0x00 */ - u_int32_t foo2; - u_int32_t foo3; - u_int32_t foo4; /* usually 2 */ - u_int32_t foo5; /* +0x10 */ - u_int32_t xgs; /* always zero */ - u_int32_t xfs; /* always zero */ - u_int32_t xes; /* always es=ds=ss */ - u_int32_t xds; /* +0x20 */ - u_int32_t edi; - u_int32_t esi; - u_int32_t ebp; - u_int32_t esp; /* +0x30 */ - u_int32_t ebx; - u_int32_t edx; - u_int32_t ecx; - u_int32_t eax; /* +0x40 */ - u_int32_t foo11; /* usually 0xe */ - u_int32_t foo12; /* usually 0x6 */ - u_int32_t eip; /* instruction pointer */ - u_int32_t xcs; /* +0x50 */ - u_int32_t foo21; /* usually 0x2 */ - u_int32_t foo22; /* second stack pointer?! Probably. */ - u_int32_t xss; - u_int32_t foo31; /* +0x60 */ /* usually 0x0 */ - u_int32_t foo32; /* usually 0x2 */ - u_int32_t fault_addr; /* Address which caused a fault */ - u_int32_t foo41; /* usually 0x2 */ -} signal_regs_t; - -signal_regs_t* ptrace_regs = 0; /* Tells my_ptrace to "ptrace" current process" */ -/* - * my_ptrace: small wrapper around ptrace. - * Act as normal ptrace if ptrace_regs==0. - * Read data from current process if ptrace_regs!=0. - */ -static int -my_ptrace( int request, - int pid, - int addr, - int data) -{ - if (ptrace_regs==0) - return ptrace(request, pid, addr, data); - /* we are tracing ourselves! */ - switch (request) { - case PTRACE_ATTACH: return 0; - case PTRACE_CONT: return 0; - case PTRACE_DETACH: return 0; - case PTRACE_PEEKUSER: - switch (addr / 4) { - case EIP: return ptrace_regs->eip; - case EBP: return ptrace_regs->ebp; - default: assert(0); - } - case PTRACE_PEEKTEXT: /* FALLTHROUGH */ - case PTRACE_PEEKDATA: return *(int*)(addr); - default: assert(0); - } - errno = 1; /* what to do here? */ - return 1; /* failed?! */ -} - -#define MAXARGS 6 - -/* - * To minimize the number of parameters. - */ -typedef struct { - asymbol** syms; /* Sorted! */ - int symcount; - debug_function_t** functions; - int functions_size; -} symbol_data_t; - -/* - * Perform a search. A binary search for a symbol. - */ -static void -decode_symbol( symbol_data_t* symbol_data, - const unsigned long addr, - char* buf, - const int bufsize) -{ - asymbol** syms = symbol_data->syms; - const int symcount = symbol_data->symcount; - int bottom = 0; - int top = symcount - 1; - int i; - if (symcount==0) { - sprintf(buf, "????"); - return; - } - while (top>bottom+1) { - i = (top+bottom) / 2; - if (bfd_asymbol_value(syms[i])==addr) { - sprintf(buf, "%s", syms[i]->name); - return; - } else if (bfd_asymbol_value(syms[i]) > addr) - top = i; - else - bottom = i; - } - i = bottom; - if (addr<bfd_asymbol_value(syms[i]) || addr>(syms[i]->section->vma+syms[i]->section->_cooked_size)) - sprintf(buf, "????"); - else - sprintf(buf, "%s + 0x%lx", syms[i]->name, addr-bfd_asymbol_value(syms[i])); -} - -/* - * 1. Perform a binary search for an debug_function_t. - * 2. Fill buf/bufsize with name, parameters and lineno, if found - * Or with '????' otherwise. - */ -static debug_function_t* -find_debug_function_t( symbol_data_t* symbol_data, - const pid_t pid, - const unsigned long fp, /* frame pointer */ - const unsigned long addr, - char* buf, /* string buffer */ - const int bufsize)/* FIXME: not used! */ -{ - debug_function_t** syms = symbol_data->functions; - debug_function_t* f = NULL; - debug_block_t* block = NULL; - debug_lineno_t* lineno = NULL; - const int symcount = symbol_data->functions_size; - int bottom = 0; - int top = symcount - 1; - int i; - char* bufptr = buf; - - if (symcount==0) { - sprintf(buf, "????"); - return NULL; - } - while (top>bottom+1) { - i = (top+bottom) / 2; - if (syms[i]->block->begin_addr==addr) { - f = syms[i]; - break; - } else if (syms[i]->block->begin_addr > addr) - top = i; - else - if (syms[i]->block->end_addr >= addr) { - f = syms[i]; - break; - } else - bottom = i; - } - i = bottom; - if (f!=0) - block = f->block; - else { - block = syms[i]->block; - if (block->begin_addr>=addr && block->end_addr<=addr) - f = syms[i]; - } - if (f==0) - sprintf(buf, "????"); - else { - /* - * Do the backtrace the GDB way... - */ - unsigned long arg; - /* assert(f->lines_count>0); */ - if (f->lines_count>0) { - lineno = &f->lines[f->lines_count-1]; - for (i=1; i<f->lines_count; ++i) - if (f->lines[i].addr>addr) { - lineno = &f->lines[i-1]; - break; - } - } - bufptr[0] = 0; - bufptr += sprintf(bufptr, "%s+0x%lx (", f->name, addr-block->begin_addr); - for (i=0; i<f->argc; ++i) { - bufptr += sprintf(bufptr, "%s = ", f->argv[i].name); - /* FIXME: better parameter printing */ - errno = 0; - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp+f->argv[i].offset, 0); - assert(errno==0); - bufptr += sprintf(bufptr, "0x%x", arg); - if (i!=f->argc-1) - bufptr += sprintf(bufptr, ", "); - } - if (lineno!=0) - bufptr += sprintf(bufptr, ") at %s:%d", f->filename, lineno->lineno); - } - return f; -} - -/* - * Advance through the stacks and display frames as needed. - */ -static int -my_crawl( int pid, - symbol_data_t* symbol_data, - int fout) -{ - unsigned long pc = 0; - unsigned long fp = 0; - unsigned long nextfp; - unsigned long nargs; - unsigned long i; - unsigned long arg; - char buf[8096]; // FIXME: enough? - debug_function_t* f = 0; - - errno = 0; - - pc = my_ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0); - if (!errno) - fp = my_ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0); - - if (!errno) { -#if 1 - f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - for ( ; !errno && fp; ) { - nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); - if (errno) - break; - - if (f==0) { - nargs = (nextfp - fp - 8) / 4; - if (nargs > MAXARGS) - nargs = MAXARGS; - if (nargs > 0) { - fdputs(" (", fout); - for (i = 1; i <= nargs; i++) { - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); - if (errno) - break; - fdprintf(fout,"%lx", arg); - if (i < nargs) - fdputs(", ", fout); - } - fdputc(')', fout); - nargs = nextfp - fp - 8 - (4 * nargs); - if (!errno && nargs > 0) - fdprintf(fout," + %lx\n", nargs); - else - fdputc('\n', fout); - } else - fdputc('\n', fout); - } else - fdputc('\n', fout); - - if (errno || !nextfp) - break; - pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); - fp = nextfp; - if (errno) - break; - f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - } -#else /* 1 */ - decode_symbol(symbol_data, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - for ( ; !errno && fp; ) { - nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); - if (errno) - break; - - nargs = (nextfp - fp - 8) / 4; - if (nargs > MAXARGS) - nargs = MAXARGS; - if (nargs > 0) { - fputs(" (", fout); - for (i = 1; i <= nargs; i++) { - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); - if (errno) - break; - fdprintf(fout,"%lx", arg); - if (i < nargs) - fputs(", ", fout); - } - fdputc(')', fout); - nargs = nextfp - fp - 8 - (4 * nargs); - if (!errno && nargs > 0) - fdprintf(fout," + %lx\n", nargs); - else - fdputc('\n', fout); - } else - fdputc('\n', fout); - - if (errno || !nextfp) - break; - pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); - fp = nextfp; - if (errno) - break; - decode_symbol(symbol_data, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - } -#endif /* !1 */ - } - if (errno) - perror("my_crawl"); - return errno; -} - -/* layout from /usr/src/linux/arch/i386/kernel/process.c */ -static void -show_regs( signal_regs_t* regs, - int fd) -{ - /* long cr0 = 0L, cr2 = 0L, cr3 = 0L; */ - - fdprintf(fd,"\n"); - fdprintf(fd,"FAULT ADDR: %08x\n", regs->fault_addr); - fdprintf(fd,"EIP: %04x:[<%08x>]",0xffff & regs->xcs,regs->eip); - if (regs->xcs & 3) - fdprintf(fd," ESP: %04x:%08x",0xffff & regs->xss,regs->esp); - /*fdprintf(fd," EFLAGS: %08lx\n",regs->eflags); */ - fdprintf(fd, "\n"); - fdprintf(fd,"EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n", - regs->eax,regs->ebx,regs->ecx,regs->edx); - fdprintf(fd,"ESI: %08x EDI: %08x EBP: %08x", - regs->esi, regs->edi, regs->ebp); - fdprintf(fd," DS: %04x ES: %04x\n", - 0xffff & regs->xds,0xffff & regs->xes); - /* - __asm__("movl %%cr0, %0": "=r" (cr0)); - __asm__("movl %%cr2, %0": "=r" (cr2)); - __asm__("movl %%cr3, %0": "=r" (cr3)); - fprintf(stderr,"CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); */ -} - -/* - * Load a BFD for an executable based on PID. Return 0 on failure. - */ -static bfd* -load_bfd( const int pid) -{ - char filename[512]; - bfd* abfd = 0; - - /* Get the contents from procfs. */ -#if 1 - sprintf(filename, "/proc/%d/exe", pid); -#else - sprintf(filename, "crashing"); -#endif - - if ((abfd = bfd_openr (filename, 0))== NULL) - bfd_nonfatal (filename); - else { - char** matching; - assert(bfd_check_format(abfd, bfd_archive)!=true); - - /* - * There is no indication in BFD documentation that it should be done. - * God knows why... - */ - if (!bfd_check_format_matches (abfd, bfd_object, &matching)) { - bfd_nonfatal (bfd_get_filename (abfd)); - if (bfd_get_error () == bfd_error_file_ambiguously_recognized) { - list_matching_formats (matching); - free (matching); - } - } - } - return abfd; -} - -/* - * Those are for qsort. We need only function addresses, so all the others don't count. - */ -/* - * Compare two BFD::asymbol-s. - */ -static int -compare_symbols(const void* ap, - const void* bp) -{ - const asymbol *a = *(const asymbol **)ap; - const asymbol *b = *(const asymbol **)bp; - if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) - return 1; - else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) - return -1; - return 0; -} - -/* - * Compare two debug_asymbol_t-s. - */ -static int -compare_debug_function_t(const void* ap, - const void* bp) -{ - const debug_function_t *a = *(const debug_function_t **)ap; - const debug_function_t *b = *(const debug_function_t **)bp; - assert(a->block!=0); - assert(b->block!=0); - { - const bfd_vma addr1 = a->block->begin_addr; - const bfd_vma addr2 = b->block->begin_addr; - if (addr1 > addr2) - return 1; - else if (addr2 > addr1) - return -1; - } - return 0; -} - -/* - * Filter out (in place) symbols that are useless for stack tracing. - * COUNT is the number of elements in SYMBOLS. - * Return the number of useful symbols. - */ - -static long -remove_useless_symbols( asymbol** symbols, - long count) -{ - asymbol** in_ptr = symbols; - asymbol** out_ptr = symbols; - - while (--count >= 0) { - asymbol *sym = *in_ptr++; - - if (sym->name == NULL || sym->name[0] == '\0' || sym->value==0) - continue; - if (sym->flags & (BSF_DEBUGGING)) - continue; - if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) - continue; - *out_ptr++ = sym; - } - return out_ptr - symbols; -} - -/* - * Debugging information. - */ -static bfd* abfd = 0; -static PTR dhandle = 0; -static asymbol** syms = 0; -static long symcount = 0; -static asymbol** sorted_syms = 0; -static long sorted_symcount = 0; -static debug_function_t** functions = 0; -static int functions_size = 0; -static int sigreport = SIGUSR1; -static pthread_t segv_tid; /* What thread did SEGV? */ -static pid_t segv_pid; - -/* - * We'll get here after a SIGSEGV. But you can install it on other signals, too :) - * Because we are in the middle of the SIGSEGV, we are on our own. We can't do - * any malloc(), any fopen(), nothing. The last is actually a sin. We event can't - * fprintf(stderr,...)!!! - */ -static void -segv_action(int signo, siginfo_t* siginfo, void* ptr) -{ - symbol_data_t symbol_data; - int fd = -1; - - segv_pid = getpid(); - segv_tid = pthread_self(); - fd = open_log_file(segv_tid, segv_pid); - /* signal(SIGSEGV, SIG_DFL); */ - ptrace_regs = (signal_regs_t*)ptr; - assert(ptrace_regs!=0); - - /* Show user how guilty we are. */ - fdprintf(fd,"--------- SEGV in PROCESS %d, THREAD %d ---------------\n", segv_pid, pthread_self()); - show_regs(ptrace_regs, fd); - - /* Some form of stack trace, too. */ - fdprintf(fd, "STACK TRACE:\n"); - - symbol_data.syms = sorted_syms; - symbol_data.symcount = sorted_symcount; - symbol_data.functions = functions; - symbol_data.functions_size = functions_size; - my_crawl(segv_pid, &symbol_data, fd); - //fflush(stdout); - close(fd); - linuxthreads_notify_others(sigreport); -} - - -static void -report_action(int signo, siginfo_t* siginfo, void* ptr) -{ - const int pid = getpid(); - pthread_t tid = pthread_self(); - symbol_data_t symbol_data; - int fd; - if (pthread_equal(tid, segv_tid)) { - /* We have already printed our stack trace... */ - return; - } - - fd = open_log_file(tid, pid); - fdprintf(fd, "REPORT: CURRENT PROCESS:%d, THREAD:%d\n", getpid(), pthread_self()); - /* signal(SIGSEGV, SIG_DFL); */ - ptrace_regs = (signal_regs_t*)ptr; - assert(ptrace_regs!=0); - - /* Show user how guilty we are. */ - fdprintf(fd,"--------- STACK TRACE FOR PROCESS %d, THREAD %d ---------------\n", pid, pthread_self()); - show_regs(ptrace_regs, fd); - - /* Some form of stack trace, too. */ - fdprintf(fd, "STACK TRACE:\n"); - - symbol_data.syms = sorted_syms; - symbol_data.symcount = sorted_symcount; - symbol_data.functions = functions; - symbol_data.functions_size = functions_size; - my_crawl(pid, &symbol_data, fd); - //fflush(stdout); - close(fd); - /* Tell segv_thread to proceed after pause(). */ - /*pthread_kill(segv_tid, sigreport); - kill(segv_pid, sigreport); - pthread_cancel(tid); */ -} - -/* - * Main library routine. Just call it on your program. - */ -int -pstack_install_segv_action( const char* path_format_) -{ - const int pid = getpid(); - struct sigaction act; - - /* Store what we have to for later usage. */ - path_format = path_format_; - - /* We need a signal action for SIGSEGV and sigreport ! */ - sigreport = SIGUSR1; - act.sa_handler = 0; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO|SA_ONESHOT; /* Just one SIGSEGV. */ - act.sa_sigaction = segv_action; - act.sa_restorer = NULL; - if (sigaction(SIGSEGV, &act, NULL)!=0) { - perror("sigaction"); - return 1; - } - act.sa_sigaction = report_action; - act.sa_flags = SA_SIGINFO; /* But many sigreports. */ - if (sigaction(sigreport, &act, NULL)!=0) { - perror("sigaction"); - return 1; - } - - /* And a little setup for libiberty. */ - program_name = "crashing"; - xmalloc_set_program_name (program_name); - - /* Umm, and initialize BFD, too */ - bfd_init(); -#if 0 - list_supported_targets(0, stdout); - set_default_bfd_target(); -#endif /* 0 */ - - if ((abfd = load_bfd(pid))==0) - fprintf(stderr, "BFD load failed..\n"); - else { - long storage_needed= (bfd_get_file_flags(abfd) & HAS_SYMS) ? - bfd_get_symtab_upper_bound (abfd) : 0; - long i; - (void)i; - - if (storage_needed < 0) - fprintf(stderr, "Symbol table size estimation failure.\n"); - else if (storage_needed > 0) { - syms = (asymbol **) xmalloc (storage_needed); - symcount = bfd_canonicalize_symtab (abfd, syms); - - TRACE_FPRINTF((stderr, "TOTAL: %ld SYMBOLS.\n", symcount)); - /* We need debugging info, too! */ - if (symcount==0 || (dhandle = read_debugging_info (abfd, syms, symcount))==0) - fprintf(stderr, "NO DEBUGGING INFORMATION FOUND.\n"); - - /* We make a copy of syms to sort. We don't want to sort syms - because that will screw up the relocs. */ - sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); - memcpy (sorted_syms, syms, symcount * sizeof (asymbol *)); - -#if 0 - for (i=0; i<symcount; ++i) - if (syms[i]->name!=0 && strlen(syms[i]->name)>0 && syms[i]->value!=0) - printf("%08lx T %s\n", syms[i]->section->vma + syms[i]->value, syms[i]->name); -#endif - sorted_symcount = remove_useless_symbols (sorted_syms, symcount); - TRACE_FPRINTF((stderr, "SORTED: %ld SYMBOLS.\n", sorted_symcount)); - - /* Sort the symbols into section and symbol order */ - qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); -#if 0 - for (i=0; i<sorted_symcount; ++i) - if (sorted_syms[i]->name!=0 && strlen(sorted_syms[i]->name)>0 && sorted_syms[i]->value!=0) - printf("%08lx T %s\n", sorted_syms[i]->section->vma + sorted_syms[i]->value, sorted_syms[i]->name); -#endif - /* We have symbols, we need debugging info somehow sorted out. */ - if (dhandle==0) { - fprintf(stderr, "STACK TRACE WILL BE UNCOMFORTABLE.\n"); - } else { - /* Start collecting the debugging information.... */ - struct pr_handle info; - - info.f = stdout; - info.indent = 0; - info.stack = NULL; - info.parameter = 0; - info.block = NULL; - info.function = NULL; - info.functions_size = 0; - info.functions_maxsize = 1000; - info.functions = (debug_function_t*)xmalloc(sizeof(debug_function_t)*info.functions_maxsize); - debug_write (dhandle, &pr_fns, (PTR) &info); - TRACE_FPRINTF((stdout, "\n%d DEBUG SYMBOLS\n", info.functions_size)); - assert(info.functions_size!=0); - functions = xmalloc(sizeof(debug_function_t*)*info.functions_size); - functions_size = info.functions_size; - for (i=0; i<functions_size; ++i) - functions[i] = &info.functions[i]; - /* Sort the symbols into section and symbol order */ - qsort (functions, functions_size, sizeof(debug_function_t*), - compare_debug_function_t); -#if 0 - for (i=0; i<info.functions_size; ++i) - fprintf(stdout, "%08lx T %s\n", info.functions[i].block->begin_addr, info.functions[i].name); -#endif - fflush(stdout); - } - } else /* storage_needed == 0 */ - fprintf(stderr, "NO SYMBOLS FOUND.\n"); - } - return 0; -} - -/*********************************************************************/ -/*********************************************************************/ -/*********************************************************************/ |