#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "libdwP.h"
#include "libelfP.h"
#include "libdwelfP.h"
#include "system.h"
#include <inttypes.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
char *
internal_function
__libdw_filepath (const char *debugdir, const char *dir, const char *file)
{
if (file == NULL)
return NULL;
if (file[0] == '/')
return strdup (file);
if (dir != NULL && dir[0] == '/')
{
size_t dirlen = strlen (dir);
size_t filelen = strlen (file);
size_t len = dirlen + 1 + filelen + 1;
char *path = malloc (len);
if (path != NULL)
{
char *c = mempcpy (path, dir, dirlen);
if (dir[dirlen - 1] != '/')
*c++ = '/';
mempcpy (c, file, filelen + 1);
}
return path;
}
if (debugdir != NULL)
{
size_t debugdirlen = strlen (debugdir);
size_t dirlen = dir != NULL ? strlen (dir) : 0;
size_t filelen = strlen (file);
size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
char *path = malloc (len);
if (path != NULL)
{
char *c = mempcpy (path, debugdir, debugdirlen);
if (dirlen > 0)
{
c = mempcpy (c, dir, dirlen);
if (dir[dirlen - 1] != '/')
*c++ = '/';
}
mempcpy (c, file, filelen + 1);
return path;
}
}
return NULL;
}
static void
find_debug_altlink (Dwarf *dbg)
{
const char *altname;
const void *build_id;
ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
&altname,
&build_id);
if (build_id_len <= 0)
return;
const uint8_t *id = (const uint8_t *) build_id;
size_t id_len = build_id_len;
int fd = -1;
#define DEBUGINFO_PATH "/usr/lib/debug"
#define MIN_BUILD_ID_BYTES 3
#define MAX_BUILD_ID_BYTES 64
if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
{
char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"];
sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
"%02" PRIx8 "/", (uint8_t) id[0]);
for (size_t i = 1; i < id_len; ++i)
sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ 3 + (id_len - 1) * 2], ".debug");
fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
}
if (fd < 0)
{
char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
if (altpath != NULL)
{
fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
free (altpath);
}
}
if (fd >= 0)
{
Dwarf *alt = dwarf_begin (fd, O_RDONLY);
if (alt != NULL)
{
dbg->alt_dwarf = alt;
dbg->alt_fd = fd;
}
else
close (fd);
}
}
Dwarf *
dwarf_getalt (Dwarf *main)
{
if (main == NULL || main->alt_dwarf == (void *) -1)
return NULL;
if (main->alt_dwarf != NULL)
return main->alt_dwarf;
find_debug_altlink (main);
if (main->alt_dwarf == NULL)
{
main->alt_dwarf = (void *) -1;
return NULL;
}
return main->alt_dwarf;
}
INTDEF (dwarf_getalt)