1da0c48c4Sopenharmony_ci/* Retrieves the DWARF descriptor for debugaltlink data.
2da0c48c4Sopenharmony_ci   Copyright (C) 2014, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include "libdwP.h"
34da0c48c4Sopenharmony_ci#include "libelfP.h"
35da0c48c4Sopenharmony_ci#include "libdwelfP.h"
36da0c48c4Sopenharmony_ci#include "system.h"
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci#include <inttypes.h>
39da0c48c4Sopenharmony_ci#include <fcntl.h>
40da0c48c4Sopenharmony_ci#include <limits.h>
41da0c48c4Sopenharmony_ci#include <stdlib.h>
42da0c48c4Sopenharmony_ci#include <stdio.h>
43da0c48c4Sopenharmony_ci#include <string.h>
44da0c48c4Sopenharmony_ci#include <sys/types.h>
45da0c48c4Sopenharmony_ci#include <sys/stat.h>
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_cichar *
49da0c48c4Sopenharmony_ciinternal_function
50da0c48c4Sopenharmony_ci__libdw_filepath (const char *debugdir, const char *dir, const char *file)
51da0c48c4Sopenharmony_ci{
52da0c48c4Sopenharmony_ci  if (file == NULL)
53da0c48c4Sopenharmony_ci    return NULL;
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci  if (file[0] == '/')
56da0c48c4Sopenharmony_ci    return strdup (file);
57da0c48c4Sopenharmony_ci
58da0c48c4Sopenharmony_ci  if (dir != NULL && dir[0] == '/')
59da0c48c4Sopenharmony_ci    {
60da0c48c4Sopenharmony_ci      size_t dirlen = strlen (dir);
61da0c48c4Sopenharmony_ci      size_t filelen = strlen (file);
62da0c48c4Sopenharmony_ci      size_t len = dirlen + 1 + filelen + 1;
63da0c48c4Sopenharmony_ci      char *path = malloc (len);
64da0c48c4Sopenharmony_ci      if (path != NULL)
65da0c48c4Sopenharmony_ci	{
66da0c48c4Sopenharmony_ci	  char *c = mempcpy (path, dir, dirlen);
67da0c48c4Sopenharmony_ci	  if (dir[dirlen - 1] != '/')
68da0c48c4Sopenharmony_ci	    *c++ = '/';
69da0c48c4Sopenharmony_ci	  mempcpy (c, file, filelen + 1);
70da0c48c4Sopenharmony_ci	}
71da0c48c4Sopenharmony_ci      return path;
72da0c48c4Sopenharmony_ci    }
73da0c48c4Sopenharmony_ci
74da0c48c4Sopenharmony_ci  if (debugdir != NULL)
75da0c48c4Sopenharmony_ci    {
76da0c48c4Sopenharmony_ci      size_t debugdirlen = strlen (debugdir);
77da0c48c4Sopenharmony_ci      size_t dirlen = dir != NULL ? strlen (dir) : 0;
78da0c48c4Sopenharmony_ci      size_t filelen = strlen (file);
79da0c48c4Sopenharmony_ci      size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
80da0c48c4Sopenharmony_ci      char *path = malloc (len);
81da0c48c4Sopenharmony_ci      if (path != NULL)
82da0c48c4Sopenharmony_ci	{
83da0c48c4Sopenharmony_ci	  char *c = mempcpy (path, debugdir, debugdirlen);
84da0c48c4Sopenharmony_ci	  if (dirlen > 0)
85da0c48c4Sopenharmony_ci	    {
86da0c48c4Sopenharmony_ci	      c = mempcpy (c, dir, dirlen);
87da0c48c4Sopenharmony_ci	      if (dir[dirlen - 1] != '/')
88da0c48c4Sopenharmony_ci		*c++ = '/';
89da0c48c4Sopenharmony_ci	    }
90da0c48c4Sopenharmony_ci	  mempcpy (c, file, filelen + 1);
91da0c48c4Sopenharmony_ci	  return path;
92da0c48c4Sopenharmony_ci	}
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  return NULL;
96da0c48c4Sopenharmony_ci}
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_cistatic void
99da0c48c4Sopenharmony_cifind_debug_altlink (Dwarf *dbg)
100da0c48c4Sopenharmony_ci{
101da0c48c4Sopenharmony_ci  const char *altname;
102da0c48c4Sopenharmony_ci  const void *build_id;
103da0c48c4Sopenharmony_ci  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
104da0c48c4Sopenharmony_ci							       &altname,
105da0c48c4Sopenharmony_ci							       &build_id);
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci  /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
108da0c48c4Sopenharmony_ci  if (build_id_len <= 0)
109da0c48c4Sopenharmony_ci    return;
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci  const uint8_t *id = (const uint8_t *) build_id;
112da0c48c4Sopenharmony_ci  size_t id_len = build_id_len;
113da0c48c4Sopenharmony_ci  int fd = -1;
114da0c48c4Sopenharmony_ci
115da0c48c4Sopenharmony_ci  /* We only look in the standard path.  And relative to the dbg file.  */
116da0c48c4Sopenharmony_ci#define DEBUGINFO_PATH "/usr/lib/debug"
117da0c48c4Sopenharmony_ci
118da0c48c4Sopenharmony_ci  /* We don't handle very short or really large build-ids.  We need at
119da0c48c4Sopenharmony_ci     at least 3 and allow for up to 64 (normally ids are 20 long).  */
120da0c48c4Sopenharmony_ci#define MIN_BUILD_ID_BYTES 3
121da0c48c4Sopenharmony_ci#define MAX_BUILD_ID_BYTES 64
122da0c48c4Sopenharmony_ci  if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
123da0c48c4Sopenharmony_ci    {
124da0c48c4Sopenharmony_ci      /* Note sizeof a string literal includes the trailing zero.  */
125da0c48c4Sopenharmony_ci      char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
126da0c48c4Sopenharmony_ci		   + 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"];
127da0c48c4Sopenharmony_ci      sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
128da0c48c4Sopenharmony_ci      sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
129da0c48c4Sopenharmony_ci	       "%02" PRIx8 "/", (uint8_t) id[0]);
130da0c48c4Sopenharmony_ci      for (size_t i = 1; i < id_len; ++i)
131da0c48c4Sopenharmony_ci	sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
132da0c48c4Sopenharmony_ci			  + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
133da0c48c4Sopenharmony_ci      strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
134da0c48c4Sopenharmony_ci		       + 3 + (id_len - 1) * 2], ".debug");
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci      fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
137da0c48c4Sopenharmony_ci    }
138da0c48c4Sopenharmony_ci
139da0c48c4Sopenharmony_ci  /* Fall back on (possible relative) alt file path.  */
140da0c48c4Sopenharmony_ci  if (fd < 0)
141da0c48c4Sopenharmony_ci    {
142da0c48c4Sopenharmony_ci      char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
143da0c48c4Sopenharmony_ci      if (altpath != NULL)
144da0c48c4Sopenharmony_ci	{
145da0c48c4Sopenharmony_ci	  fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
146da0c48c4Sopenharmony_ci	  free (altpath);
147da0c48c4Sopenharmony_ci	}
148da0c48c4Sopenharmony_ci    }
149da0c48c4Sopenharmony_ci
150da0c48c4Sopenharmony_ci  if (fd >= 0)
151da0c48c4Sopenharmony_ci    {
152da0c48c4Sopenharmony_ci      Dwarf *alt = dwarf_begin (fd, O_RDONLY);
153da0c48c4Sopenharmony_ci      if (alt != NULL)
154da0c48c4Sopenharmony_ci	{
155da0c48c4Sopenharmony_ci	  dbg->alt_dwarf = alt;
156da0c48c4Sopenharmony_ci	  dbg->alt_fd = fd;
157da0c48c4Sopenharmony_ci	}
158da0c48c4Sopenharmony_ci      else
159da0c48c4Sopenharmony_ci	close (fd);
160da0c48c4Sopenharmony_ci    }
161da0c48c4Sopenharmony_ci}
162da0c48c4Sopenharmony_ci
163da0c48c4Sopenharmony_ciDwarf *
164da0c48c4Sopenharmony_cidwarf_getalt (Dwarf *main)
165da0c48c4Sopenharmony_ci{
166da0c48c4Sopenharmony_ci  /* Only try once.  */
167da0c48c4Sopenharmony_ci  if (main == NULL || main->alt_dwarf == (void *) -1)
168da0c48c4Sopenharmony_ci    return NULL;
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci  if (main->alt_dwarf != NULL)
171da0c48c4Sopenharmony_ci    return main->alt_dwarf;
172da0c48c4Sopenharmony_ci
173da0c48c4Sopenharmony_ci  find_debug_altlink (main);
174da0c48c4Sopenharmony_ci
175da0c48c4Sopenharmony_ci  /* If we found nothing, make sure we don't try again.  */
176da0c48c4Sopenharmony_ci  if (main->alt_dwarf == NULL)
177da0c48c4Sopenharmony_ci    {
178da0c48c4Sopenharmony_ci      main->alt_dwarf = (void *) -1;
179da0c48c4Sopenharmony_ci      return NULL;
180da0c48c4Sopenharmony_ci    }
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci  return main->alt_dwarf;
183da0c48c4Sopenharmony_ci}
184da0c48c4Sopenharmony_ciINTDEF (dwarf_getalt)
185