]>
Commit | Line | Data |
---|---|---|
38cbfe40 RK |
1 | /**************************************************************************** |
2 | * * | |
3 | * GNATMEM COMPONENTS * | |
4 | * * | |
5 | * G M E M * | |
6 | * * | |
5d1a9698 | 7 | * $Revision$ |
38cbfe40 RK |
8 | * * |
9 | * C Implementation File * | |
10 | * * | |
11 | * Copyright (C) 2000-2001 Free Software Foundation, Inc. * | |
12 | * * | |
13 | * GNAT is free software; you can redistribute it and/or modify it under * | |
14 | * terms of the GNU General Public License as published by the Free Soft- * | |
15 | * ware Foundation; either version 2, or (at your option) any later ver- * | |
16 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * | |
17 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * | |
18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * | |
19 | * for more details. You should have received a copy of the GNU General * | |
20 | * Public License distributed with GNAT; see file COPYING. If not, write * | |
21 | * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * | |
22 | * MA 02111-1307, USA. * | |
23 | * * | |
24 | * As a special exception, if you link this file with other files to * | |
25 | * produce an executable, this file does not by itself cause the resulting * | |
26 | * executable to be covered by the GNU General Public License. This except- * | |
27 | * ion does not however invalidate any other reasons why the executable * | |
28 | * file might be covered by the GNU Public License. * | |
29 | * * | |
30 | * GNAT was originally developed by the GNAT team at New York University. * | |
31 | * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). * | |
32 | * * | |
33 | ****************************************************************************/ | |
34 | ||
35 | /* This unit reads the allocation tracking log produced by augmented | |
36 | __gnat_malloc and __gnat_free procedures (see file a-raise.c) and | |
37 | provides GNATMEM tool with gdb-compliant output. The output is | |
38 | processed by GNATMEM to detect dynamic memory allocation errors. | |
39 | ||
40 | See GNATMEM section in GNAT User's Guide for more information. | |
41 | ||
42 | NOTE: This capability is currently supported on the following targets: | |
43 | ||
44 | DEC Unix | |
45 | SGI Irix | |
5d1a9698 | 46 | GNU/Linux x86 |
38cbfe40 RK |
47 | Solaris (sparc and x86) (*) |
48 | Windows 98/95/NT (x86) | |
49 | ||
50 | (*) on these targets, the compilation must be done with -funwind-tables to | |
51 | be able to build the stack backtrace. */ | |
52 | ||
53 | #ifdef __alpha_vxworks | |
54 | #include "vxWorks.h" | |
55 | #endif | |
56 | ||
57 | #ifdef IN_RTS | |
58 | #include "tconfig.h" | |
59 | #include "tsystem.h" | |
60 | #else | |
61 | #include "config.h" | |
62 | #include "system.h" | |
63 | #endif | |
64 | ||
65 | #include "adaint.h" | |
66 | ||
67 | static FILE *gmemfile; | |
68 | ||
69 | /* tb_len is the number of call level supported by this module */ | |
70 | #define TB_LEN 200 | |
71 | ||
72 | static char *tracebk [TB_LEN]; | |
73 | static int cur_tb_len, cur_tb_pos; | |
74 | ||
75 | extern void convert_addresses PARAMS ((char *[], int, void *, | |
76 | int *)); | |
77 | static void gmem_read_backtrace PARAMS ((void)); | |
78 | static char *spc2nul PARAMS ((char *)); | |
79 | ||
80 | extern int __gnat_gmem_initialize PARAMS ((char *)); | |
81 | extern void __gnat_gmem_a2l_initialize PARAMS ((char *)); | |
82 | extern void __gnat_gmem_read_next PARAMS ((char *)); | |
83 | extern void __gnat_gmem_read_bt_frame PARAMS ((char *)); | |
84 | \f | |
85 | /* Reads backtrace information from gmemfile placing them in tracebk | |
86 | array. cur_tb_len is the size of this array. */ | |
87 | ||
88 | static void | |
89 | gmem_read_backtrace () | |
90 | { | |
91 | fread (&cur_tb_len, sizeof (int), 1, gmemfile); | |
92 | fread (tracebk, sizeof (char *), cur_tb_len, gmemfile); | |
93 | cur_tb_pos = 0; | |
94 | } | |
95 | ||
96 | /* Initialize gmem feature from the dumpname file. Return 1 if the | |
97 | dumpname has been generated by GMEM (instrumented malloc/free) and 0 if not | |
98 | (i.e. probably a GDB generated file). */ | |
99 | ||
100 | int | |
101 | __gnat_gmem_initialize (dumpname) | |
102 | char *dumpname; | |
103 | { | |
104 | char header[10]; | |
105 | ||
106 | gmemfile = fopen (dumpname, "rb"); | |
107 | fread (header, 10, 1, gmemfile); | |
108 | ||
109 | /* Check for GMEM magic-tag. */ | |
110 | if (memcmp (header, "GMEM DUMP\n", 10)) | |
111 | { | |
112 | fclose (gmemfile); | |
113 | return 0; | |
114 | } | |
c0b1738d | 115 | |
38cbfe40 RK |
116 | return 1; |
117 | } | |
118 | ||
119 | /* Initialize addr2line library */ | |
120 | ||
121 | void | |
122 | __gnat_gmem_a2l_initialize (exename) | |
123 | char *exename; | |
124 | { | |
125 | extern char **gnat_argv; | |
126 | char s [100]; | |
127 | int l; | |
128 | ||
129 | gnat_argv [0] = exename; | |
130 | convert_addresses (tracebk, 1, s, &l); | |
131 | } | |
132 | ||
133 | /* Read next allocation of deallocation information from the GMEM file and | |
134 | write an alloc/free information in buf to be processed by GDB (see gnatmem | |
135 | implementation). */ | |
136 | ||
137 | void | |
138 | __gnat_gmem_read_next (buf) | |
139 | char *buf; | |
140 | { | |
141 | void *addr; | |
142 | int size; | |
c0b1738d | 143 | int j; |
38cbfe40 | 144 | |
c0b1738d RK |
145 | j = fgetc (gmemfile); |
146 | if (j == EOF) | |
38cbfe40 RK |
147 | { |
148 | fclose (gmemfile); | |
149 | sprintf (buf, "Program exited."); | |
150 | } | |
151 | else | |
152 | { | |
c0b1738d | 153 | switch (j) |
38cbfe40 RK |
154 | { |
155 | case 'A' : | |
156 | fread (&addr, sizeof (char *), 1, gmemfile); | |
157 | fread (&size, sizeof (int), 1, gmemfile); | |
158 | sprintf (buf, "ALLOC^%d^0x%lx^", size, (long) addr); | |
159 | break; | |
160 | case 'D' : | |
161 | fread (&addr, sizeof (char *), 1, gmemfile); | |
162 | sprintf (buf, "DEALL^0x%lx^", (long) addr); | |
163 | break; | |
164 | default: | |
165 | puts ("GMEM dump file corrupt"); | |
166 | __gnat_os_exit (1); | |
167 | } | |
168 | ||
169 | gmem_read_backtrace (); | |
170 | } | |
171 | } | |
172 | ||
173 | /* Scans the line until the space or new-line character is encountered; | |
174 | this character is replaced by nul and its position is returned. */ | |
175 | ||
176 | static char * | |
177 | spc2nul (s) | |
178 | char *s; | |
179 | { | |
180 | while (*++s) | |
181 | if (*s == ' ' || *s == '\n') | |
182 | { | |
183 | *s = 0; | |
184 | return s; | |
185 | } | |
186 | ||
187 | abort (); | |
188 | } | |
189 | ||
190 | /* Convert backtrace address in tracebk at position cur_tb_pos to a symbolic | |
191 | traceback information returned in buf and to be processed by GDB (see | |
192 | gnatmem implementation). */ | |
193 | ||
194 | void | |
195 | __gnat_gmem_read_bt_frame (buf) | |
196 | char *buf; | |
197 | { | |
198 | int l = 0; | |
199 | char s[1000]; | |
200 | char *name, *file; | |
201 | ||
202 | if (cur_tb_pos >= cur_tb_len) | |
203 | { | |
204 | buf [0] = ' '; | |
205 | buf [1] = '\0'; | |
206 | return; | |
207 | } | |
208 | ||
209 | convert_addresses (tracebk + cur_tb_pos, 1, s, &l); | |
210 | s[l] = '\0'; | |
211 | name = spc2nul (s) + 4; | |
212 | file = spc2nul (name) + 4; | |
213 | spc2nul (file); | |
214 | ++cur_tb_pos; | |
215 | ||
216 | sprintf (buf, "# %s () at %s", name, file); | |
217 | } |