1 /* 2 Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. 3 Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. 4 Portions Copyright 2011-2019. David Anderson. All Rights Reserved. 5 6 This program is free software; you can redistribute it 7 and/or modify it under the terms of version 2.1 of the 8 GNU Lesser General Public License as published by the Free 9 Software Foundation. 10 11 This program is distributed in the hope that it would be 12 useful, but WITHOUT ANY WARRANTY; without even the implied 13 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 14 PURPOSE. 15 16 Further, this software is distributed without any warranty 17 that it is free of the rightful claim of any third person 18 regarding infringement or the like. Any license provided 19 herein, whether implied or otherwise, applies only to this 20 software file. Patent licenses, if any, provided herein 21 do not apply to combinations of this program with other 22 software, or any other product whatsoever. 23 24 You should have received a copy of the GNU Lesser General 25 Public License along with this program; if not, write the 26 Free Software Foundation, Inc., 51 Franklin Street - Fifth 27 Floor, Boston MA 02110-1301, USA. 28 29 */ 30 31 #include "config.h" 32 #include "pro_incl.h" 33 #include <stddef.h> 34 #include "dwarf.h" 35 #include "libdwarf.h" 36 #include "pro_opaque.h" 37 #include "pro_alloc.h" 38 #ifdef HAVE_STDLIB_H 39 #include <stdlib.h> 40 #endif /* HAVE_STDLIB_H */ 41 #ifdef HAVE_MALLOC_H 42 /* Useful include for some Windows compilers. */ 43 #include <malloc.h> 44 #endif /* HAVE_MALLOC_H */ 45 #ifdef HAVE_STRING_H 46 #include <string.h> 47 #endif /* HAVE_STRING_H */ 48 #ifdef HAVE_STDINT_H 49 #include <stdint.h> /* For uintptr_t */ 50 #endif /* HAVE_STDINT_H */ 51 #ifdef HAVE_INTTYPES_H 52 #include <inttypes.h> 53 #endif /* HAVE_INTTYPES_H */ 54 #include "dwarf_tsearch.h" 55 56 /* When each block is allocated, there is a two-word structure 57 allocated at the beginning so the block can go on a list. 58 The address returned is the address *after* the two pointers 59 at the start. But this allows us to be given a pointer to 60 a generic block, and go backwards to find the list-node. Then 61 we can remove this block from it's list without the need to search 62 through a linked list in order to remove the node. It also allows 63 us to 'delete' a memory block without needing the dbg structure. 64 We still need the dbg structure on allocation so that we know which 65 linked list to add the block to. 66 67 Only the allocation of the dbg structure itself cannot use 68 _dwarf_p_get_alloc. 69 That structure should be set up by hand, and the two list pointers 70 should be initialized to point at the node itself. That initializes 71 the doubly linked list. */ 72 73 #define LIST_TO_BLOCK(lst) ((void*) (((char *)lst) + sizeof(memory_list_t))) 74 #define BLOCK_TO_LIST(blk) ((memory_list_t*) (((char*)blk) - sizeof(memory_list_t))) 75 76 77 /* 78 dbg should be NULL only when allocating dbg itself. In that 79 case we initialize it to an empty circular doubly-linked list. 80 */ 81 82 Dwarf_Ptr 83 _dwarf_p_get_alloc(Dwarf_P_Debug dbg, Dwarf_Unsigned size) 84 { 85 void *sp; 86 memory_list_t *lp = NULL; 87 memory_list_t *dbglp = NULL; 88 memory_list_t *nextblock = NULL; 89 90 /* alloc control struct and data block together for performance reasons */ 91 lp = (memory_list_t *) malloc(size + sizeof(memory_list_t)); 92 if (lp == NULL) { 93 /* should throw an error */ 94 return NULL; 95 } 96 97 /* point to 'size' bytes just beyond lp struct */ 98 sp = LIST_TO_BLOCK(lp); 99 memset(sp, 0, size); 100 101 if (dbg == NULL) { 102 lp->next = lp->prev = lp; 103 } else { 104 /* I always have to draw a picture to understand this part. */ 105 106 dbglp = BLOCK_TO_LIST(dbg); 107 nextblock = dbglp->next; 108 109 /* Insert between dbglp and nextblock */ 110 dbglp->next = lp; 111 lp->prev = dbglp; 112 lp->next = nextblock; 113 nextblock->prev = lp; 114 } 115 116 return sp; 117 } 118 119 /* 120 This routine is only here in case a caller of an older version of the 121 library is calling this for some reason. 122 This does nothing! 123 No need to remove this block. In theory the user might be 124 depending on the fact that we used to just 'free' this. 125 In theory they might also be 126 passing a block that they got from libdwarf. So we don't know if we 127 should try to remove this block from our global list. Safest just to 128 do nothing at this point. 129 130 !!! 131 This function is deprecated! Don't call it inside libdwarf or outside of it. 132 Does nothing! 133 !!! 134 */ 135 136 void 137 dwarf_p_dealloc(UNUSEDARG Dwarf_Small * ptr) 138 { 139 return; 140 } 141 142 /* 143 The dbg structure is not needed here anymore. 144 */ 145 146 void 147 _dwarf_p_dealloc(UNUSEDARG Dwarf_P_Debug dbg, 148 Dwarf_Small * ptr) /* ARGSUSED */ 149 { 150 memory_list_t *lp; 151 lp = BLOCK_TO_LIST(ptr); 152 153 /* Remove from a doubly linked, circular list. 154 Read carefully, use a white board if necessary. 155 If this is an empty list, the following statements are no-ops, and 156 will write to the same memory location they read from. 157 This should only happen when we deallocate the dbg structure itself. 158 */ 159 if (lp == lp->next) { 160 /* The list has a single item, itself. */ 161 lp->prev = 0; 162 lp->next = 0; 163 } else if (lp->next == lp->prev) { 164 /* List had exactly two entries. Reduce it to one, 165 cutting lp out. */ 166 memory_list_t * remaining = lp->next; 167 remaining->next = remaining; 168 remaining->prev = remaining; 169 } else { 170 /* Multi=entry. Just cut lp out. */ 171 lp->prev->next = lp->next; 172 lp->next->prev = lp->prev; 173 lp->prev = lp->next = 0; 174 } 175 free((void*)lp); 176 } 177 178 179 static void 180 _dwarf_str_hashtab_freenode(void * nodep) 181 { 182 free(nodep); 183 } 184 185 186 /* 187 This routine deallocates all the nodes on the dbg list, 188 and then deallocates the dbg structure itself. 189 */ 190 191 void 192 _dwarf_p_dealloc_all(Dwarf_P_Debug dbg) 193 { 194 memory_list_t *dbglp; 195 memory_list_t *base_dbglp; 196 197 if (dbg == NULL) { 198 /* should throw an error */ 199 return; 200 } 201 202 base_dbglp = BLOCK_TO_LIST(dbg); 203 dbglp = base_dbglp->next; 204 205 while (dbglp != base_dbglp) { 206 memory_list_t*next = dbglp->next; 207 208 _dwarf_p_dealloc(dbg, LIST_TO_BLOCK(dbglp)); 209 dbglp = next; 210 } 211 dwarf_tdestroy(dbg->de_debug_str_hashtab, 212 _dwarf_str_hashtab_freenode); 213 dwarf_tdestroy(dbg->de_debug_line_str_hashtab, 214 _dwarf_str_hashtab_freenode); 215 free((void *)base_dbglp); 216 } 217