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
_dwarf_p_get_alloc(Dwarf_P_Debug dbg,Dwarf_Unsigned size)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
dwarf_p_dealloc(UNUSEDARG Dwarf_Small * ptr)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
_dwarf_p_dealloc(UNUSEDARG Dwarf_P_Debug dbg,Dwarf_Small * ptr)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
_dwarf_str_hashtab_freenode(void * nodep)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
_dwarf_p_dealloc_all(Dwarf_P_Debug dbg)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