summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdwarf/common/dwarf_debuglink.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_debuglink.c')
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_debuglink.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_debuglink.c b/usr/src/lib/libdwarf/common/dwarf_debuglink.c
new file mode 100644
index 0000000000..30afaea68a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_debuglink.c
@@ -0,0 +1,916 @@
+/*
+Copyright (c) 2019-2020, David Anderson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with
+or without modification, are permitted provided that the
+following conditions are met:
+
+ Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif /* HAVE_MALLOC_H */
+#ifdef HAVE_STDDEF_H
+#include <stddef.h> /* ptrdiff_t */
+#endif /* HAVE_STDDEF_H */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#include <string.h>
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif /* HAVE_ELF_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* getcwd */
+#endif /* HAVE_UNISTD_H */
+#if 0
+#include <sys/types.h> /* for open() */
+#include <sys/stat.h> /* for open() */
+#include <fcntl.h> /* for open() */
+#include <errno.h>
+#endif
+#include "dwarf_incl.h"
+#include "dwarf_alloc.h"
+#include "dwarf_error.h"
+#include "dwarf_util.h"
+#include "dwarfstring.h"
+#include "dwarf_debuglink.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif /* O_BINARY */
+
+#define MINBUFLEN 1000
+#define TRUE 1
+#define FALSE 0
+
+#ifdef HAVE_UNUSED_ATTRIBUTE
+#define UNUSEDARG __attribute__ ((unused))
+#else
+#define UNUSEDARG
+#endif
+
+
+#if _WIN32
+#define NULL_DEVICE_NAME "NUL"
+#else
+#define NULL_DEVICE_NAME "/dev/null"
+#endif /* _WIN32 */
+
+#ifdef WORDS_BIGENDIAN
+#define ASNAR(func,t,s) \
+ do { \
+ unsigned tbyte = sizeof(t) - sizeof(s); \
+ t = 0; \
+ func(((char *)&t)+tbyte ,&s[0],sizeof(s)); \
+ } while (0)
+#else /* LITTLE ENDIAN */
+#define ASNAR(func,t,s) \
+ do { \
+ t = 0; \
+ func(&t,&s[0],sizeof(s)); \
+ } while (0)
+#endif /* end LITTLE- BIG-ENDIAN */
+
+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);
+
+struct joins_s {
+ char * js_fullpath;
+ dwarfstring js_dirname;
+ dwarfstring js_basepath;
+ dwarfstring js_basename;
+ dwarfstring js_cwd;
+ dwarfstring js_originalfullpath;
+ dwarfstring js_tmp;
+ dwarfstring js_tmp2;
+ dwarfstring js_tmpdeb;
+ dwarfstring js_tmp3;
+ dwarfstring js_buildid;
+ dwarfstring js_buildid_filename;
+};
+
+#if 0
+int
+_dwarf_check_string_valid(
+ void *areaptr,
+ void *strptr,
+ void *areaendptr,
+ int suggested_error,
+ int *errcode)
+{
+ Dwarf_Small *start = areaptr;
+ Dwarf_Small *p = strptr;
+ Dwarf_Small *end = areaendptr;
+ ptrdiff_t diff = 0;
+
+ if (p < start) {
+ diff = start - p;
+#ifdef TESTING
+ printf("Error string start pointer error: loc %"
+ DW_PR_DSs
+ " bytes before available area \n",(Dwarf_Signed)diff);
+#endif /* TESTING */
+ *errcode = suggested_error;
+ return DW_DLV_ERROR;
+ }
+ if (p >= end) {
+ diff = p - start;
+#ifdef TESTING
+ printf("Error string end pointer error, not terminated %"
+ " before end of area. Length: "
+ DW_PR_DSs "\n",(Dwarf_Signed)diff);
+#endif /* TESTING */
+ *errcode = suggested_error;
+ return DW_DLV_ERROR;
+ }
+ while (p < end) {
+ if (*p == 0) {
+ return DW_DLV_OK;
+ }
+ ++p;
+ }
+ diff = p - start;
+#ifdef TESTING
+ printf("Error string not terminated error: not ended after %"
+ DW_PR_DSs " bytes (past end of available bytes)\n",
+ (Dwarf_Signed)diff);
+#endif /* TESTING */
+ *errcode = DW_DLE_STRING_NOT_TERMINATED;
+ return DW_DLV_ERROR;
+}
+#endif
+
+
+#if 0
+static int
+does_file_exist(char *f)
+{
+ int fd = 0;
+
+ fd = open(f,O_RDONLY|O_BINARY);
+ if (fd < 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ /* Here we could derive the crc to validate the file. */
+ close(fd);
+ return DW_DLV_OK;
+}
+#endif
+
+
+static void
+construct_js(struct joins_s * js)
+{
+ memset(js,0,sizeof(struct joins_s));
+ dwarfstring_constructor(&js->js_basename);
+ dwarfstring_constructor(&js->js_dirname);
+ dwarfstring_constructor(&js->js_basepath);
+ dwarfstring_constructor(&js->js_cwd);
+ dwarfstring_constructor(&js->js_originalfullpath);
+ dwarfstring_constructor(&js->js_tmp);
+ dwarfstring_constructor(&js->js_tmp2);
+ dwarfstring_constructor(&js->js_tmpdeb);
+ dwarfstring_constructor(&js->js_tmp3);
+ dwarfstring_constructor(&js->js_buildid);
+ dwarfstring_constructor(&js->js_buildid_filename);
+}
+static void
+destruct_js(struct joins_s * js)
+{
+ dwarfstring_destructor(&js->js_dirname);
+ dwarfstring_destructor(&js->js_basepath);
+ dwarfstring_destructor(&js->js_basename);
+ dwarfstring_destructor(&js->js_cwd);
+ dwarfstring_destructor(&js->js_originalfullpath);
+ dwarfstring_destructor(&js->js_tmp);
+ dwarfstring_destructor(&js->js_tmp2);
+ dwarfstring_destructor(&js->js_tmpdeb);
+ dwarfstring_destructor(&js->js_tmp3);
+ dwarfstring_destructor(&js->js_buildid);
+ dwarfstring_destructor(&js->js_buildid_filename);
+}
+
+static char joinchar = '/';
+static char* joinstr = "/";
+
+int
+_dwarf_pathjoinl(dwarfstring *target,dwarfstring * input)
+{
+ char *inputs = dwarfstring_string(input);
+ char *targ = dwarfstring_string(target);
+ size_t targlen = 0;
+
+ if (!dwarfstring_strlen(target)) {
+ dwarfstring_append(target,dwarfstring_string(input));
+ return DW_DLV_OK;
+ }
+ targlen = dwarfstring_strlen(target);
+ targ = dwarfstring_string(target);
+ if (targ[targlen-1] != joinchar) {
+ if (*inputs != joinchar) {
+ dwarfstring_append(target,joinstr);
+ dwarfstring_append(target,inputs);
+ } else {
+ dwarfstring_append(target,inputs);
+ }
+ } else {
+ if (*inputs != joinchar) {
+ dwarfstring_append(target,inputs);
+ } else {
+ dwarfstring_append(target,inputs+1);
+ }
+ }
+ return DW_DLV_OK;
+}
+/* ASSERT: the last character in s is not a / */
+static size_t
+mydirlen(char *s)
+{
+ char *cp = 0;
+ char *lastjoinchar = 0;
+ size_t count =0;
+
+ for(cp = s ; *cp ; ++cp,++count) {
+ if (*cp == joinchar) {
+ lastjoinchar = cp;
+ }
+ }
+ if (lastjoinchar) {
+ /* we know diff is postive in all cases */
+ ptrdiff_t diff = lastjoinchar - s;
+ /* count the last join as mydirlen. */
+ return (size_t)(diff+1);
+ }
+ return 0;
+}
+
+struct dwarfstring_list_s {
+ dwarfstring dl_string;
+ struct dwarfstring_list_s *dl_next;
+};
+
+static void
+dwarfstring_list_constructor(struct dwarfstring_list_s *l)
+{
+ dwarfstring_constructor(&l->dl_string);
+ l->dl_next = 0;
+}
+
+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)
+{
+ struct dwarfstring_list_s *next = 0;
+ if(prev) {
+ next = ( struct dwarfstring_list_s *)
+ malloc(sizeof(struct dwarfstring_list_s));
+ if (!next) {
+ *errcode = DW_DLE_ALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ dwarfstring_list_constructor(next);
+ } else {
+ next = base_entry;
+ }
+ dwarfstring_append(&next->dl_string,
+ dwarfstring_string(input));
+ if (prev) {
+ prev->dl_next = next;
+ }
+ *new_out = next;
+ return DW_DLV_OK;
+}
+
+/* destructs passed in entry (does not free it) and all
+ those on the dl_next list (those are freed). */
+static void
+dwarfstring_list_destructor(struct dwarfstring_list_s *l)
+{
+ struct dwarfstring_list_s *curl = l;
+ struct dwarfstring_list_s *nextl = l;
+
+ nextl = curl->dl_next;
+ dwarfstring_destructor(&curl->dl_string);
+ curl->dl_next = 0;
+ curl = nextl;
+ for( ; curl ; curl = nextl) {
+ nextl = curl->dl_next;
+ dwarfstring_destructor(&curl->dl_string);
+ curl->dl_next = 0;
+ free(curl);
+ }
+}
+
+static void
+build_buildid_filename(dwarfstring *target,
+ unsigned buildid_length,
+ unsigned char *buildid)
+{
+ dwarfstring tmp;
+ unsigned bu = 0;
+ unsigned char *cp = 0;
+
+ dwarfstring_constructor(&tmp);
+ cp = buildid;
+ for (bu = 0; bu < buildid_length; ++bu ,++cp) {
+ dwarfstring_append_printf_u(&tmp, "%02x",*cp);
+ if (bu == 0) {
+ dwarfstring_append(&tmp,"/");
+ }
+ }
+ dwarfstring_append(&tmp,".debug");
+ _dwarf_pathjoinl(target,&tmp);
+ dwarfstring_destructor(&tmp);
+ return;
+}
+
+#if 0
+static void
+dump_bytes(const char *msg,unsigned char * start, unsigned len)
+{
+ Dwarf_Small *end = start + len;
+ Dwarf_Small *cur = start;
+ printf("%s (0x%lx) ",msg,(unsigned long)start);
+ for (; cur < end; cur++) {
+ printf("%02x", *cur);
+ }
+ printf("\n");
+}
+#endif
+
+
+/* New September 2019. Access to the GNU section named
+ .gnu_debuglink
+ See
+ https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
+
+*/
+int _dwarf_construct_linkedto_path(
+ char **global_prefixes_in,
+ unsigned length_global_prefixes_in,
+ char *pathname_in,
+ char *link_string_in, /* from debug link */
+ dwarfstring * link_string_fullpath_out,
+ UNUSEDARG unsigned char *crc_in, /* from debug_link, 4 bytes */
+ unsigned char *buildid, /* from gnu buildid */
+ unsigned buildid_length, /* from gnu buildid */
+ char ***paths_out,
+ unsigned *paths_out_length,
+ int *errcode)
+{
+ char * depath = pathname_in;
+ int res = 0;
+ struct joins_s joind;
+ size_t dirnamelen = 0;
+ struct dwarfstring_list_s base_dwlist;
+ struct dwarfstring_list_s *last_entry = 0;
+ unsigned global_prefix_number = 0;
+
+ dwarfstring_list_constructor(&base_dwlist);
+ construct_js(&joind);
+ build_buildid_filename(&joind.js_buildid_filename,
+ buildid_length, buildid);
+ dirnamelen = mydirlen(depath);
+ if (dirnamelen) {
+ dwarfstring_append_length(&joind.js_dirname,
+ depath,dirnamelen);
+ }
+ dwarfstring_append(&joind.js_basepath,depath+dirnamelen);
+ dwarfstring_append(&joind.js_basename,link_string_in);
+ if (depath[0] != joinchar) {
+ char buffer[2000];
+#ifdef TESTING
+ buffer[0] = 0;
+ /* For testing lets use a fake (consistent)
+ base dir. */
+ strcpy(buffer,"/fake/dir/path");
+#else
+ unsigned buflen= sizeof(buffer);
+ char *wdret = 0;
+
+ buffer[0] = 0;
+ wdret = getcwd(buffer,buflen);
+ if (!wdret) {
+ printf("getcwd() issue. Do nothing. "
+ " line %d %s\n",__LINE__,__FILE__);
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ *errcode = DW_DLE_ALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+#endif /* TESTING */
+ dwarfstring_append(&joind.js_cwd,buffer);
+ buffer[0] = 0;
+ }
+
+ {
+ /* Builds the full path to the original
+ executable, but absent executable name. */
+ dwarfstring_append(&joind.js_originalfullpath,
+ dwarfstring_string(&joind.js_cwd));
+ _dwarf_pathjoinl(&joind.js_originalfullpath,
+ &joind.js_dirname);
+ _dwarf_pathjoinl(&joind.js_originalfullpath,
+ &joind.js_basepath);
+#ifdef TESTING
+ printf("originalfullpath : %s\n",
+ dwarfstring_string(&joind.js_originalfullpath));
+#endif
+ }
+ {
+ /* There is perhaps a directory prefix in the
+ incoming pathname.
+ So we add that to js_cwd. */
+ res = _dwarf_pathjoinl(&joind.js_cwd,
+ &joind.js_dirname);
+ /* This is used in a couple search paths. */
+ }
+ for (global_prefix_number = 0;
+ buildid_length &&
+ (global_prefix_number < length_global_prefixes_in);
+ ++global_prefix_number) {
+ char * prefix = 0;
+
+ prefix = global_prefixes_in[global_prefix_number];
+ dwarfstring_reset(&joind.js_buildid);
+ dwarfstring_append(&joind.js_buildid,prefix);
+ _dwarf_pathjoinl(&joind.js_buildid,
+ &joind.js_buildid_filename);
+ if (!strcmp(dwarfstring_string(&joind.js_originalfullpath),
+ dwarfstring_string(&joind.js_buildid))) {
+#ifdef TESTING
+ printf("duplicated output string %s\n",
+ dwarfstring_string(&joind.js_buildid));
+#endif /* TESTING */
+ /* duplicated name. spurious match. */
+ } else {
+ struct dwarfstring_list_s *now_last = 0;
+ res = dwarfstring_list_add_new(
+ &base_dwlist,
+ last_entry,&joind.js_buildid,
+ &now_last,errcode);
+ if(res != DW_DLV_OK) {
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ return res;
+ }
+ last_entry = now_last;
+ }
+ }
+ if (link_string_in) {
+ /* js_cwd is a leading / directory name. */
+ {
+ dwarfstring_reset(&joind.js_tmp);
+ dwarfstring_append(&joind.js_tmp,
+ dwarfstring_string(&joind.js_cwd));
+ /* If we add basename do we find what we look for? */
+ res = _dwarf_pathjoinl(&joind.js_tmp,&joind.js_basename);
+ /* We return the original link as full path this way. */
+ dwarfstring_append(link_string_fullpath_out,
+ dwarfstring_string(&joind.js_tmp));
+ if (!strcmp(dwarfstring_string(&joind.js_originalfullpath),
+ dwarfstring_string(&joind.js_tmp))) {
+#ifdef TESTING
+ printf("duplicated output string %s\n",
+ dwarfstring_string(&joind.js_tmp));
+#endif /* TESTING */
+ /* duplicated name. spurious match. */
+ } else if (res == DW_DLV_OK) {
+ struct dwarfstring_list_s *now_last = 0;
+ res = dwarfstring_list_add_new(
+ &base_dwlist,
+ last_entry,&joind.js_tmp,
+ &now_last,errcode);
+ if(res != DW_DLV_OK) {
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ return res;
+ }
+ last_entry = now_last;
+ }
+ }
+ {
+ dwarfstring_reset(&joind.js_tmp2);
+ dwarfstring_reset(&joind.js_tmpdeb);
+
+ dwarfstring_append(&joind.js_tmp2,
+ dwarfstring_string(&joind.js_cwd));
+ dwarfstring_append(&joind.js_tmpdeb,".debug");
+ res = _dwarf_pathjoinl(&joind.js_tmp2,&joind.js_tmpdeb);
+ if (res == DW_DLV_OK) {
+ res = _dwarf_pathjoinl(&joind.js_tmp2,
+ &joind.js_basename);
+ /* this the second search path
+ after global directories
+ search for nn/nnnnn....debug. */
+ if (!strcmp(dwarfstring_string(
+ &joind.js_originalfullpath),
+ dwarfstring_string(&joind.js_tmp2))) {
+#ifdef TESTING
+ printf("duplicated output string %s\n",
+ dwarfstring_string(&joind.js_tmp2));
+#endif /* TESTING */
+ /* duplicated name. spurious match. */
+ } else if(res == DW_DLV_OK) {
+ struct dwarfstring_list_s *now_last = 0;
+ res = dwarfstring_list_add_new(
+ &base_dwlist,
+ last_entry,&joind.js_tmp2,
+ &now_last,errcode);
+ if(res != DW_DLV_OK) {
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ return res;
+ }
+ last_entry = now_last;
+ }
+ }
+ }
+ /* Not found above, now look in the global locations. */
+ for (global_prefix_number = 0;
+ global_prefix_number < length_global_prefixes_in;
+ ++global_prefix_number) {
+ char * prefix = global_prefixes_in[global_prefix_number];
+
+ dwarfstring_reset(&joind.js_tmp3);
+ dwarfstring_append(&joind.js_tmp3, prefix);
+ res = _dwarf_pathjoinl(&joind.js_tmp3, &joind.js_cwd);
+ if (res == DW_DLV_OK) {
+ res = _dwarf_pathjoinl(&joind.js_tmp3,
+ &joind.js_basename);
+ if (!strcmp(dwarfstring_string(
+ &joind.js_originalfullpath),
+ dwarfstring_string(&joind.js_tmp3))) {
+ /* duplicated name. spurious match. */
+#ifdef TESTING
+ printf("duplicated output string %s\n",
+ dwarfstring_string(&joind.js_tmp3));
+#endif /* TESTING */
+ } else if (res == DW_DLV_OK) {
+ struct dwarfstring_list_s *now_last = 0;
+ res = dwarfstring_list_add_new(
+ &base_dwlist,
+ last_entry,&joind.js_tmp3,
+ &now_last,errcode);
+ if(res != DW_DLV_OK) {
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ return res;
+ }
+ last_entry = now_last;
+ }
+ }
+ }
+ }
+
+ {
+ struct dwarfstring_list_s *cur = 0;
+ char **resultfullstring = 0;
+
+ unsigned long count = 0;
+ unsigned long pointerarraysize = 0;
+ unsigned long sumstringlengths = 0;
+ unsigned long totalareasize = 0;
+ unsigned long setptrindex = 0;
+ unsigned long setstrindex = 0;
+
+ cur = &base_dwlist;
+ for ( ; cur ; cur = cur->dl_next) {
+ ++count;
+ pointerarraysize += sizeof(void *);
+ sumstringlengths +=
+ dwarfstring_strlen(&cur->dl_string) +1;
+ }
+ /* Make a final null pointer in the pointer array. */
+ pointerarraysize += sizeof(void *);
+ totalareasize = pointerarraysize + sumstringlengths +8;
+ resultfullstring = (char **)malloc(totalareasize);
+ setstrindex = pointerarraysize;
+ if(!resultfullstring) {
+#ifdef TESTING
+ printf("Malloc fail making final paths. Length %lu"
+ " bytes.\n",totalareasize);
+#endif /* TESTING */
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ *errcode = DW_DLE_ALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ memset(resultfullstring,0,totalareasize);
+ cur = &base_dwlist;
+
+ for ( ; cur ; cur = cur->dl_next,++setptrindex) {
+ char **iptr = (char **)((char *)resultfullstring +
+ setptrindex*sizeof(void *));
+ char *sptr = (char*)resultfullstring + setstrindex;
+
+ strcpy(sptr,dwarfstring_string(&cur->dl_string));
+ setstrindex += dwarfstring_strlen(&cur->dl_string)+1;
+ *iptr = sptr;
+ }
+ *paths_out = resultfullstring;
+ *paths_out_length = count;
+ }
+ dwarfstring_list_destructor(&base_dwlist);
+ destruct_js(&joind);
+ return DW_DLV_OK;
+}
+
+static int
+extract_debuglink(Dwarf_Debug dbg,
+ struct Dwarf_Section_s * pdebuglink,
+ char ** name_returned, /* static storage, do not free */
+ unsigned char ** crc_returned, /* 32bit crc , do not free */
+ Dwarf_Error *error)
+{
+ Dwarf_Small *ptr = 0;
+ Dwarf_Small *endptr = 0;
+ unsigned namelen = 0;
+ unsigned m = 0;
+ unsigned incr = 0;
+ Dwarf_Small *crcptr = 0;
+ int res = DW_DLV_ERROR;
+ Dwarf_Unsigned secsize = 0;
+
+ if (!pdebuglink->dss_data) {
+ res = _dwarf_load_section(dbg, pdebuglink,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ secsize = pdebuglink->dss_size;
+ ptr = pdebuglink->dss_data;
+ endptr = ptr + secsize;
+
+ res = _dwarf_check_string_valid(dbg,ptr,
+ ptr, endptr, DW_DLE_FORM_STRING_BAD_STRING,
+ error);
+ if ( res != DW_DLV_OK) {
+ return res;
+ }
+ namelen = (unsigned)strlen((const char*)ptr);
+ m = (namelen+1) %4;
+ if (m) {
+ incr = 4 - m;
+ }
+ crcptr = (unsigned char *)ptr +namelen +1 +incr;
+ if ((crcptr +4) != (unsigned char*)endptr) {
+ _dwarf_error(dbg,error,DW_DLE_CORRUPT_GNU_DEBUGLINK);
+ return DW_DLV_ERROR;
+ }
+ *name_returned = (char *)ptr;
+ *crc_returned = crcptr;
+ return DW_DLV_OK;
+}
+
+
+/* The definition of .note.gnu.buildid contents (also
+ used for other GNU .note.gnu. sections too. */
+struct buildid_s {
+ char bu_ownernamesize[4];
+ char bu_buildidsize[4];
+ char bu_type[4];
+ char bu_owner[1];
+};
+
+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)
+{
+ Dwarf_Small * ptr = 0;
+ Dwarf_Small * endptr = 0;
+ int res = DW_DLV_ERROR;
+ struct buildid_s *bu = 0;
+ Dwarf_Unsigned namesize = 0;
+ Dwarf_Unsigned descrsize = 0;
+ Dwarf_Unsigned type = 0;
+ Dwarf_Unsigned finalsize;
+ Dwarf_Unsigned secsize = 0;
+
+ if (!pbuildid->dss_data) {
+ res = _dwarf_load_section(dbg, pbuildid,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ secsize = pbuildid->dss_size;
+ ptr = pbuildid->dss_data;
+ if (secsize < sizeof(struct buildid_s)) {
+#ifdef TESTING
+ printf("ERROR section .note.gnu.build-id too small: "
+ " section length: 0x%" DW_PR_DUx
+ " minimum struct size 0x%" DW_PR_DUx "\n",
+ secsize,(Dwarf_Unsigned) sizeof(struct buildid_s));
+#endif /* TESTING */
+ _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID);
+ return DW_DLV_ERROR;
+ }
+ endptr = ptr + secsize;
+ /* We hold gh_content till all is closed
+ as we return pointers into it
+ if all goes well. */
+ bu = (struct buildid_s *)ptr;
+ ASNAR(dbg->de_copy_word,namesize, bu->bu_ownernamesize);
+ ASNAR(dbg->de_copy_word,descrsize,bu->bu_buildidsize);
+ ASNAR(dbg->de_copy_word,type, bu->bu_type);
+ if (descrsize != 20) {
+ _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID);
+ return DW_DLV_ERROR;
+ }
+ res = _dwarf_check_string_valid(dbg,
+ (Dwarf_Small *)&bu->bu_owner[0],
+ (Dwarf_Small *)&bu->bu_owner[0],
+ endptr,
+ DW_DLE_CORRUPT_GNU_DEBUGID_STRING,
+ error);
+ if ( res != DW_DLV_OK) {
+ return res;
+ }
+ if ((strlen(bu->bu_owner) +1) != namesize) {
+ _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_STRING);
+ return res;
+ }
+
+ finalsize = sizeof(struct buildid_s)-1 + namesize + descrsize;
+ if (finalsize > secsize) {
+ _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_SIZE);
+ return DW_DLV_ERROR;
+ }
+ *type_returned = type;
+ *owner_name_returned = &bu->bu_owner[0];
+ *build_id_length_returned = descrsize;
+ *build_id_returned = (unsigned char *)ptr +
+ sizeof(struct buildid_s)-1 + namesize;
+ return DW_DLV_OK;
+}
+
+/* */
+int 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)
+{
+ dwarfstring debuglink_fullpath;
+ int linkres = DW_DLV_ERROR;
+ int res = DW_DLV_ERROR;
+ char * pathname = 0;
+ int buildidres = 0;
+ int errcode = 0;
+ struct Dwarf_Section_s * pdebuglink = 0;
+ struct Dwarf_Section_s * pbuildid = 0;
+
+ if(!dbg) {
+ _dwarf_error(dbg,error,DW_DLE_DBG_NULL);
+ return DW_DLV_ERROR;
+ }
+ if (dbg->de_gnu_debuglink.dss_size) {
+ pdebuglink = &dbg->de_gnu_debuglink;
+ }
+ if (dbg->de_note_gnu_buildid.dss_size) {
+ pbuildid = &dbg->de_note_gnu_buildid;
+ }
+ if (!pdebuglink && !pbuildid) {
+ return DW_DLV_NO_ENTRY;
+ }
+ if (pdebuglink) {
+ linkres = extract_debuglink(dbg,
+ pdebuglink,
+ debuglink_path_returned,
+ crc_returned,
+ error);
+ if (linkres == DW_DLV_ERROR) {
+ return linkres;
+ }
+ }
+ if (pbuildid) {
+ buildidres = extract_buildid(dbg,
+ pbuildid,
+ buildid_type_returned,
+ buildid_owner_name_returned,
+ buildid_returned,
+ buildid_length_returned,
+ error);
+ if (buildidres == DW_DLV_ERROR) {
+ return buildidres;
+ }
+ }
+
+ dwarfstring_constructor(&debuglink_fullpath);
+ pathname = (char *)dbg->de_path;
+ if (pathname && paths_returned) {
+ res = _dwarf_construct_linkedto_path(
+ (char **)dbg->de_gnu_global_paths,
+ dbg->de_gnu_global_path_count,
+ pathname,
+ *debuglink_path_returned,
+ &debuglink_fullpath,
+ *crc_returned,
+ *buildid_returned,
+ *buildid_length_returned,
+ paths_returned,
+ paths_count_returned,
+ &errcode);
+ if(res != DW_DLV_OK) {
+ dwarfstring_destructor(&debuglink_fullpath);
+ return res;
+ }
+ if (dwarfstring_strlen(&debuglink_fullpath)) {
+ *debuglink_fullpath_returned =
+ strdup(dwarfstring_string(&debuglink_fullpath));
+ *debuglink_fullpath_length_returned =
+ dwarfstring_strlen(&debuglink_fullpath);
+ }
+ } else if (paths_count_returned) {
+ *paths_count_returned = 0;
+ }
+ dwarfstring_destructor(&debuglink_fullpath);
+ return DW_DLV_OK;
+}
+
+/* This should be rarely called and most likely
+ only once (at dbg init time from dwarf_generic_init.c,
+ see set_global_paths_init()).
+ Maybe once or twice later.
+*/
+int
+dwarf_add_debuglink_global_path(Dwarf_Debug dbg,
+ const char *pathname,
+ Dwarf_Error *error)
+{
+ unsigned glpath_count_in = 0;
+ unsigned glpath_count_out = 0;
+ const char **glpaths = 0;
+ const char * path1 = 0;
+
+ glpath_count_in = dbg->de_gnu_global_path_count;
+ glpath_count_out = glpath_count_in+1;
+ glpaths = (const char **)malloc(sizeof(char *)*
+ glpath_count_out);
+ if (!glpaths) {
+ _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL);
+ return DW_DLV_ERROR;
+ }
+ if (glpath_count_in) {
+ memcpy(glpaths, dbg->de_gnu_global_paths,
+ sizeof(char *)*glpath_count_in);
+ }
+ path1 = strdup(pathname);
+ if (!path1) {
+ free(glpaths);
+ _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL);
+ return DW_DLV_ERROR;
+ }
+ free((char *)dbg->de_gnu_global_paths);
+ glpaths[glpath_count_in] = path1;
+ dbg->de_gnu_global_paths = (const char **)glpaths;
+ dbg->de_gnu_global_path_count = glpath_count_out;
+ return DW_DLV_OK;
+}