process.c: Use the symbol, it looks like it was meant to be used...
[memprof.git] / lib / stack-frame.c
blobebb2c9247ece34bc993bb628746f9cdcf25604ef
1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 1999, 2000, 2001, Red Hat, Inc.
5 * Copyright 2002, Kristian Rietveld
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 /*====*/
23 /* This code is mostly from eazel-tools/prof
25 * stack-frame.c -- hacks to read the backtrace
27 * Authors: John Harper <jsh@eazel.com>
29 * With modifications by Owen Taylor <otaylor@redhat.com> to
30 * add mi_call_with_signal_backtrace() and to work better within
31 * the MemProf framework.
33 #include <config.h>
35 #include <alloca.h>
36 #include <string.h>
38 #ifdef HAVE_EXECINFO_H
39 # include <execinfo.h>
40 #endif
42 #include "stack-frame.h"
44 #if defined (HAVE_BACKTRACE)
45 void
46 mi_call_with_backtrace (int to_skip, void callback (int, void **, void *), void *data)
48 int bufsiz = 128, count = 0;
49 void **buf;
50 static __thread int in_backtrace = 0;
52 again:
53 buf = alloca (bufsiz * sizeof (void *));
55 if (!(in_backtrace++))
56 count = backtrace (buf, bufsiz);
57 in_backtrace--;
59 if (count == bufsiz)
61 bufsiz = bufsiz * 2;
62 goto again;
65 callback (count - to_skip, buf + to_skip, data);
67 #endif
69 /* Magic code to chain along the stack frames
71 This may even work on non-386 gcc targets, but I haven't tested it.. */
73 #define HAVE_FRAME_ACCESSORS
75 #if defined (__GNUC__) && defined (__i386__)
76 typedef struct stack_frame_struct stack_frame;
77 struct stack_frame_struct {
78 stack_frame *next;
79 void *return_address;
82 static inline stack_frame *
83 first_frame (void)
85 return __builtin_frame_address (0);
88 static inline stack_frame *
89 next_frame (stack_frame *fp)
91 return (fp != 0) ? fp->next : 0;
94 static inline void *
95 frame_return_address (stack_frame *fp)
97 return (fp != 0) ? fp->return_address : 0;
100 #endif
102 #ifndef HAVE_BACKTRACE
104 #ifndef HAVE_FRAME_ACCESSORS
105 # error "Don't have stack-frame accessors for your compiler/architecture."
106 #endif
108 void
109 mi_call_with_backtrace (int to_skip, void callback (int, void **, void *), void *data)
111 int nframes = 64;
112 void **frames = alloca (sizeof (void *) * nframes);
113 int depth;
114 stack_frame *frame;
116 for (frame = first_frame (), depth = 0;
117 frame != 0;
118 frame = next_frame (frame), depth++)
120 void *ret = frame_return_address (frame);
121 if (depth == nframes)
123 void *new = alloca (sizeof (void *) * (nframes * 2));
124 memcpy (new, frames, nframes * sizeof (void *));
125 frames = new;
126 nframes *= 2;
128 frames[depth] = ret;
131 callback (depth - to_skip, frames + to_skip, data);
134 #endif /* !HAVE_BACKTRACE */
137 * mi_call_with_signal_backtrace:
138 * @first_address: Instruction pointer from signal context
139 * @second_frame: Frame pointer from signal context.
140 * @stack_bound: Stack pointer from signal context; used as
141 * a rough way of detecting invalid frame pointers.
142 * @callback: callback function
143 * @data: User data to pass to @callback
145 * Calls @callback with a stack trace from the the pointer where the
146 * signal interupted normap execution.
148 void
149 mi_call_with_signal_backtrace (void *first_address, void *second_frame, void *stack_bound,
150 void callback (int, void **, void *), void *data)
152 int nframes = 64;
153 void **frames = alloca (sizeof (void *) * nframes);
154 int depth;
155 stack_frame *frame;
157 frames[0] = first_address;
159 for (frame = second_frame, depth = 1;
160 (void *)frame > stack_bound;
161 frame = next_frame (frame), depth++)
163 void *ret = frame_return_address (frame);
164 if (depth == nframes)
166 void *new = alloca (sizeof (void *) * (nframes * 2));
167 memcpy (new, frames, nframes * sizeof (void *));
168 frames = new;
169 nframes *= 2;
171 frames[depth] = ret;
174 callback (depth, frames, data);