Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame^] | 1 | /* 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. */ |
| 26 | static int |
| 27 | try_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. */ |
| 53 | static inline bool |
| 54 | check_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 | |
| 60 | int |
| 61 | dwfl_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 | } |
| 157 | INTDEF (dwfl_standard_find_debuginfo) |