1 /*
2 
3   Copyright (C) 2015-2015 David Anderson. All Rights Reserved.
4 
5   This program is free software; you can redistribute it
6   and/or modify it under the terms of version 2.1 of the
7   GNU Lesser General Public License as published by the Free
8   Software Foundation.
9 
10   This program is distributed in the hope that it would be
11   useful, but WITHOUT ANY WARRANTY; without even the implied
12   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13   PURPOSE.
14 
15   Further, this software is distributed without any warranty
16   that it is free of the rightful claim of any third person
17   regarding infringement or the like.  Any license provided
18   herein, whether implied or otherwise, applies only to this
19   software file.  Patent licenses, if any, provided herein
20   do not apply to combinations of this program with other
21   software, or any other product whatsoever.
22 
23   You should have received a copy of the GNU Lesser General
24   Public License along with this program; if not, write the
25   Free Software Foundation, Inc., 51 Franklin Street - Fifth
26   Floor, Boston MA 02110-1301, USA.
27 
28 */
29 
30 #include "config.h"
31 #include "dwarf_incl.h"
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h> /* for free(). */
34 #endif /* HAVE_STDLIB_H */
35 #ifdef HAVE_MALLOC_H
36 /* Useful include for some Windows compilers. */
37 #include <malloc.h>
38 #endif /* HAVE_MALLOC_H */
39 #include <stdio.h> /* For debugging. */
40 #ifdef HAVE_STDINT_H
41 #include <stdint.h> /* For uintptr_t */
42 #endif /* HAVE_STDINT_H */
43 #include "dwarf_tsearch.h"
44 #include "dwarf_tied_decls.h"
45 
46 #define TRUE  1
47 #define FALSE 0
48 
49 
50 void
_dwarf_dumpsig(const char * msg,Dwarf_Sig8 * sig,int lineno)51 _dwarf_dumpsig(const char *msg, Dwarf_Sig8 *sig,int lineno)
52 {
53     const char *sigv = 0;
54     unsigned u = 0;
55 
56     printf("%s 0x",msg);
57     sigv = &sig->signature[0];
58     for (u = 0; u < 8; u++) {
59         printf("%02x",0xff&sigv[u]);
60     }
61     printf(" line %d\n",lineno);
62 }
63 
64 void *
_dwarf_tied_make_entry(Dwarf_Sig8 * key,Dwarf_CU_Context val)65 _dwarf_tied_make_entry(Dwarf_Sig8 *key, Dwarf_CU_Context val)
66 {
67     struct Dwarf_Tied_Entry_s *e = 0;
68     e = calloc(1,sizeof(struct Dwarf_Tied_Entry_s));
69     if(e) {
70         e->dt_key =    *key;
71         e->dt_context = val;
72     }
73     return e;
74 }
75 
76 
77 /*  Tied data Key is Dwarf_Sig8.
78     A hash needed because we are using a hash search
79     here. Would not be needed for the other tree searchs
80     like balanced trees..  */
81 DW_TSHASHTYPE
_dwarf_tied_data_hashfunc(const void * keyp)82 _dwarf_tied_data_hashfunc(const void *keyp)
83 {
84     const struct Dwarf_Tied_Entry_s * enp = keyp;
85     DW_TSHASHTYPE hashv = 0;
86     /* Just take some of the 8 bytes of the signature. */
87     memcpy(&hashv,enp->dt_key.signature,sizeof(hashv));
88     return hashv;
89 }
90 
91 int
_dwarf_tied_compare_function(const void * l,const void * r)92 _dwarf_tied_compare_function(const void *l, const void *r)
93 {
94     const struct Dwarf_Tied_Entry_s * lp = l;
95     const struct Dwarf_Tied_Entry_s * rp = r;
96     const char *lcp = (const char *)&lp->dt_key.signature;
97     const char *rcp = (const char *)&rp->dt_key.signature;
98     const char *lcpend = lcp + sizeof(Dwarf_Sig8);
99 
100     for(; lcp < lcpend; ++lcp,++rcp) {
101         if (*lcp < *rcp) {
102             return -1;
103         } else  if (*lcp > *rcp) {
104             return 1;
105         }
106     }
107     /* match. */
108     return 0;
109 }
110 
111 
112 void
_dwarf_tied_destroy_free_node(void * nodep)113 _dwarf_tied_destroy_free_node(void*nodep)
114 {
115     struct Dwarf_Tied_Entry_s * enp = nodep;
116     free(enp);
117     return;
118 }
119 
120 
121 /*  This presumes only we are reading the debug_info
122     CUs from tieddbg. That is a reasonable
123     requirement, one hopes.
124     Currently it reads all the tied CUs at once, unless
125     there is an error..
126     */
127 int
_dwarf_loop_reading_debug_info_for_cu(Dwarf_Debug tieddbg,Dwarf_Sig8 sig,Dwarf_Error * error)128 _dwarf_loop_reading_debug_info_for_cu(
129     Dwarf_Debug tieddbg,
130     Dwarf_Sig8 sig,
131     Dwarf_Error *error)
132 {
133     unsigned loop_count = 0;
134     /*  We will not find tied signatures
135         for .debug_addr (or line tables) in .debug_types.
136         it seems. Those signatures point from
137         'normal' to 'dwo/dwp'  (DWARF4) */
138     int is_info = TRUE;
139     Dwarf_CU_Context startingcontext = 0;
140     Dwarf_Unsigned next_cu_offset = 0;
141 
142     startingcontext = tieddbg->de_info_reading.de_cu_context;
143 
144     if (startingcontext) {
145         next_cu_offset =
146             startingcontext->cc_debug_offset +
147             startingcontext->cc_length +
148             startingcontext->cc_length_size +
149             startingcontext->cc_extension_size;
150     }
151 
152     for (;;++loop_count) {
153         int sres = DW_DLV_OK;
154         Dwarf_Half cu_type = 0;
155         Dwarf_CU_Context latestcontext = 0;
156         Dwarf_Unsigned cu_header_length = 0;
157         Dwarf_Unsigned abbrev_offset = 0;
158         Dwarf_Half version_stamp = 0;
159         Dwarf_Half address_size = 0;
160         Dwarf_Half extension_size = 0;
161         Dwarf_Half length_size = 0;
162         Dwarf_Sig8 signature;
163         Dwarf_Bool has_signature = FALSE;
164         Dwarf_Unsigned typeoffset = 0;
165 
166 
167         memset(&signature,0,sizeof(signature));
168         sres = _dwarf_next_cu_header_internal(tieddbg,
169             is_info,
170             &cu_header_length, &version_stamp,
171             &abbrev_offset, &address_size,
172             &length_size,&extension_size,
173             &signature, &has_signature,
174             &typeoffset,
175             &next_cu_offset,
176             &cu_type, error);
177         if (sres == DW_DLV_NO_ENTRY) {
178             break;
179         }
180 
181         latestcontext = tieddbg->de_info_reading.de_cu_context;
182 
183         if (has_signature) {
184             void *retval = 0;
185             Dwarf_Sig8 consign =
186                 latestcontext->cc_signature;
187             void *entry =
188                 _dwarf_tied_make_entry(&consign,latestcontext);
189 
190             if (!entry) {
191                 return DW_DLV_NO_ENTRY;
192             }
193             /* Insert this signature and context. */
194             retval = dwarf_tsearch(entry,
195                 &tieddbg->de_tied_data.td_tied_search,
196                 _dwarf_tied_compare_function);
197             if (!retval) {
198                 /* FAILED might be out of memory.*/
199                 return DW_DLV_NO_ENTRY;
200             }
201 #if 0 /* FIXME: do this? Not? */
202             /*  This could be a compiler error. But
203                 let us not decide?  FIXME */
204             if (!latestcontext->cc_addr_base_present) {
205             }
206 #endif
207             if (!_dwarf_tied_compare_function(&sig,&consign) ) {
208                 /*  Identical. We found the matching CU. */
209                 return DW_DLV_OK;
210             }
211         }
212     }
213     /*  Apparently we never found the sig we are looking for.
214         Pretend ok.  Caller will check for success. */
215     return DW_DLV_OK;
216 }
217 
218 
219 /* If out of memory just return DW_DLV_NO_ENTRY.
220 */
221 int
_dwarf_search_for_signature(Dwarf_Debug tieddbg,Dwarf_Sig8 sig,Dwarf_CU_Context * context_out,Dwarf_Error * error)222 _dwarf_search_for_signature(Dwarf_Debug tieddbg,
223     Dwarf_Sig8 sig,
224     Dwarf_CU_Context *context_out,
225     Dwarf_Error *error)
226 {
227 
228     void *entry2 = 0;
229     struct Dwarf_Tied_Entry_s entry;
230     struct Dwarf_Tied_Data_s * tied = &tieddbg->de_tied_data;
231     int res = 0;
232 
233     if (!tied->td_tied_search) {
234         dwarf_initialize_search_hash(&tied->td_tied_search,
235             _dwarf_tied_data_hashfunc,0);
236         if (!tied->td_tied_search) {
237             return DW_DLV_NO_ENTRY;
238         }
239     }
240     entry.dt_key = sig;
241     entry.dt_context = 0;
242     entry2 = dwarf_tfind(&entry,
243         &tied->td_tied_search,
244         _dwarf_tied_compare_function);
245     if (entry2) {
246         struct Dwarf_Tied_Entry_s *e2 =
247             *(struct Dwarf_Tied_Entry_s **)entry2;
248         *context_out = e2->dt_context;
249         return DW_DLV_OK;
250     }
251 
252     /*  We assume the caller is NOT doing
253         info section read operations
254         on the tieddbg.  */
255     res  = _dwarf_loop_reading_debug_info_for_cu(
256         tieddbg,sig,error);
257     if (res == DW_DLV_ERROR) {
258         return res;
259     }
260     entry2 = dwarf_tfind(&entry,
261         &tied->td_tied_search,
262         _dwarf_tied_compare_function);
263     if (entry2) {
264         struct Dwarf_Tied_Entry_s *e2 =
265             *(struct Dwarf_Tied_Entry_s **)entry2;
266         *context_out = e2->dt_context;
267         return DW_DLV_OK;
268     }
269     return DW_DLV_NO_ENTRY;
270 }
271