xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_debuglink.c (revision 8459c777fc1aaabb2f7dad05de1313aa169417cd)
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
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
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
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
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
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
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
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
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 */
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
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
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 /* */
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
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