blob: c9e640dd106f130e8ddf6c3791509cbb2a75d870 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Standard find_debuginfo callback for libdwfl.
2 Copyright (C) 2005 Red Hat, Inc.
3
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
7
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
13
14#include "libdwflP.h"
15#include <stdio.h>
16#include <fcntl.h>
17#include <unistd.h>
18#include "system.h"
19
20
21#define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug"
22
23
24/* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
25 On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */
26static int
27try_open (const char *dir, const char *subdir, const char *debuglink,
28 char **debuginfo_file_name)
29{
30 char *fname = NULL;
31 if (dir == NULL && subdir == NULL)
32 fname = strdup (debuglink);
33 else if (subdir == NULL)
34 asprintf (&fname, "%s/%s", dir, debuglink);
35 else if (dir == NULL)
36 asprintf (&fname, "%s/%s", subdir, debuglink);
37 else
38 asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink);
39
40 if (fname == NULL)
41 return -1;
42
43 int fd = open64 (fname, O_RDONLY);
44 if (fd < 0)
45 free (fname);
46 else
47 *debuginfo_file_name = fname;
48
49 return fd;
50}
51
52/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
53static inline bool
54check_crc (int fd, GElf_Word debuglink_crc)
55{
56 uint32_t file_crc;
57 return crc32_file (fd, &file_crc) == 0 && file_crc == debuglink_crc;
58}
59
60int
61dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
62 void **userdata __attribute__ ((unused)),
63 const char *modname __attribute__ ((unused)),
64 GElf_Addr base __attribute__ ((unused)),
65 const char *file_name,
66 const char *debuglink_file,
67 GElf_Word debuglink_crc,
68 char **debuginfo_file_name)
69{
70 bool cancheck = true;
71
72 const char *file_basename = file_name == NULL ? NULL : basename (file_name);
73 if (debuglink_file == NULL)
74 {
75 if (file_basename == NULL)
76 {
77 errno = 0;
78 return -1;
79 }
80
81 size_t len = strlen (file_basename);
82 char *localname = alloca (len + sizeof ".debug");
83 memcpy (localname, file_basename, len);
84 memcpy (&localname[len], ".debug", sizeof ".debug");
85 debuglink_file = localname;
86 cancheck = false;
87 }
88
89 /* Look for a file named DEBUGLINK_FILE in the directories
90 indicated by the debug directory path setting. */
91
92 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
93 char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
94 ?: DEFAULT_DEBUGINFO_PATH);
95
96 /* A leading - or + in the whole path sets whether to check file CRCs. */
97 bool defcheck = true;
98 if (path[0] == '-' || path[0] == '+')
99 {
100 defcheck = path[0] == '+';
101 ++path;
102 }
103
104 char *file_dirname = (file_basename == file_name ? NULL
105 : strndupa (file_name, file_basename - 1 - file_name));
106 char *p;
107 while ((p = strsep (&path, ":")) != NULL)
108 {
109 /* A leading - or + says whether to check file CRCs for this element. */
110 bool check = defcheck;
111 if (*p == '+' || *p == '-')
112 check = *p++ == '+';
113 check = check && cancheck;
114
115 const char *dir, *subdir;
116 switch (p[0])
117 {
118 case '\0':
119 /* An empty entry says to try the main file's directory. */
120 dir = file_dirname;
121 subdir = NULL;
122 break;
123 case '/':
124 /* An absolute path says to look there for a subdirectory
125 named by the main file's absolute directory.
126 This cannot be applied to a relative file name. */
127 if (file_dirname == NULL || file_dirname[0] != '/')
128 continue;
129 dir = p;
130 subdir = file_dirname + 1;
131 break;
132 default:
133 /* A relative path says to try a subdirectory of that name
134 in the main file's directory. */
135 dir = file_dirname;
136 subdir = p;
137 break;
138 }
139
140 char *fname;
141 int fd = try_open (dir, subdir, debuglink_file, &fname);
142 if (fd < 0)
143 continue;
144 if (!check || check_crc (fd, debuglink_crc))
145 {
146 *debuginfo_file_name = fname;
147 return fd;
148 }
149 free (fname);
150 close (fd);
151 }
152
153 /* No dice. */
154 errno = 0;
155 return -1;
156}
157INTDEF (dwfl_standard_find_debuginfo)