1 /*  Copyright (c) 2019-2019, David Anderson
2     All rights reserved.
3 
4     Redistribution and use in source and binary forms, with
5     or without modification, are permitted provided that the
6     following conditions are met:
7 
8     Redistributions of source code must retain the above
9     copyright notice, this list of conditions and the following
10     disclaimer.
11 
12     Redistributions in binary form must reproduce the above
13     copyright notice, this list of conditions and the following
14     disclaimer in the documentation and/or other materials
15     provided with the distribution.
16 
17     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 
32 #include "config.h"
33 #include "libdwarfdefs.h"
34 #include <stdio.h>
35 #include <string.h>
36 #include <stddef.h>
37 #ifdef HAVE_STDINT_H
38 #include <stdint.h> /* For uintptr_t */
39 #endif /* HAVE_STDINT_H */
40 #include "pro_incl.h"
41 #include "dwarf.h"
42 #include "libdwarf.h"
43 #include "pro_opaque.h"
44 #include "dwarfstring.h"
45 
46 
47 
48 
49 /*  in the producer_init extras string.
50     Handles hex and decimal. Not octal.
51     Used a very small number of times, so performance
52     not an issue. */
53 
54 /*  err will be used...shortly */
55 static int
translatetosigned(char * s,Dwarf_Signed * v,UNUSEDARG int * err)56 translatetosigned(char *s,Dwarf_Signed *v, UNUSEDARG int *err)
57 {
58     unsigned char *cp = (unsigned char *)s;
59     unsigned char *digits = (unsigned char *)s;
60     int signmult = 1;
61     Dwarf_Signed l = 0;
62 
63     if (*cp == '0' &&
64         (*(cp+1) == 'x'|| (*(cp+1) == 'X'))) {
65         digits += 2;
66         cp = digits;
67         for( ; *cp; cp++) {
68             l = l << 4;
69             switch (*cp) {
70             case '0':
71             case '1':
72             case '2':
73             case '3':
74             case '4':
75             case '5':
76             case '6':
77             case '7':
78             case '8':
79             case '9':
80                 l += (*cp - '0');
81                 break;
82             case 'a':
83             case 'A':
84                 l += 10;
85                 break;
86             case 'b':
87             case 'B':
88                 l += 11;
89                 break;
90             case 'c':
91             case 'C':
92                 l += 12;
93                 break;
94             case 'd':
95             case 'D':
96                 l += 13;
97                 break;
98             case 'e':
99             case 'E':
100                 l += 14;
101                 break;
102             case 'f':
103             case 'F':
104                 l += 15;
105                 break;
106             default:
107 #ifdef TESTING
108                 printf("ERROR in hex string \"%s\" "
109                     "bad character 0x%x, line %d %s\n",
110                     s,*cp,__LINE__,__FILE__);
111 #endif
112                 *err = DW_DLE_HEX_STRING_ERROR;
113                 return DW_DLV_ERROR;
114             }
115         }
116         *v = l;
117         return DW_DLV_OK;
118     } else if (*cp == '-') {
119         signmult = -1;
120         digits ++;
121     }
122 
123     cp = digits;
124     for( ; *cp; cp++) {
125         l = l * 10;
126         switch (*cp) {
127         case '9':
128         case '8':
129         case '7':
130         case '6':
131         case '5':
132         case '4':
133         case '3':
134         case '2':
135         case '1':
136         case '0':
137             l +=  (*cp - '0');
138             break;
139         default:
140 #ifdef TESTING
141             printf("ERROR in decimal string \"%s\", "
142                 "bad character 0x%x, line %d %s\n",
143                 s,*cp,__LINE__,__FILE__);
144 #endif
145             *err = DW_DLE_DECIMAL_STRING_ERROR;
146             return DW_DLV_ERROR;
147         }
148     }
149     *v = signmult * l;
150     return DW_DLV_OK;
151 }
152 
153 static int
update_named_field(Dwarf_P_Debug dbg,dwarfstring * cmsname,dwarfstring * cmsvalue,int * err)154 update_named_field(Dwarf_P_Debug dbg, dwarfstring *cmsname,dwarfstring *cmsvalue,
155     int *err)
156 {
157     char *name = dwarfstring_string(cmsname);
158     char *value = dwarfstring_string(cmsvalue);
159     Dwarf_Signed v = 0;
160     int res;
161 
162     res = translatetosigned(value,&v,err);
163     if (res != DW_DLV_OK) {
164         return res;
165     }
166     if ( dwarfstring_strlen(cmsvalue) == 0) {
167         return DW_DLV_NO_ENTRY;
168     }
169 
170     /*  The value in the string is a number,
171         but always quite a small number. */
172     if (!strcmp(name,"default_is_stmt")) {
173         dbg->de_line_inits.pi_default_is_stmt = (unsigned)v;
174     } else if (!strcmp(name,"minimum_instruction_length")) {
175         dbg->de_line_inits.pi_minimum_instruction_length = (unsigned)v;
176     } else if (!strcmp(name,"maximum_operations_per_instruction")) {
177         dbg->de_line_inits.pi_maximum_operations_per_instruction = (unsigned)v;
178     } else if (!strcmp(name,"opcode_base")) {
179         dbg->de_line_inits.pi_opcode_base = (unsigned)v;
180     } else if (!strcmp(name,"line_base")) {
181         dbg->de_line_inits.pi_line_base = (int)v;
182     } else if (!strcmp(name,"line_range")) {
183         dbg->de_line_inits.pi_line_range = (int)v;
184     } else if (!strcmp(name,"linetable_version")) {
185         dbg->de_line_inits.pi_linetable_version = (unsigned)v;
186         dbg->de_output_version = (unsigned)v;
187     } else if (!strcmp(name,"segment_selector_size")) {
188         dbg->de_line_inits.pi_segment_selector_size = (unsigned)v;
189     } else if (!strcmp(name,"segment_size")) {
190         dbg->de_line_inits.pi_segment_size = (unsigned)v;
191     } else if (!strcmp(name,"address_size")) {
192         dbg->de_line_inits.pi_address_size = (unsigned)v;
193         dbg->de_pointer_size = (unsigned)v;
194     } else {
195 #ifdef TESTING
196         printf("ERROR  due to unknown string \"%s\", line %d %s\n",
197             name,__LINE__,__FILE__);
198 #endif
199         *err = DW_DLE_PRO_INIT_EXTRAS_UNKNOWN;
200         return DW_DLV_ERROR;
201     }
202     return DW_DLV_OK;
203 }
204 static int
update_named_value(Dwarf_P_Debug dbg,dwarfstring * cms,int * err)205 update_named_value(Dwarf_P_Debug dbg, dwarfstring*cms,
206     int *err)
207 {
208     char * str = dwarfstring_string(cms);
209     char *cp = str;
210     char * value_start = 0;
211     dwarfstring cmsname;
212     dwarfstring cmsvalue;
213     unsigned slen = 0;
214     int res = 0;
215 
216     dwarfstring_constructor(&cmsname);
217     dwarfstring_constructor(&cmsvalue);
218     for ( ; *cp && *cp != '=' && *cp != ' '; cp++) { }
219     if (! *cp) {
220         /* Ignore this, it's empty or has no =value clause */
221         dwarfstring_destructor(&cmsname);
222         dwarfstring_destructor(&cmsvalue);
223         /* FIXME *err */
224         return DW_DLV_NO_ENTRY;
225     }
226     if (*cp == ' ') {
227         /* Trailing spaces, no = is an input bug. */
228         dwarfstring_destructor(&cmsname);
229         dwarfstring_destructor(&cmsvalue);
230 #ifdef TESTING
231         printf("ERROR due to  trailing spaces before = in \"%s\", line %d %s\n",
232             cp,__LINE__,__FILE__);
233 #endif
234         *err = DW_DLE_PRO_INIT_EXTRAS_ERR;
235         return DW_DLV_ERROR;
236     }
237     slen = cp - str;
238     dwarfstring_append_length(&cmsname,str,slen);
239     cp++;
240     value_start = cp;
241     for ( ; *cp && *cp != ' '; cp++) { }
242     slen = cp - value_start;
243     if (slen) {
244         dwarfstring_append_length(&cmsvalue,value_start,slen);
245     } else {
246         dwarfstring_destructor(&cmsname);
247         dwarfstring_destructor(&cmsvalue);
248         return DW_DLV_NO_ENTRY;
249     }
250     res = update_named_field(dbg,&cmsname,&cmsvalue,err);
251     dwarfstring_destructor(&cmsname);
252     dwarfstring_destructor(&cmsvalue);
253     return res;
254 }
255 
256 static int
find_next_comma(const char * base,const char ** nextcomma)257 find_next_comma(const char *base,const char **nextcomma)
258 {
259     const char *cp = base;
260     for( ; *cp ; ++cp) {
261         if (*cp == ',') {
262             *nextcomma = cp;
263             return DW_DLV_OK;
264         }
265     }
266     /*  Encountered end of string, should not happen as
267         we ensured a last string. */
268     *nextcomma = cp;
269     return DW_DLV_OK;
270 }
271 
272 /*  Publicly visible in in libdwarf to enable easy testing
273     of the code here. */
274 int
_dwarf_log_extra_flagstrings(Dwarf_P_Debug dbg,const char * extra,int * err)275 _dwarf_log_extra_flagstrings(Dwarf_P_Debug dbg,
276   const char *extra,
277   int *err)
278 {
279     int res = 0;
280     const char *nextcharloc = 0;
281     const char *nextcomma = 0;
282     dwarfstring cms;
283     dwarfstring input;
284 
285     if (!extra || !*extra) {
286         /* Nothing to do. */
287         return DW_DLV_NO_ENTRY;
288     }
289 
290     dwarfstring_constructor(&cms);
291     dwarfstring_constructor(&input);
292     dwarfstring_append(&input,(char *)extra);
293     /*  Adding a final , simplifies logic here. */
294     dwarfstring_append(&input,(char *)",");
295     nextcharloc = dwarfstring_string(&input);
296     while (1) {
297         dwarfstring_reset(&cms);
298         find_next_comma(nextcharloc,&nextcomma);
299         {
300             unsigned len = nextcomma - nextcharloc;
301             if (len > 0) {
302                 dwarfstring_append_length(&cms,(char *)nextcharloc,
303                     len);
304                 res = update_named_value(dbg,&cms,err);
305                 if (res == DW_DLV_ERROR) {
306                     dwarfstring_destructor(&cms);
307                     dwarfstring_destructor(&input);
308                     return res;
309                 }
310             }  else {/* else empty, */
311             }
312             if (!(nextcomma[1])) {
313                 dwarfstring_destructor(&cms);
314                 dwarfstring_destructor(&input);
315                 return DW_DLV_OK;
316             }
317             nextcharloc = nextcomma+1;
318         }
319     }
320     dwarfstring_destructor(&input);
321     dwarfstring_destructor(&cms);
322     return DW_DLV_OK;
323 }
324 
325 /* ===== end  Initialization using string=value,string2=valu2 (etc) */
326