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.
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.
38 #ifdef HAVE_EXECINFO_H
39 # include <execinfo.h>
42 #include "stack-frame.h"
44 #if defined (HAVE_BACKTRACE)
46 mi_call_with_backtrace (int to_skip
, void callback (int, void **, void *), void *data
)
48 int bufsiz
= 128, count
= 0;
50 static __thread
int in_backtrace
= 0;
53 buf
= alloca (bufsiz
* sizeof (void *));
55 if (!(in_backtrace
++))
56 count
= backtrace (buf
, bufsiz
);
65 callback (count
- to_skip
, buf
+ to_skip
, data
);
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
{
82 static inline stack_frame
*
85 return __builtin_frame_address (0);
88 static inline stack_frame
*
89 next_frame (stack_frame
*fp
)
91 return (fp
!= 0) ? fp
->next
: 0;
95 frame_return_address (stack_frame
*fp
)
97 return (fp
!= 0) ? fp
->return_address
: 0;
102 #ifndef HAVE_BACKTRACE
104 #ifndef HAVE_FRAME_ACCESSORS
105 # error "Don't have stack-frame accessors for your compiler/architecture."
109 mi_call_with_backtrace (int to_skip
, void callback (int, void **, void *), void *data
)
112 void **frames
= alloca (sizeof (void *) * nframes
);
116 for (frame
= first_frame (), depth
= 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 *));
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.
149 mi_call_with_signal_backtrace (void *first_address
, void *second_frame
, void *stack_bound
,
150 void callback (int, void **, void *), void *data
)
153 void **frames
= alloca (sizeof (void *) * nframes
);
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 *));
174 callback (depth
, frames
, data
);