debuginfo.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * DWARF debug information handling code. Copied from probe-finder.c.
  4. *
  5. * Written by Masami Hiramatsu <mhiramat@redhat.com>
  6. */
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <linux/zalloc.h>
  14. #include "build-id.h"
  15. #include "dso.h"
  16. #include "debug.h"
  17. #include "debuginfo.h"
  18. #include "symbol.h"
  19. #ifdef HAVE_DEBUGINFOD_SUPPORT
  20. #include <elfutils/debuginfod.h>
  21. #endif
  22. /* Dwarf FL wrappers */
  23. static char *debuginfo_path; /* Currently dummy */
  24. static const Dwfl_Callbacks offline_callbacks = {
  25. .find_debuginfo = dwfl_standard_find_debuginfo,
  26. .debuginfo_path = &debuginfo_path,
  27. .section_address = dwfl_offline_section_address,
  28. /* We use this table for core files too. */
  29. .find_elf = dwfl_build_id_find_elf,
  30. };
  31. /* Get a Dwarf from offline image */
  32. static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
  33. const char *path)
  34. {
  35. GElf_Addr dummy;
  36. int fd;
  37. fd = open(path, O_RDONLY);
  38. if (fd < 0)
  39. return fd;
  40. dbg->dwfl = dwfl_begin(&offline_callbacks);
  41. if (!dbg->dwfl)
  42. goto error;
  43. dwfl_report_begin(dbg->dwfl);
  44. dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
  45. if (!dbg->mod)
  46. goto error;
  47. dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
  48. if (!dbg->dbg)
  49. goto error;
  50. dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);
  51. dwfl_report_end(dbg->dwfl, NULL, NULL);
  52. return 0;
  53. error:
  54. if (dbg->dwfl)
  55. dwfl_end(dbg->dwfl);
  56. else
  57. close(fd);
  58. memset(dbg, 0, sizeof(*dbg));
  59. return -ENOENT;
  60. }
  61. static struct debuginfo *__debuginfo__new(const char *path)
  62. {
  63. struct debuginfo *dbg = zalloc(sizeof(*dbg));
  64. if (!dbg)
  65. return NULL;
  66. if (debuginfo__init_offline_dwarf(dbg, path) < 0)
  67. zfree(&dbg);
  68. if (dbg)
  69. pr_debug("Open Debuginfo file: %s\n", path);
  70. return dbg;
  71. }
  72. enum dso_binary_type distro_dwarf_types[] = {
  73. DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
  74. DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
  75. DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
  76. DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
  77. DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
  78. DSO_BINARY_TYPE__NOT_FOUND,
  79. };
  80. struct debuginfo *debuginfo__new(const char *path)
  81. {
  82. enum dso_binary_type *type;
  83. char buf[PATH_MAX], nil = '\0';
  84. struct dso *dso;
  85. struct debuginfo *dinfo = NULL;
  86. struct build_id bid = { .size = 0};
  87. /* Try to open distro debuginfo files */
  88. dso = dso__new(path);
  89. if (!dso)
  90. goto out;
  91. /*
  92. * Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO. Don't block
  93. * incase the path isn't for a regular file.
  94. */
  95. assert(!dso__has_build_id(dso));
  96. if (filename__read_build_id(path, &bid) > 0)
  97. dso__set_build_id(dso, &bid);
  98. for (type = distro_dwarf_types;
  99. !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
  100. type++) {
  101. if (dso__read_binary_type_filename(dso, *type, &nil,
  102. buf, PATH_MAX) < 0)
  103. continue;
  104. dinfo = __debuginfo__new(buf);
  105. }
  106. dso__put(dso);
  107. out:
  108. if (dinfo)
  109. return dinfo;
  110. /* if failed to open all distro debuginfo, open given binary */
  111. symbol__join_symfs(buf, path);
  112. return __debuginfo__new(buf);
  113. }
  114. void debuginfo__delete(struct debuginfo *dbg)
  115. {
  116. if (dbg) {
  117. if (dbg->dwfl)
  118. dwfl_end(dbg->dwfl);
  119. free(dbg);
  120. }
  121. }
  122. /* For the kernel module, we need a special code to get a DIE */
  123. int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
  124. bool adjust_offset)
  125. {
  126. int n, i;
  127. Elf32_Word shndx;
  128. Elf_Scn *scn;
  129. Elf *elf;
  130. GElf_Shdr mem, *shdr;
  131. const char *p;
  132. elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
  133. if (!elf)
  134. return -EINVAL;
  135. /* Get the number of relocations */
  136. n = dwfl_module_relocations(dbg->mod);
  137. if (n < 0)
  138. return -ENOENT;
  139. /* Search the relocation related .text section */
  140. for (i = 0; i < n; i++) {
  141. p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
  142. if (strcmp(p, ".text") == 0) {
  143. /* OK, get the section header */
  144. scn = elf_getscn(elf, shndx);
  145. if (!scn)
  146. return -ENOENT;
  147. shdr = gelf_getshdr(scn, &mem);
  148. if (!shdr)
  149. return -ENOENT;
  150. *offs = shdr->sh_addr;
  151. if (adjust_offset)
  152. *offs -= shdr->sh_offset;
  153. }
  154. }
  155. return 0;
  156. }
  157. #ifdef HAVE_DEBUGINFOD_SUPPORT
  158. int get_source_from_debuginfod(const char *raw_path,
  159. const char *sbuild_id, char **new_path)
  160. {
  161. debuginfod_client *c = debuginfod_begin();
  162. const char *p = raw_path;
  163. int fd;
  164. if (!c)
  165. return -ENOMEM;
  166. fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
  167. 0, p, new_path);
  168. pr_debug("Search %s from debuginfod -> %d\n", p, fd);
  169. if (fd >= 0)
  170. close(fd);
  171. debuginfod_end(c);
  172. if (fd < 0) {
  173. pr_debug("Failed to find %s in debuginfod (%s)\n",
  174. raw_path, sbuild_id);
  175. return -ENOENT;
  176. }
  177. pr_debug("Got a source %s\n", *new_path);
  178. return 0;
  179. }
  180. #endif /* HAVE_DEBUGINFOD_SUPPORT */