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