1 /*
2 Copyright (c) 2019-2020, David Anderson
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with
6 or without modification, are permitted provided that the
7 following conditions are met:
8
9 Redistributions of source code must retain the above
10 copyright notice, this list of conditions and the following
11 disclaimer.
12
13 Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following
15 disclaimer in the documentation and/or other materials
16 provided with the distribution.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
31
32 #include "config.h"
33 #include <stdio.h>
34 #ifdef HAVE_MALLOC_H
35 #include <malloc.h>
36 #endif /* HAVE_MALLOC_H */
37 #ifdef HAVE_STDDEF_H
38 #include <stddef.h> /* ptrdiff_t */
39 #endif /* HAVE_STDDEF_H */
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif /* HAVE_STDLIB_H */
43 #include <string.h>
44 #ifdef HAVE_ELF_H
45 #include <elf.h>
46 #endif /* HAVE_ELF_H */
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h> /* getcwd */
49 #endif /* HAVE_UNISTD_H */
50 #if 0
51 #include <sys/types.h> /* for open() */
52 #include <sys/stat.h> /* for open() */
53 #include <fcntl.h> /* for open() */
54 #include <errno.h>
55 #endif
56 #include "dwarf_incl.h"
57 #include "dwarf_alloc.h"
58 #include "dwarf_error.h"
59 #include "dwarf_util.h"
60 #include "dwarfstring.h"
61 #include "dwarf_debuglink.h"
62
63 #ifndef O_BINARY
64 #define O_BINARY 0
65 #endif /* O_BINARY */
66
67 #define MINBUFLEN 1000
68 #define TRUE 1
69 #define FALSE 0
70
71 #ifdef HAVE_UNUSED_ATTRIBUTE
72 #define UNUSEDARG __attribute__ ((unused))
73 #else
74 #define UNUSEDARG
75 #endif
76
77
78 #if _WIN32
79 #define NULL_DEVICE_NAME "NUL"
80 #else
81 #define NULL_DEVICE_NAME "/dev/null"
82 #endif /* _WIN32 */
83
84 #ifdef WORDS_BIGENDIAN
85 #define ASNAR(func,t,s) \
86 do { \
87 unsigned tbyte = sizeof(t) - sizeof(s); \
88 t = 0; \
89 func(((char *)&t)+tbyte ,&s[0],sizeof(s)); \
90 } while (0)
91 #else /* LITTLE ENDIAN */
92 #define ASNAR(func,t,s) \
93 do { \
94 t = 0; \
95 func(&t,&s[0],sizeof(s)); \
96 } while (0)
97 #endif /* end LITTLE- BIG-ENDIAN */
98
99 static int
100 extract_buildid(Dwarf_Debug dbg,
101 struct Dwarf_Section_s * pbuildid,
102 unsigned *type_returned,
103 char **owner_name_returned,
104 unsigned char **build_id_returned,
105 unsigned *build_id_length_returned,
106 Dwarf_Error *error);
107
108 struct joins_s {
109 char * js_fullpath;
110 dwarfstring js_dirname;
111 dwarfstring js_basepath;
112 dwarfstring js_basename;
113 dwarfstring js_cwd;
114 dwarfstring js_originalfullpath;
115 dwarfstring js_tmp;
116 dwarfstring js_tmp2;
117 dwarfstring js_tmpdeb;
118 dwarfstring js_tmp3;
119 dwarfstring js_buildid;
120 dwarfstring js_buildid_filename;
121 };
122
123 #if 0
124 int
125 _dwarf_check_string_valid(
126 void *areaptr,
127 void *strptr,
128 void *areaendptr,
129 int suggested_error,
130 int *errcode)
131 {
132 Dwarf_Small *start = areaptr;
133 Dwarf_Small *p = strptr;
134 Dwarf_Small *end = areaendptr;
135 ptrdiff_t diff = 0;
136
137 if (p < start) {
138 diff = start - p;
139 #ifdef TESTING
140 printf("Error string start pointer error: loc %"
141 DW_PR_DSs
142 " bytes before available area \n",(Dwarf_Signed)diff);
143 #endif /* TESTING */
144 *errcode = suggested_error;
145 return DW_DLV_ERROR;
146 }
147 if (p >= end) {
148 diff = p - start;
149 #ifdef TESTING
150 printf("Error string end pointer error, not terminated %"
151 " before end of area. Length: "
152 DW_PR_DSs "\n",(Dwarf_Signed)diff);
153 #endif /* TESTING */
154 *errcode = suggested_error;
155 return DW_DLV_ERROR;
156 }
157 while (p < end) {
158 if (*p == 0) {
159 return DW_DLV_OK;
160 }
161 ++p;
162 }
163 diff = p - start;
164 #ifdef TESTING
165 printf("Error string not terminated error: not ended after %"
166 DW_PR_DSs " bytes (past end of available bytes)\n",
167 (Dwarf_Signed)diff);
168 #endif /* TESTING */
169 *errcode = DW_DLE_STRING_NOT_TERMINATED;
170 return DW_DLV_ERROR;
171 }
172 #endif
173
174
175 #if 0
176 static int
177 does_file_exist(char *f)
178 {
179 int fd = 0;
180
181 fd = open(f,O_RDONLY|O_BINARY);
182 if (fd < 0) {
183 return DW_DLV_NO_ENTRY;
184 }
185 /* Here we could derive the crc to validate the file. */
186 close(fd);
187 return DW_DLV_OK;
188 }
189 #endif
190
191
192 static void
construct_js(struct joins_s * js)193 construct_js(struct joins_s * js)
194 {
195 memset(js,0,sizeof(struct joins_s));
196 dwarfstring_constructor(&js->js_basename);
197 dwarfstring_constructor(&js->js_dirname);
198 dwarfstring_constructor(&js->js_basepath);
199 dwarfstring_constructor(&js->js_cwd);
200 dwarfstring_constructor(&js->js_originalfullpath);
201 dwarfstring_constructor(&js->js_tmp);
202 dwarfstring_constructor(&js->js_tmp2);
203 dwarfstring_constructor(&js->js_tmpdeb);
204 dwarfstring_constructor(&js->js_tmp3);
205 dwarfstring_constructor(&js->js_buildid);
206 dwarfstring_constructor(&js->js_buildid_filename);
207 }
208 static void
destruct_js(struct joins_s * js)209 destruct_js(struct joins_s * js)
210 {
211 dwarfstring_destructor(&js->js_dirname);
212 dwarfstring_destructor(&js->js_basepath);
213 dwarfstring_destructor(&js->js_basename);
214 dwarfstring_destructor(&js->js_cwd);
215 dwarfstring_destructor(&js->js_originalfullpath);
216 dwarfstring_destructor(&js->js_tmp);
217 dwarfstring_destructor(&js->js_tmp2);
218 dwarfstring_destructor(&js->js_tmpdeb);
219 dwarfstring_destructor(&js->js_tmp3);
220 dwarfstring_destructor(&js->js_buildid);
221 dwarfstring_destructor(&js->js_buildid_filename);
222 }
223
224 static char joinchar = '/';
225 static char* joinstr = "/";
226
227 int
_dwarf_pathjoinl(dwarfstring * target,dwarfstring * input)228 _dwarf_pathjoinl(dwarfstring *target,dwarfstring * input)
229 {
230 char *inputs = dwarfstring_string(input);
231 char *targ = dwarfstring_string(target);
232 size_t targlen = 0;
233
234 if (!dwarfstring_strlen(target)) {
235 dwarfstring_append(target,dwarfstring_string(input));
236 return DW_DLV_OK;
237 }
238 targlen = dwarfstring_strlen(target);
239 targ = dwarfstring_string(target);
240 if (targ[targlen-1] != joinchar) {
241 if (*inputs != joinchar) {
242 dwarfstring_append(target,joinstr);
243 dwarfstring_append(target,inputs);
244 } else {
245 dwarfstring_append(target,inputs);
246 }
247 } else {
248 if (*inputs != joinchar) {
249 dwarfstring_append(target,inputs);
250 } else {
251 dwarfstring_append(target,inputs+1);
252 }
253 }
254 return DW_DLV_OK;
255 }
256 /* ASSERT: the last character in s is not a / */
257 static size_t
mydirlen(char * s)258 mydirlen(char *s)
259 {
260 char *cp = 0;
261 char *lastjoinchar = 0;
262 size_t count =0;
263
264 for(cp = s ; *cp ; ++cp,++count) {
265 if (*cp == joinchar) {
266 lastjoinchar = cp;
267 }
268 }
269 if (lastjoinchar) {
270 /* we know diff is postive in all cases */
271 ptrdiff_t diff = lastjoinchar - s;
272 /* count the last join as mydirlen. */
273 return (size_t)(diff+1);
274 }
275 return 0;
276 }
277
278 struct dwarfstring_list_s {
279 dwarfstring dl_string;
280 struct dwarfstring_list_s *dl_next;
281 };
282
283 static void
dwarfstring_list_constructor(struct dwarfstring_list_s * l)284 dwarfstring_list_constructor(struct dwarfstring_list_s *l)
285 {
286 dwarfstring_constructor(&l->dl_string);
287 l->dl_next = 0;
288 }
289
290 static int
dwarfstring_list_add_new(struct dwarfstring_list_s * base_entry,struct dwarfstring_list_s * prev,dwarfstring * input,struct dwarfstring_list_s ** new_out,int * errcode)291 dwarfstring_list_add_new(struct dwarfstring_list_s * base_entry,
292 struct dwarfstring_list_s *prev,
293 dwarfstring * input,
294 struct dwarfstring_list_s ** new_out,
295 int *errcode)
296 {
297 struct dwarfstring_list_s *next = 0;
298 if(prev) {
299 next = ( struct dwarfstring_list_s *)
300 malloc(sizeof(struct dwarfstring_list_s));
301 if (!next) {
302 *errcode = DW_DLE_ALLOC_FAIL;
303 return DW_DLV_ERROR;
304 }
305 dwarfstring_list_constructor(next);
306 } else {
307 next = base_entry;
308 }
309 dwarfstring_append(&next->dl_string,
310 dwarfstring_string(input));
311 if (prev) {
312 prev->dl_next = next;
313 }
314 *new_out = next;
315 return DW_DLV_OK;
316 }
317
318 /* destructs passed in entry (does not free it) and all
319 those on the dl_next list (those are freed). */
320 static void
dwarfstring_list_destructor(struct dwarfstring_list_s * l)321 dwarfstring_list_destructor(struct dwarfstring_list_s *l)
322 {
323 struct dwarfstring_list_s *curl = l;
324 struct dwarfstring_list_s *nextl = l;
325
326 nextl = curl->dl_next;
327 dwarfstring_destructor(&curl->dl_string);
328 curl->dl_next = 0;
329 curl = nextl;
330 for( ; curl ; curl = nextl) {
331 nextl = curl->dl_next;
332 dwarfstring_destructor(&curl->dl_string);
333 curl->dl_next = 0;
334 free(curl);
335 }
336 }
337
338 static void
build_buildid_filename(dwarfstring * target,unsigned buildid_length,unsigned char * buildid)339 build_buildid_filename(dwarfstring *target,
340 unsigned buildid_length,
341 unsigned char *buildid)
342 {
343 dwarfstring tmp;
344 unsigned bu = 0;
345 unsigned char *cp = 0;
346
347 dwarfstring_constructor(&tmp);
348 cp = buildid;
349 for (bu = 0; bu < buildid_length; ++bu ,++cp) {
350 dwarfstring_append_printf_u(&tmp, "%02x",*cp);
351 if (bu == 0) {
352 dwarfstring_append(&tmp,"/");
353 }
354 }
355 dwarfstring_append(&tmp,".debug");
356 _dwarf_pathjoinl(target,&tmp);
357 dwarfstring_destructor(&tmp);
358 return;
359 }
360
361 #if 0
362 static void
363 dump_bytes(const char *msg,unsigned char * start, unsigned len)
364 {
365 Dwarf_Small *end = start + len;
366 Dwarf_Small *cur = start;
367 printf("%s (0x%lx) ",msg,(unsigned long)start);
368 for (; cur < end; cur++) {
369 printf("%02x", *cur);
370 }
371 printf("\n");
372 }
373 #endif
374
375
376 /* New September 2019. Access to the GNU section named
377 .gnu_debuglink
378 See
379 https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
380
381 */
_dwarf_construct_linkedto_path(char ** global_prefixes_in,unsigned length_global_prefixes_in,char * pathname_in,char * link_string_in,dwarfstring * link_string_fullpath_out,UNUSEDARG unsigned char * crc_in,unsigned char * buildid,unsigned buildid_length,char *** paths_out,unsigned * paths_out_length,int * errcode)382 int _dwarf_construct_linkedto_path(
383 char **global_prefixes_in,
384 unsigned length_global_prefixes_in,
385 char *pathname_in,
386 char *link_string_in, /* from debug link */
387 dwarfstring * link_string_fullpath_out,
388 UNUSEDARG unsigned char *crc_in, /* from debug_link, 4 bytes */
389 unsigned char *buildid, /* from gnu buildid */
390 unsigned buildid_length, /* from gnu buildid */
391 char ***paths_out,
392 unsigned *paths_out_length,
393 int *errcode)
394 {
395 char * depath = pathname_in;
396 int res = 0;
397 struct joins_s joind;
398 size_t dirnamelen = 0;
399 struct dwarfstring_list_s base_dwlist;
400 struct dwarfstring_list_s *last_entry = 0;
401 unsigned global_prefix_number = 0;
402
403 dwarfstring_list_constructor(&base_dwlist);
404 construct_js(&joind);
405 build_buildid_filename(&joind.js_buildid_filename,
406 buildid_length, buildid);
407 dirnamelen = mydirlen(depath);
408 if (dirnamelen) {
409 dwarfstring_append_length(&joind.js_dirname,
410 depath,dirnamelen);
411 }
412 dwarfstring_append(&joind.js_basepath,depath+dirnamelen);
413 dwarfstring_append(&joind.js_basename,link_string_in);
414 if (depath[0] != joinchar) {
415 char buffer[2000];
416 #ifdef TESTING
417 buffer[0] = 0;
418 /* For testing lets use a fake (consistent)
419 base dir. */
420 strcpy(buffer,"/fake/dir/path");
421 #else
422 unsigned buflen= sizeof(buffer);
423 char *wdret = 0;
424
425 buffer[0] = 0;
426 wdret = getcwd(buffer,buflen);
427 if (!wdret) {
428 printf("getcwd() issue. Do nothing. "
429 " line %d %s\n",__LINE__,__FILE__);
430 dwarfstring_list_destructor(&base_dwlist);
431 destruct_js(&joind);
432 *errcode = DW_DLE_ALLOC_FAIL;
433 return DW_DLV_ERROR;
434 }
435 #endif /* TESTING */
436 dwarfstring_append(&joind.js_cwd,buffer);
437 buffer[0] = 0;
438 }
439
440 {
441 /* Builds the full path to the original
442 executable, but absent executable name. */
443 dwarfstring_append(&joind.js_originalfullpath,
444 dwarfstring_string(&joind.js_cwd));
445 _dwarf_pathjoinl(&joind.js_originalfullpath,
446 &joind.js_dirname);
447 _dwarf_pathjoinl(&joind.js_originalfullpath,
448 &joind.js_basepath);
449 #ifdef TESTING
450 printf("originalfullpath : %s\n",
451 dwarfstring_string(&joind.js_originalfullpath));
452 #endif
453 }
454 {
455 /* There is perhaps a directory prefix in the
456 incoming pathname.
457 So we add that to js_cwd. */
458 res = _dwarf_pathjoinl(&joind.js_cwd,
459 &joind.js_dirname);
460 /* This is used in a couple search paths. */
461 }
462 for (global_prefix_number = 0;
463 buildid_length &&
464 (global_prefix_number < length_global_prefixes_in);
465 ++global_prefix_number) {
466 char * prefix = 0;
467
468 prefix = global_prefixes_in[global_prefix_number];
469 dwarfstring_reset(&joind.js_buildid);
470 dwarfstring_append(&joind.js_buildid,prefix);
471 _dwarf_pathjoinl(&joind.js_buildid,
472 &joind.js_buildid_filename);
473 if (!strcmp(dwarfstring_string(&joind.js_originalfullpath),
474 dwarfstring_string(&joind.js_buildid))) {
475 #ifdef TESTING
476 printf("duplicated output string %s\n",
477 dwarfstring_string(&joind.js_buildid));
478 #endif /* TESTING */
479 /* duplicated name. spurious match. */
480 } else {
481 struct dwarfstring_list_s *now_last = 0;
482 res = dwarfstring_list_add_new(
483 &base_dwlist,
484 last_entry,&joind.js_buildid,
485 &now_last,errcode);
486 if(res != DW_DLV_OK) {
487 dwarfstring_list_destructor(&base_dwlist);
488 destruct_js(&joind);
489 return res;
490 }
491 last_entry = now_last;
492 }
493 }
494 if (link_string_in) {
495 /* js_cwd is a leading / directory name. */
496 {
497 dwarfstring_reset(&joind.js_tmp);
498 dwarfstring_append(&joind.js_tmp,
499 dwarfstring_string(&joind.js_cwd));
500 /* If we add basename do we find what we look for? */
501 res = _dwarf_pathjoinl(&joind.js_tmp,&joind.js_basename);
502 /* We return the original link as full path this way. */
503 dwarfstring_append(link_string_fullpath_out,
504 dwarfstring_string(&joind.js_tmp));
505 if (!strcmp(dwarfstring_string(&joind.js_originalfullpath),
506 dwarfstring_string(&joind.js_tmp))) {
507 #ifdef TESTING
508 printf("duplicated output string %s\n",
509 dwarfstring_string(&joind.js_tmp));
510 #endif /* TESTING */
511 /* duplicated name. spurious match. */
512 } else if (res == DW_DLV_OK) {
513 struct dwarfstring_list_s *now_last = 0;
514 res = dwarfstring_list_add_new(
515 &base_dwlist,
516 last_entry,&joind.js_tmp,
517 &now_last,errcode);
518 if(res != DW_DLV_OK) {
519 dwarfstring_list_destructor(&base_dwlist);
520 destruct_js(&joind);
521 return res;
522 }
523 last_entry = now_last;
524 }
525 }
526 {
527 dwarfstring_reset(&joind.js_tmp2);
528 dwarfstring_reset(&joind.js_tmpdeb);
529
530 dwarfstring_append(&joind.js_tmp2,
531 dwarfstring_string(&joind.js_cwd));
532 dwarfstring_append(&joind.js_tmpdeb,".debug");
533 res = _dwarf_pathjoinl(&joind.js_tmp2,&joind.js_tmpdeb);
534 if (res == DW_DLV_OK) {
535 res = _dwarf_pathjoinl(&joind.js_tmp2,
536 &joind.js_basename);
537 /* this the second search path
538 after global directories
539 search for nn/nnnnn....debug. */
540 if (!strcmp(dwarfstring_string(
541 &joind.js_originalfullpath),
542 dwarfstring_string(&joind.js_tmp2))) {
543 #ifdef TESTING
544 printf("duplicated output string %s\n",
545 dwarfstring_string(&joind.js_tmp2));
546 #endif /* TESTING */
547 /* duplicated name. spurious match. */
548 } else if(res == DW_DLV_OK) {
549 struct dwarfstring_list_s *now_last = 0;
550 res = dwarfstring_list_add_new(
551 &base_dwlist,
552 last_entry,&joind.js_tmp2,
553 &now_last,errcode);
554 if(res != DW_DLV_OK) {
555 dwarfstring_list_destructor(&base_dwlist);
556 destruct_js(&joind);
557 return res;
558 }
559 last_entry = now_last;
560 }
561 }
562 }
563 /* Not found above, now look in the global locations. */
564 for (global_prefix_number = 0;
565 global_prefix_number < length_global_prefixes_in;
566 ++global_prefix_number) {
567 char * prefix = global_prefixes_in[global_prefix_number];
568
569 dwarfstring_reset(&joind.js_tmp3);
570 dwarfstring_append(&joind.js_tmp3, prefix);
571 res = _dwarf_pathjoinl(&joind.js_tmp3, &joind.js_cwd);
572 if (res == DW_DLV_OK) {
573 res = _dwarf_pathjoinl(&joind.js_tmp3,
574 &joind.js_basename);
575 if (!strcmp(dwarfstring_string(
576 &joind.js_originalfullpath),
577 dwarfstring_string(&joind.js_tmp3))) {
578 /* duplicated name. spurious match. */
579 #ifdef TESTING
580 printf("duplicated output string %s\n",
581 dwarfstring_string(&joind.js_tmp3));
582 #endif /* TESTING */
583 } else if (res == DW_DLV_OK) {
584 struct dwarfstring_list_s *now_last = 0;
585 res = dwarfstring_list_add_new(
586 &base_dwlist,
587 last_entry,&joind.js_tmp3,
588 &now_last,errcode);
589 if(res != DW_DLV_OK) {
590 dwarfstring_list_destructor(&base_dwlist);
591 destruct_js(&joind);
592 return res;
593 }
594 last_entry = now_last;
595 }
596 }
597 }
598 }
599
600 {
601 struct dwarfstring_list_s *cur = 0;
602 char **resultfullstring = 0;
603
604 unsigned long count = 0;
605 unsigned long pointerarraysize = 0;
606 unsigned long sumstringlengths = 0;
607 unsigned long totalareasize = 0;
608 unsigned long setptrindex = 0;
609 unsigned long setstrindex = 0;
610
611 cur = &base_dwlist;
612 for ( ; cur ; cur = cur->dl_next) {
613 ++count;
614 pointerarraysize += sizeof(void *);
615 sumstringlengths +=
616 dwarfstring_strlen(&cur->dl_string) +1;
617 }
618 /* Make a final null pointer in the pointer array. */
619 pointerarraysize += sizeof(void *);
620 totalareasize = pointerarraysize + sumstringlengths +8;
621 resultfullstring = (char **)malloc(totalareasize);
622 setstrindex = pointerarraysize;
623 if(!resultfullstring) {
624 #ifdef TESTING
625 printf("Malloc fail making final paths. Length %lu"
626 " bytes.\n",totalareasize);
627 #endif /* TESTING */
628 dwarfstring_list_destructor(&base_dwlist);
629 destruct_js(&joind);
630 *errcode = DW_DLE_ALLOC_FAIL;
631 return DW_DLV_ERROR;
632 }
633 memset(resultfullstring,0,totalareasize);
634 cur = &base_dwlist;
635
636 for ( ; cur ; cur = cur->dl_next,++setptrindex) {
637 char **iptr = (char **)((char *)resultfullstring +
638 setptrindex*sizeof(void *));
639 char *sptr = (char*)resultfullstring + setstrindex;
640
641 strcpy(sptr,dwarfstring_string(&cur->dl_string));
642 setstrindex += dwarfstring_strlen(&cur->dl_string)+1;
643 *iptr = sptr;
644 }
645 *paths_out = resultfullstring;
646 *paths_out_length = count;
647 }
648 dwarfstring_list_destructor(&base_dwlist);
649 destruct_js(&joind);
650 return DW_DLV_OK;
651 }
652
653 static int
extract_debuglink(Dwarf_Debug dbg,struct Dwarf_Section_s * pdebuglink,char ** name_returned,unsigned char ** crc_returned,Dwarf_Error * error)654 extract_debuglink(Dwarf_Debug dbg,
655 struct Dwarf_Section_s * pdebuglink,
656 char ** name_returned, /* static storage, do not free */
657 unsigned char ** crc_returned, /* 32bit crc , do not free */
658 Dwarf_Error *error)
659 {
660 Dwarf_Small *ptr = 0;
661 Dwarf_Small *endptr = 0;
662 unsigned namelen = 0;
663 unsigned m = 0;
664 unsigned incr = 0;
665 Dwarf_Small *crcptr = 0;
666 int res = DW_DLV_ERROR;
667 Dwarf_Unsigned secsize = 0;
668
669 if (!pdebuglink->dss_data) {
670 res = _dwarf_load_section(dbg, pdebuglink,error);
671 if (res != DW_DLV_OK) {
672 return res;
673 }
674 }
675 secsize = pdebuglink->dss_size;
676 ptr = pdebuglink->dss_data;
677 endptr = ptr + secsize;
678
679 res = _dwarf_check_string_valid(dbg,ptr,
680 ptr, endptr, DW_DLE_FORM_STRING_BAD_STRING,
681 error);
682 if ( res != DW_DLV_OK) {
683 return res;
684 }
685 namelen = (unsigned)strlen((const char*)ptr);
686 m = (namelen+1) %4;
687 if (m) {
688 incr = 4 - m;
689 }
690 crcptr = (unsigned char *)ptr +namelen +1 +incr;
691 if ((crcptr +4) != (unsigned char*)endptr) {
692 _dwarf_error(dbg,error,DW_DLE_CORRUPT_GNU_DEBUGLINK);
693 return DW_DLV_ERROR;
694 }
695 *name_returned = (char *)ptr;
696 *crc_returned = crcptr;
697 return DW_DLV_OK;
698 }
699
700
701 /* The definition of .note.gnu.buildid contents (also
702 used for other GNU .note.gnu. sections too. */
703 struct buildid_s {
704 char bu_ownernamesize[4];
705 char bu_buildidsize[4];
706 char bu_type[4];
707 char bu_owner[1];
708 };
709
710 static int
extract_buildid(Dwarf_Debug dbg,struct Dwarf_Section_s * pbuildid,unsigned * type_returned,char ** owner_name_returned,unsigned char ** build_id_returned,unsigned * build_id_length_returned,Dwarf_Error * error)711 extract_buildid(Dwarf_Debug dbg,
712 struct Dwarf_Section_s * pbuildid,
713 unsigned * type_returned,
714 char **owner_name_returned,
715 unsigned char **build_id_returned,
716 unsigned * build_id_length_returned,
717 Dwarf_Error *error)
718 {
719 Dwarf_Small * ptr = 0;
720 Dwarf_Small * endptr = 0;
721 int res = DW_DLV_ERROR;
722 struct buildid_s *bu = 0;
723 Dwarf_Unsigned namesize = 0;
724 Dwarf_Unsigned descrsize = 0;
725 Dwarf_Unsigned type = 0;
726 Dwarf_Unsigned finalsize;
727 Dwarf_Unsigned secsize = 0;
728
729 if (!pbuildid->dss_data) {
730 res = _dwarf_load_section(dbg, pbuildid,error);
731 if (res != DW_DLV_OK) {
732 return res;
733 }
734 }
735 secsize = pbuildid->dss_size;
736 ptr = pbuildid->dss_data;
737 if (secsize < sizeof(struct buildid_s)) {
738 #ifdef TESTING
739 printf("ERROR section .note.gnu.build-id too small: "
740 " section length: 0x%" DW_PR_DUx
741 " minimum struct size 0x%" DW_PR_DUx "\n",
742 secsize,(Dwarf_Unsigned) sizeof(struct buildid_s));
743 #endif /* TESTING */
744 _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID);
745 return DW_DLV_ERROR;
746 }
747 endptr = ptr + secsize;
748 /* We hold gh_content till all is closed
749 as we return pointers into it
750 if all goes well. */
751 bu = (struct buildid_s *)ptr;
752 ASNAR(dbg->de_copy_word,namesize, bu->bu_ownernamesize);
753 ASNAR(dbg->de_copy_word,descrsize,bu->bu_buildidsize);
754 ASNAR(dbg->de_copy_word,type, bu->bu_type);
755 if (descrsize != 20) {
756 _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID);
757 return DW_DLV_ERROR;
758 }
759 res = _dwarf_check_string_valid(dbg,
760 (Dwarf_Small *)&bu->bu_owner[0],
761 (Dwarf_Small *)&bu->bu_owner[0],
762 endptr,
763 DW_DLE_CORRUPT_GNU_DEBUGID_STRING,
764 error);
765 if ( res != DW_DLV_OK) {
766 return res;
767 }
768 if ((strlen(bu->bu_owner) +1) != namesize) {
769 _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_STRING);
770 return res;
771 }
772
773 finalsize = sizeof(struct buildid_s)-1 + namesize + descrsize;
774 if (finalsize > secsize) {
775 _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_SIZE);
776 return DW_DLV_ERROR;
777 }
778 *type_returned = type;
779 *owner_name_returned = &bu->bu_owner[0];
780 *build_id_length_returned = descrsize;
781 *build_id_returned = (unsigned char *)ptr +
782 sizeof(struct buildid_s)-1 + namesize;
783 return DW_DLV_OK;
784 }
785
786 /* */
dwarf_gnu_debuglink(Dwarf_Debug dbg,char ** debuglink_path_returned,unsigned char ** crc_returned,char ** debuglink_fullpath_returned,unsigned * debuglink_fullpath_length_returned,unsigned * buildid_type_returned,char ** buildid_owner_name_returned,unsigned char ** buildid_returned,unsigned * buildid_length_returned,char *** paths_returned,unsigned * paths_count_returned,Dwarf_Error * error)787 int dwarf_gnu_debuglink(Dwarf_Debug dbg,
788 char ** debuglink_path_returned,
789 unsigned char ** crc_returned,
790 char ** debuglink_fullpath_returned,
791 unsigned * debuglink_fullpath_length_returned,
792
793 unsigned * buildid_type_returned ,
794 char ** buildid_owner_name_returned,
795 unsigned char ** buildid_returned,
796 unsigned * buildid_length_returned,
797 char *** paths_returned,
798 unsigned * paths_count_returned,
799 Dwarf_Error* error)
800 {
801 dwarfstring debuglink_fullpath;
802 int linkres = DW_DLV_ERROR;
803 int res = DW_DLV_ERROR;
804 char * pathname = 0;
805 int buildidres = 0;
806 int errcode = 0;
807 struct Dwarf_Section_s * pdebuglink = 0;
808 struct Dwarf_Section_s * pbuildid = 0;
809
810 if(!dbg) {
811 _dwarf_error(dbg,error,DW_DLE_DBG_NULL);
812 return DW_DLV_ERROR;
813 }
814 if (dbg->de_gnu_debuglink.dss_size) {
815 pdebuglink = &dbg->de_gnu_debuglink;
816 }
817 if (dbg->de_note_gnu_buildid.dss_size) {
818 pbuildid = &dbg->de_note_gnu_buildid;
819 }
820 if (!pdebuglink && !pbuildid) {
821 return DW_DLV_NO_ENTRY;
822 }
823 if (pdebuglink) {
824 linkres = extract_debuglink(dbg,
825 pdebuglink,
826 debuglink_path_returned,
827 crc_returned,
828 error);
829 if (linkres == DW_DLV_ERROR) {
830 return linkres;
831 }
832 }
833 if (pbuildid) {
834 buildidres = extract_buildid(dbg,
835 pbuildid,
836 buildid_type_returned,
837 buildid_owner_name_returned,
838 buildid_returned,
839 buildid_length_returned,
840 error);
841 if (buildidres == DW_DLV_ERROR) {
842 return buildidres;
843 }
844 }
845
846 dwarfstring_constructor(&debuglink_fullpath);
847 pathname = (char *)dbg->de_path;
848 if (pathname && paths_returned) {
849 res = _dwarf_construct_linkedto_path(
850 (char **)dbg->de_gnu_global_paths,
851 dbg->de_gnu_global_path_count,
852 pathname,
853 *debuglink_path_returned,
854 &debuglink_fullpath,
855 *crc_returned,
856 *buildid_returned,
857 *buildid_length_returned,
858 paths_returned,
859 paths_count_returned,
860 &errcode);
861 if(res != DW_DLV_OK) {
862 dwarfstring_destructor(&debuglink_fullpath);
863 return res;
864 }
865 if (dwarfstring_strlen(&debuglink_fullpath)) {
866 *debuglink_fullpath_returned =
867 strdup(dwarfstring_string(&debuglink_fullpath));
868 *debuglink_fullpath_length_returned =
869 dwarfstring_strlen(&debuglink_fullpath);
870 }
871 } else if (paths_count_returned) {
872 *paths_count_returned = 0;
873 }
874 dwarfstring_destructor(&debuglink_fullpath);
875 return DW_DLV_OK;
876 }
877
878 /* This should be rarely called and most likely
879 only once (at dbg init time from dwarf_generic_init.c,
880 see set_global_paths_init()).
881 Maybe once or twice later.
882 */
883 int
dwarf_add_debuglink_global_path(Dwarf_Debug dbg,const char * pathname,Dwarf_Error * error)884 dwarf_add_debuglink_global_path(Dwarf_Debug dbg,
885 const char *pathname,
886 Dwarf_Error *error)
887 {
888 unsigned glpath_count_in = 0;
889 unsigned glpath_count_out = 0;
890 const char **glpaths = 0;
891 const char * path1 = 0;
892
893 glpath_count_in = dbg->de_gnu_global_path_count;
894 glpath_count_out = glpath_count_in+1;
895 glpaths = (const char **)malloc(sizeof(char *)*
896 glpath_count_out);
897 if (!glpaths) {
898 _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL);
899 return DW_DLV_ERROR;
900 }
901 if (glpath_count_in) {
902 memcpy(glpaths, dbg->de_gnu_global_paths,
903 sizeof(char *)*glpath_count_in);
904 }
905 path1 = strdup(pathname);
906 if (!path1) {
907 free(glpaths);
908 _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL);
909 return DW_DLV_ERROR;
910 }
911 free((char *)dbg->de_gnu_global_paths);
912 glpaths[glpath_count_in] = path1;
913 dbg->de_gnu_global_paths = (const char **)glpaths;
914 dbg->de_gnu_global_path_count = glpath_count_out;
915 return DW_DLV_OK;
916 }
917