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