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