xref: /titanic_44/usr/src/tools/ctf/dwarf/common/malloc_check.c (revision 07dc1947c362e187fb955d283b692f8769dd5def)
1*07dc1947SRichard Lowe /*
2*07dc1947SRichard Lowe 
3*07dc1947SRichard Lowe   Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
4*07dc1947SRichard Lowe 
5*07dc1947SRichard Lowe   This program is free software; you can redistribute it and/or modify it
6*07dc1947SRichard Lowe   under the terms of version 2.1 of the GNU Lesser General Public License
7*07dc1947SRichard Lowe   as published by the Free Software Foundation.
8*07dc1947SRichard Lowe 
9*07dc1947SRichard Lowe   This program is distributed in the hope that it would be useful, but
10*07dc1947SRichard Lowe   WITHOUT ANY WARRANTY; without even the implied warranty of
11*07dc1947SRichard Lowe   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12*07dc1947SRichard Lowe 
13*07dc1947SRichard Lowe   Further, this software is distributed without any warranty that it is
14*07dc1947SRichard Lowe   free of the rightful claim of any third person regarding infringement
15*07dc1947SRichard Lowe   or the like.  Any license provided herein, whether implied or
16*07dc1947SRichard Lowe   otherwise, applies only to this software file.  Patent licenses, if
17*07dc1947SRichard Lowe   any, provided herein do not apply to combinations of this program with
18*07dc1947SRichard Lowe   other software, or any other product whatsoever.
19*07dc1947SRichard Lowe 
20*07dc1947SRichard Lowe   You should have received a copy of the GNU Lesser General Public
21*07dc1947SRichard Lowe   License along with this program; if not, write the Free Software
22*07dc1947SRichard Lowe   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23*07dc1947SRichard Lowe   USA.
24*07dc1947SRichard Lowe 
25*07dc1947SRichard Lowe   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
26*07dc1947SRichard Lowe   Mountain View, CA 94043, or:
27*07dc1947SRichard Lowe 
28*07dc1947SRichard Lowe   http://www.sgi.com
29*07dc1947SRichard Lowe 
30*07dc1947SRichard Lowe   For further information regarding this notice, see:
31*07dc1947SRichard Lowe 
32*07dc1947SRichard Lowe   http://oss.sgi.com/projects/GenInfo/NoticeExplan
33*07dc1947SRichard Lowe 
34*07dc1947SRichard Lowe */
35*07dc1947SRichard Lowe 
36*07dc1947SRichard Lowe 
37*07dc1947SRichard Lowe 
38*07dc1947SRichard Lowe /* malloc_check.c For checking dealloc completeness.
39*07dc1947SRichard Lowe 
40*07dc1947SRichard Lowe    This code is as simple as possible and works ok for
41*07dc1947SRichard Lowe    reasonable size allocation counts.
42*07dc1947SRichard Lowe 
43*07dc1947SRichard Lowe    It treats allocation as global, and so will not
44*07dc1947SRichard Lowe    work very well if an application opens more than one
45*07dc1947SRichard Lowe    Dwarf_Debug.
46*07dc1947SRichard Lowe 
47*07dc1947SRichard Lowe */
48*07dc1947SRichard Lowe 
49*07dc1947SRichard Lowe #include <stdio.h>
50*07dc1947SRichard Lowe #include <stdlib.h>             /* for exit() and various malloc
51*07dc1947SRichard Lowe                                    prototypes */
52*07dc1947SRichard Lowe #include "config.h"
53*07dc1947SRichard Lowe #include "dwarf_incl.h"
54*07dc1947SRichard Lowe #include "malloc_check.h"
55*07dc1947SRichard Lowe #ifdef  WANT_LIBBDWARF_MALLOC_CHECK
56*07dc1947SRichard Lowe 
57*07dc1947SRichard Lowe /* To turn off printing every entry, just change the define
58*07dc1947SRichard Lowe    to set PRINT_MALLOC_DETAILS 0.
59*07dc1947SRichard Lowe */
60*07dc1947SRichard Lowe #define PRINT_MALLOC_DETAILS 0
61*07dc1947SRichard Lowe 
62*07dc1947SRichard Lowe #define MC_TYPE_UNKNOWN 0
63*07dc1947SRichard Lowe #define MC_TYPE_ALLOC 1
64*07dc1947SRichard Lowe #define MC_TYPE_DEALLOC 2
65*07dc1947SRichard Lowe 
66*07dc1947SRichard Lowe struct mc_data_s {
67*07dc1947SRichard Lowe     struct mc_data_s *mc_prev;
68*07dc1947SRichard Lowe     unsigned long mc_address;   /* Assumes this is large enough to hold
69*07dc1947SRichard Lowe                                    a pointer! */
70*07dc1947SRichard Lowe 
71*07dc1947SRichard Lowe     long mc_alloc_number;       /* Assigned in order by when record
72*07dc1947SRichard Lowe                                    created. */
73*07dc1947SRichard Lowe     unsigned char mc_alloc_code;        /* Allocation code, libdwarf. */
74*07dc1947SRichard Lowe     unsigned char mc_type;
75*07dc1947SRichard Lowe     unsigned char mc_dealloc_noted;     /* Used on an ALLOC node. */
76*07dc1947SRichard Lowe     unsigned char mc_dealloc_noted_count;       /* Used on an ALLOC
77*07dc1947SRichard Lowe                                                    node. */
78*07dc1947SRichard Lowe };
79*07dc1947SRichard Lowe 
80*07dc1947SRichard Lowe /*
81*07dc1947SRichard Lowe 
82*07dc1947SRichard Lowe 
83*07dc1947SRichard Lowe */
84*07dc1947SRichard Lowe #define HASH_TABLE_SIZE 10501
85*07dc1947SRichard Lowe static struct mc_data_s *mc_data_hash[HASH_TABLE_SIZE];
86*07dc1947SRichard Lowe static long mc_data_list_size = 0;
87*07dc1947SRichard Lowe 
88*07dc1947SRichard Lowe static char *alloc_type_name[MAX_DW_DLA + 1] = {
89*07dc1947SRichard Lowe     "",
90*07dc1947SRichard Lowe     "DW_DLA_STRING",
91*07dc1947SRichard Lowe     "DW_DLA_LOC",
92*07dc1947SRichard Lowe     "DW_DLA_LOCDESC",
93*07dc1947SRichard Lowe     "DW_DLA_ELLIST",
94*07dc1947SRichard Lowe     "DW_DLA_BOUNDS",
95*07dc1947SRichard Lowe     "DW_DLA_BLOCK",
96*07dc1947SRichard Lowe     "DW_DLA_DEBUG",
97*07dc1947SRichard Lowe     "DW_DLA_DIE",
98*07dc1947SRichard Lowe     "DW_DLA_LINE",
99*07dc1947SRichard Lowe     "DW_DLA_ATTR",
100*07dc1947SRichard Lowe     "DW_DLA_TYPE",
101*07dc1947SRichard Lowe     "DW_DLA_SUBSCR",
102*07dc1947SRichard Lowe     "DW_DLA_GLOBAL",
103*07dc1947SRichard Lowe     "DW_DLA_ERROR",
104*07dc1947SRichard Lowe     "DW_DLA_LIST",
105*07dc1947SRichard Lowe     "DW_DLA_LINEBUF",
106*07dc1947SRichard Lowe     "DW_DLA_ARANGE",
107*07dc1947SRichard Lowe     "DW_DLA_ABBREV",
108*07dc1947SRichard Lowe     "DW_DLA_FRAME_OP",
109*07dc1947SRichard Lowe     "DW_DLA_CIE",
110*07dc1947SRichard Lowe     "DW_DLA_FDE",
111*07dc1947SRichard Lowe     "DW_DLA_LOC_BLOCK",
112*07dc1947SRichard Lowe     "DW_DLA_FRAME_BLOCK",
113*07dc1947SRichard Lowe     "DW_DLA_FUNC",
114*07dc1947SRichard Lowe     "DW_DLA_TYPENAME",
115*07dc1947SRichard Lowe     "DW_DLA_VAR",
116*07dc1947SRichard Lowe     "DW_DLA_WEAK",
117*07dc1947SRichard Lowe     "DW_DLA_ADDR",
118*07dc1947SRichard Lowe     "DW_DLA_ABBREV_LIST",
119*07dc1947SRichard Lowe     "DW_DLA_CHAIN",
120*07dc1947SRichard Lowe     "DW_DLA_CU_CONTEXT",
121*07dc1947SRichard Lowe     "DW_DLA_FRAME",
122*07dc1947SRichard Lowe     "DW_DLA_GLOBAL_CONTEXT",
123*07dc1947SRichard Lowe     "DW_DLA_FILE_ENTRY",
124*07dc1947SRichard Lowe     "DW_DLA_LINE_CONTEXT",
125*07dc1947SRichard Lowe     "DW_DLA_LOC_CHAIN",
126*07dc1947SRichard Lowe     "DW_DLA_HASH_TABLE",
127*07dc1947SRichard Lowe     "DW_DLA_FUNC_CONTEXT",
128*07dc1947SRichard Lowe     "DW_DLA_TYPENAME_CONTEXT",
129*07dc1947SRichard Lowe     "DW_DLA_VAR_CONTEXT",
130*07dc1947SRichard Lowe     "DW_DLA_WEAK_CONTEXT",
131*07dc1947SRichard Lowe     "DW_DLA_PUBTYPES_CONTEXT"
132*07dc1947SRichard Lowe         /* Don't forget to expand this list if the list of codes
133*07dc1947SRichard Lowe            expands. */
134*07dc1947SRichard Lowe };
135*07dc1947SRichard Lowe 
136*07dc1947SRichard Lowe static unsigned
hash_address(unsigned long addr)137*07dc1947SRichard Lowe hash_address(unsigned long addr)
138*07dc1947SRichard Lowe {
139*07dc1947SRichard Lowe     unsigned long a = addr >> 2;
140*07dc1947SRichard Lowe 
141*07dc1947SRichard Lowe     return a % HASH_TABLE_SIZE;
142*07dc1947SRichard Lowe }
143*07dc1947SRichard Lowe 
144*07dc1947SRichard Lowe #if PRINT_MALLOC_DETAILS
145*07dc1947SRichard Lowe static void
print_alloc_dealloc_detail(unsigned long addr,int code,char * whichisit)146*07dc1947SRichard Lowe print_alloc_dealloc_detail(unsigned long addr,
147*07dc1947SRichard Lowe                            int code, char *whichisit)
148*07dc1947SRichard Lowe {
149*07dc1947SRichard Lowe     fprintf(stderr,
150*07dc1947SRichard Lowe             "%s  addr 0x%lx code %d (%s) entry %ld\n",
151*07dc1947SRichard Lowe             whichisit, addr, code, alloc_type_name[code],
152*07dc1947SRichard Lowe             mc_data_list_size);
153*07dc1947SRichard Lowe }
154*07dc1947SRichard Lowe #else
155*07dc1947SRichard Lowe #define  print_alloc_dealloc_detail(a,b,c)      /* nothing */
156*07dc1947SRichard Lowe #endif
157*07dc1947SRichard Lowe 
158*07dc1947SRichard Lowe /* Create a zeroed struct or die. */
159*07dc1947SRichard Lowe static void *
newone(void)160*07dc1947SRichard Lowe newone(void)
161*07dc1947SRichard Lowe {
162*07dc1947SRichard Lowe     struct mc_data_s *newd = malloc(sizeof(struct mc_data_s));
163*07dc1947SRichard Lowe 
164*07dc1947SRichard Lowe     if (newd == 0) {
165*07dc1947SRichard Lowe         fprintf(stderr, "out of memory , # %ld\n", mc_data_list_size);
166*07dc1947SRichard Lowe         exit(1);
167*07dc1947SRichard Lowe     }
168*07dc1947SRichard Lowe     memset(newd, 0, sizeof(struct mc_data_s));
169*07dc1947SRichard Lowe     return newd;
170*07dc1947SRichard Lowe }
171*07dc1947SRichard Lowe 
172*07dc1947SRichard Lowe /* Notify checker that get_alloc has allocated user data. */
173*07dc1947SRichard Lowe void
dwarf_malloc_check_alloc_data(void * addr_in,unsigned char code)174*07dc1947SRichard Lowe dwarf_malloc_check_alloc_data(void *addr_in, unsigned char code)
175*07dc1947SRichard Lowe {
176*07dc1947SRichard Lowe     struct mc_data_s *newd = newone();
177*07dc1947SRichard Lowe     unsigned long addr = (unsigned long) addr_in;
178*07dc1947SRichard Lowe     struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
179*07dc1947SRichard Lowe 
180*07dc1947SRichard Lowe     print_alloc_dealloc_detail(addr, code, "alloc   ");
181*07dc1947SRichard Lowe     newd->mc_address = addr;
182*07dc1947SRichard Lowe     newd->mc_alloc_code = code;
183*07dc1947SRichard Lowe     newd->mc_type = MC_TYPE_ALLOC;
184*07dc1947SRichard Lowe     newd->mc_alloc_number = mc_data_list_size;
185*07dc1947SRichard Lowe     newd->mc_prev = *base;
186*07dc1947SRichard Lowe     *base = newd;
187*07dc1947SRichard Lowe     newd->mc_alloc_number = mc_data_list_size;
188*07dc1947SRichard Lowe     mc_data_list_size += 1;
189*07dc1947SRichard Lowe }
190*07dc1947SRichard Lowe 
191*07dc1947SRichard Lowe static void
print_entry(char * msg,struct mc_data_s * data)192*07dc1947SRichard Lowe print_entry(char *msg, struct mc_data_s *data)
193*07dc1947SRichard Lowe {
194*07dc1947SRichard Lowe     fprintf(stderr,
195*07dc1947SRichard Lowe             "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n",
196*07dc1947SRichard Lowe             msg,
197*07dc1947SRichard Lowe             (long) data->mc_address,
198*07dc1947SRichard Lowe             data->mc_alloc_code,
199*07dc1947SRichard Lowe             alloc_type_name[data->mc_alloc_code],
200*07dc1947SRichard Lowe             (data->mc_type == MC_TYPE_ALLOC) ? "alloc  " :
201*07dc1947SRichard Lowe             (data->mc_type == MC_TYPE_DEALLOC) ? "dealloc" : "unknown",
202*07dc1947SRichard Lowe             (unsigned) data->mc_dealloc_noted,
203*07dc1947SRichard Lowe             (unsigned) data->mc_dealloc_noted_count);
204*07dc1947SRichard Lowe }
205*07dc1947SRichard Lowe 
206*07dc1947SRichard Lowe /* newd is a 'dealloc'.
207*07dc1947SRichard Lowe */
208*07dc1947SRichard Lowe static long
balanced_by_alloc_p(struct mc_data_s * newd,long * addr_match_num,struct mc_data_s ** addr_match,struct mc_data_s * base)209*07dc1947SRichard Lowe balanced_by_alloc_p(struct mc_data_s *newd,
210*07dc1947SRichard Lowe                     long *addr_match_num,
211*07dc1947SRichard Lowe                     struct mc_data_s **addr_match,
212*07dc1947SRichard Lowe                     struct mc_data_s *base)
213*07dc1947SRichard Lowe {
214*07dc1947SRichard Lowe     struct mc_data_s *cur = base;
215*07dc1947SRichard Lowe 
216*07dc1947SRichard Lowe     for (; cur; cur = cur->mc_prev) {
217*07dc1947SRichard Lowe         if (cur->mc_address == newd->mc_address) {
218*07dc1947SRichard Lowe             if (cur->mc_type == MC_TYPE_ALLOC) {
219*07dc1947SRichard Lowe                 if (cur->mc_alloc_code == newd->mc_alloc_code) {
220*07dc1947SRichard Lowe                     *addr_match = cur;
221*07dc1947SRichard Lowe                     *addr_match_num = cur->mc_alloc_number;
222*07dc1947SRichard Lowe                     return cur->mc_alloc_number;
223*07dc1947SRichard Lowe                 } else {
224*07dc1947SRichard Lowe                     /* code mismatch */
225*07dc1947SRichard Lowe                     *addr_match = cur;
226*07dc1947SRichard Lowe                     *addr_match_num = cur->mc_alloc_number;
227*07dc1947SRichard Lowe                     return -1;
228*07dc1947SRichard Lowe                 }
229*07dc1947SRichard Lowe             } else {
230*07dc1947SRichard Lowe                 /* Unbalanced new/del */
231*07dc1947SRichard Lowe                 *addr_match = cur;
232*07dc1947SRichard Lowe                 *addr_match_num = cur->mc_alloc_number;
233*07dc1947SRichard Lowe                 return -1;
234*07dc1947SRichard Lowe             }
235*07dc1947SRichard Lowe         }
236*07dc1947SRichard Lowe     }
237*07dc1947SRichard Lowe     return -1;
238*07dc1947SRichard Lowe }
239*07dc1947SRichard Lowe 
240*07dc1947SRichard Lowe /*  A dealloc is to take place. Ensure it balances an alloc.
241*07dc1947SRichard Lowe */
242*07dc1947SRichard Lowe void
dwarf_malloc_check_dealloc_data(void * addr_in,unsigned char code)243*07dc1947SRichard Lowe dwarf_malloc_check_dealloc_data(void *addr_in, unsigned char code)
244*07dc1947SRichard Lowe {
245*07dc1947SRichard Lowe     struct mc_data_s *newd = newone();
246*07dc1947SRichard Lowe     long prev;
247*07dc1947SRichard Lowe     long addr_match_num = -1;
248*07dc1947SRichard Lowe     struct mc_data_s *addr_match = 0;
249*07dc1947SRichard Lowe     unsigned long addr = (unsigned long) addr_in;
250*07dc1947SRichard Lowe     struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
251*07dc1947SRichard Lowe 
252*07dc1947SRichard Lowe 
253*07dc1947SRichard Lowe     print_alloc_dealloc_detail(addr, code, "dealloc ");
254*07dc1947SRichard Lowe     newd->mc_address = (unsigned long) addr;
255*07dc1947SRichard Lowe     newd->mc_alloc_code = code;
256*07dc1947SRichard Lowe     newd->mc_type = MC_TYPE_DEALLOC;
257*07dc1947SRichard Lowe     newd->mc_prev = *base;
258*07dc1947SRichard Lowe     prev =
259*07dc1947SRichard Lowe         balanced_by_alloc_p(newd, &addr_match_num, &addr_match, *base);
260*07dc1947SRichard Lowe     if (prev < 0) {
261*07dc1947SRichard Lowe         fprintf(stderr,
262*07dc1947SRichard Lowe                 "Unbalanced dealloc at index %ld\n", mc_data_list_size);
263*07dc1947SRichard Lowe         print_entry("new", newd);
264*07dc1947SRichard Lowe         fprintf(stderr, "addr-match_num? %ld\n", addr_match_num);
265*07dc1947SRichard Lowe         if (addr_match) {
266*07dc1947SRichard Lowe             print_entry("prev entry", addr_match);
267*07dc1947SRichard Lowe             if (addr_match->mc_dealloc_noted > 1) {
268*07dc1947SRichard Lowe                 fprintf(stderr, "Above is Duplicate dealloc!\n");
269*07dc1947SRichard Lowe             }
270*07dc1947SRichard Lowe         }
271*07dc1947SRichard Lowe         abort();
272*07dc1947SRichard Lowe         exit(3);
273*07dc1947SRichard Lowe     }
274*07dc1947SRichard Lowe     addr_match->mc_dealloc_noted = 1;
275*07dc1947SRichard Lowe     addr_match->mc_dealloc_noted_count += 1;
276*07dc1947SRichard Lowe     if (addr_match->mc_dealloc_noted_count > 1) {
277*07dc1947SRichard Lowe         fprintf(stderr, "Double dealloc entry %ld\n", addr_match_num);
278*07dc1947SRichard Lowe         print_entry("new dealloc entry", newd);
279*07dc1947SRichard Lowe         print_entry("bad alloc entry", addr_match);
280*07dc1947SRichard Lowe     }
281*07dc1947SRichard Lowe     *base = newd;
282*07dc1947SRichard Lowe     mc_data_list_size += 1;
283*07dc1947SRichard Lowe }
284*07dc1947SRichard Lowe 
285*07dc1947SRichard Lowe /* Final check for leaks.
286*07dc1947SRichard Lowe */
287*07dc1947SRichard Lowe void
dwarf_malloc_check_complete(char * msg)288*07dc1947SRichard Lowe dwarf_malloc_check_complete(char *msg)
289*07dc1947SRichard Lowe {
290*07dc1947SRichard Lowe     long i = 0;
291*07dc1947SRichard Lowe     long total = mc_data_list_size;
292*07dc1947SRichard Lowe     long hash_slots_used = 0;
293*07dc1947SRichard Lowe     long max_chain_length = 0;
294*07dc1947SRichard Lowe 
295*07dc1947SRichard Lowe     fprintf(stderr, "Run complete, %s. %ld entries\n", msg, total);
296*07dc1947SRichard Lowe     for (; i < HASH_TABLE_SIZE; ++i) {
297*07dc1947SRichard Lowe         struct mc_data_s *cur = mc_data_hash[i];
298*07dc1947SRichard Lowe         long cur_chain_length = 0;
299*07dc1947SRichard Lowe 
300*07dc1947SRichard Lowe         if (cur == 0)
301*07dc1947SRichard Lowe             continue;
302*07dc1947SRichard Lowe         ++hash_slots_used;
303*07dc1947SRichard Lowe         for (; cur; cur = cur->mc_prev) {
304*07dc1947SRichard Lowe             ++cur_chain_length;
305*07dc1947SRichard Lowe             if (cur->mc_type == MC_TYPE_ALLOC) {
306*07dc1947SRichard Lowe                 if (cur->mc_dealloc_noted) {
307*07dc1947SRichard Lowe                     if (cur->mc_dealloc_noted > 1) {
308*07dc1947SRichard Lowe                         fprintf(stderr,
309*07dc1947SRichard Lowe                                 " Duplicate dealloc! entry %ld\n",
310*07dc1947SRichard Lowe                                 cur->mc_alloc_number);
311*07dc1947SRichard Lowe                         print_entry("duplicate dealloc", cur);
312*07dc1947SRichard Lowe 
313*07dc1947SRichard Lowe                     }
314*07dc1947SRichard Lowe                     continue;
315*07dc1947SRichard Lowe                 } else {
316*07dc1947SRichard Lowe                     fprintf(stderr, "malloc no dealloc, entry %ld\n",
317*07dc1947SRichard Lowe                             cur->mc_alloc_number);
318*07dc1947SRichard Lowe                     print_entry("dangle", cur);
319*07dc1947SRichard Lowe                 }
320*07dc1947SRichard Lowe             } else {
321*07dc1947SRichard Lowe                 /* mc_type is MC_TYPE_DEALLOC, already checked */
322*07dc1947SRichard Lowe 
323*07dc1947SRichard Lowe             }
324*07dc1947SRichard Lowe         }
325*07dc1947SRichard Lowe         if (cur_chain_length > max_chain_length) {
326*07dc1947SRichard Lowe             max_chain_length = cur_chain_length;
327*07dc1947SRichard Lowe         }
328*07dc1947SRichard Lowe     }
329*07dc1947SRichard Lowe     fprintf(stderr, "mc hash table slots=%ld, "
330*07dc1947SRichard Lowe             "used=%ld,  maxchain=%ld\n",
331*07dc1947SRichard Lowe             (long) HASH_TABLE_SIZE, hash_slots_used, max_chain_length);
332*07dc1947SRichard Lowe     return;
333*07dc1947SRichard Lowe }
334*07dc1947SRichard Lowe 
335*07dc1947SRichard Lowe #else
336*07dc1947SRichard Lowe 
337*07dc1947SRichard Lowe extern void *libdwarf_an_unused_function_so_not_empty_c_file();
338*07dc1947SRichard Lowe 
339*07dc1947SRichard Lowe #endif /* WANT_LIBBDWARF_MALLOC_CHECK */
340