PageRenderTime 24ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/external/elfutils/libdwfl/find-debuginfo.c

https://bitbucket.org/rlyspn/androidrr
C | 298 lines | 189 code | 24 blank | 85 comment | 59 complexity | db92077f6ec5d6425b48a618a4d10bed MD5 | raw file
  1. /* Standard find_debuginfo callback for libdwfl.
  2. Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
  3. This file is part of Red Hat elfutils.
  4. Red Hat elfutils is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; version 2 of the License.
  7. Red Hat elfutils is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with Red Hat elfutils; if not, write to the Free Software Foundation,
  13. Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
  14. In addition, as a special exception, Red Hat, Inc. gives You the
  15. additional right to link the code of Red Hat elfutils with code licensed
  16. under any Open Source Initiative certified open source license
  17. (http://www.opensource.org/licenses/index.php) which requires the
  18. distribution of source code with any binary distribution and to
  19. distribute linked combinations of the two. Non-GPL Code permitted under
  20. this exception must only link to the code of Red Hat elfutils through
  21. those well defined interfaces identified in the file named EXCEPTION
  22. found in the source code files (the "Approved Interfaces"). The files
  23. of Non-GPL Code may instantiate templates or use macros or inline
  24. functions from the Approved Interfaces without causing the resulting
  25. work to be covered by the GNU General Public License. Only Red Hat,
  26. Inc. may make changes or additions to the list of Approved Interfaces.
  27. Red Hat's grant of this exception is conditioned upon your not adding
  28. any new exceptions. If you wish to add a new Approved Interface or
  29. exception, please contact Red Hat. You must obey the GNU General Public
  30. License in all respects for all of the Red Hat elfutils code and other
  31. code used in conjunction with Red Hat elfutils except the Non-GPL Code
  32. covered by this exception. If you modify this file, you may extend this
  33. exception to your version of the file, but you are not obligated to do
  34. so. If you do not wish to provide this exception without modification,
  35. you must delete this exception statement from your version and license
  36. this file solely under the GPL without exception.
  37. Red Hat elfutils is an included package of the Open Invention Network.
  38. An included package of the Open Invention Network is a package for which
  39. Open Invention Network licensees cross-license their patents. No patent
  40. license is granted, either expressly or impliedly, by designation as an
  41. included package. Should you wish to participate in the Open Invention
  42. Network licensing program, please visit www.openinventionnetwork.com
  43. <http://www.openinventionnetwork.com>. */
  44. #include "libdwflP.h"
  45. #include <stdio.h>
  46. #include <fcntl.h>
  47. #include <unistd.h>
  48. #include "system.h"
  49. /* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
  50. On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */
  51. static int
  52. try_open (const char *dir, const char *subdir, const char *debuglink,
  53. char **debuginfo_file_name)
  54. {
  55. char *fname;
  56. if (dir == NULL && subdir == NULL)
  57. {
  58. fname = strdup (debuglink);
  59. if (fname == NULL)
  60. return -1;
  61. }
  62. else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
  63. : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
  64. : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
  65. return -1;
  66. int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
  67. if (fd < 0)
  68. free (fname);
  69. else
  70. *debuginfo_file_name = fname;
  71. return fd;
  72. }
  73. /* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
  74. static inline bool
  75. check_crc (int fd, GElf_Word debuglink_crc)
  76. {
  77. uint32_t file_crc;
  78. return (__libdwfl_crc32_file (fd, &file_crc) == 0
  79. && file_crc == debuglink_crc);
  80. }
  81. static bool
  82. validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
  83. {
  84. /* If we have a build ID, check only that. */
  85. if (mod->build_id_len > 0)
  86. {
  87. /* We need to open an Elf handle on the file so we can check its
  88. build ID note for validation. Backdoor the handle into the
  89. module data structure since we had to open it early anyway. */
  90. mod->debug.elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
  91. if (likely (__libdwfl_find_build_id (mod, false, mod->debug.elf) == 2))
  92. /* Also backdoor the gratuitous flag. */
  93. mod->debug.valid = true;
  94. else
  95. {
  96. /* A mismatch! */
  97. elf_end (mod->debug.elf);
  98. mod->debug.elf = NULL;
  99. mod->debug.valid = false;
  100. }
  101. return mod->debug.valid;
  102. }
  103. return !check || check_crc (fd, debuglink_crc);
  104. }
  105. static int
  106. find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
  107. const char *debuglink_file, GElf_Word debuglink_crc,
  108. char **debuginfo_file_name)
  109. {
  110. bool cancheck = debuglink_crc != (GElf_Word) 0;
  111. const char *file_basename = file_name == NULL ? NULL : basename (file_name);
  112. if (debuglink_file == NULL)
  113. {
  114. if (file_basename == NULL)
  115. {
  116. errno = 0;
  117. return -1;
  118. }
  119. size_t len = strlen (file_basename);
  120. char *localname = alloca (len + sizeof ".debug");
  121. memcpy (localname, file_basename, len);
  122. memcpy (&localname[len], ".debug", sizeof ".debug");
  123. debuglink_file = localname;
  124. cancheck = false;
  125. }
  126. /* Look for a file named DEBUGLINK_FILE in the directories
  127. indicated by the debug directory path setting. */
  128. const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
  129. /* ANDROID_CHANGE_BEGIN */
  130. #if defined(__BIONIC__) || defined(__APPLE__)
  131. char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
  132. ?: DEFAULT_DEBUGINFO_PATH);
  133. #else
  134. char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
  135. ?: DEFAULT_DEBUGINFO_PATH);
  136. #endif
  137. /* ANDROID_CHANGE_END */
  138. /* A leading - or + in the whole path sets whether to check file CRCs. */
  139. bool defcheck = true;
  140. if (path[0] == '-' || path[0] == '+')
  141. {
  142. defcheck = path[0] == '+';
  143. ++path;
  144. }
  145. /* ANDROID_CHANGE_BEGIN */
  146. #if defined(__BIONIC__) || defined(__APPLE__)
  147. char *file_dirname = (file_basename == file_name ? NULL
  148. : strndup (file_name, file_basename - 1 - file_name));
  149. #else
  150. char *file_dirname = (file_basename == file_name ? NULL
  151. : strndupa (file_name, file_basename - 1 - file_name));
  152. #endif
  153. /* ANDROID_CHANGE_END */
  154. char *p;
  155. while ((p = strsep (&path, ":")) != NULL)
  156. {
  157. /* A leading - or + says whether to check file CRCs for this element. */
  158. bool check = defcheck;
  159. if (*p == '+' || *p == '-')
  160. check = *p++ == '+';
  161. check = check && cancheck;
  162. const char *dir, *subdir;
  163. switch (p[0])
  164. {
  165. case '\0':
  166. /* An empty entry says to try the main file's directory. */
  167. dir = file_dirname;
  168. subdir = NULL;
  169. break;
  170. case '/':
  171. /* An absolute path says to look there for a subdirectory
  172. named by the main file's absolute directory.
  173. This cannot be applied to a relative file name. */
  174. if (file_dirname == NULL || file_dirname[0] != '/')
  175. continue;
  176. dir = p;
  177. subdir = file_dirname + 1;
  178. break;
  179. default:
  180. /* A relative path says to try a subdirectory of that name
  181. in the main file's directory. */
  182. dir = file_dirname;
  183. subdir = p;
  184. break;
  185. }
  186. /* ANDROID_CHANGE_BEGIN */
  187. char *fname = NULL;
  188. /* ANDROID_CHANGE_END */
  189. int fd = try_open (dir, subdir, debuglink_file, &fname);
  190. if (fd < 0)
  191. switch (errno)
  192. {
  193. case ENOENT:
  194. case ENOTDIR:
  195. continue;
  196. default:
  197. /* ANDROID_CHANGE_BEGIN */
  198. #ifdef __BIONIC__
  199. free(path);
  200. free(file_dirname);
  201. #endif
  202. /* ANDROID_CHANGE_END */
  203. return -1;
  204. }
  205. if (validate (mod, fd, check, debuglink_crc))
  206. {
  207. *debuginfo_file_name = fname;
  208. /* ANDROID_CHANGE_BEGIN */
  209. #ifdef __BIONIC__
  210. free(path);
  211. free(file_dirname);
  212. #endif
  213. /* ANDROID_CHANGE_END */
  214. return fd;
  215. }
  216. free (fname);
  217. close (fd);
  218. }
  219. /* ANDROID_CHANGE_BEGIN */
  220. #ifdef __BIONIC__
  221. free(path);
  222. free(file_dirname);
  223. #endif
  224. /* ANDROID_CHANGE_END */
  225. /* No dice. */
  226. errno = 0;
  227. return -1;
  228. }
  229. int
  230. dwfl_standard_find_debuginfo (Dwfl_Module *mod,
  231. void **userdata __attribute__ ((unused)),
  232. const char *modname __attribute__ ((unused)),
  233. GElf_Addr base __attribute__ ((unused)),
  234. const char *file_name,
  235. const char *debuglink_file,
  236. GElf_Word debuglink_crc,
  237. char **debuginfo_file_name)
  238. {
  239. /* First try by build ID if we have one. If that succeeds or fails
  240. other than just by finding nothing, that's all we do. */
  241. const unsigned char *bits;
  242. GElf_Addr vaddr;
  243. if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
  244. {
  245. int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
  246. NULL, NULL, 0,
  247. NULL, NULL, 0,
  248. debuginfo_file_name);
  249. if (fd >= 0 || errno != 0)
  250. return fd;
  251. }
  252. /* Failing that, search the path by name. */
  253. int fd = find_debuginfo_in_path (mod, file_name,
  254. debuglink_file, debuglink_crc,
  255. debuginfo_file_name);
  256. if (fd < 0 && errno == 0)
  257. {
  258. /* If FILE_NAME is a symlink, the debug file might be associated
  259. with the symlink target name instead. */
  260. char *canon = canonicalize_file_name (file_name);
  261. if (canon != NULL && strcmp (file_name, canon))
  262. fd = find_debuginfo_in_path (mod, canon,
  263. debuglink_file, debuglink_crc,
  264. debuginfo_file_name);
  265. free (canon);
  266. }
  267. return fd;
  268. }
  269. INTDEF (dwfl_standard_find_debuginfo)