llvm-c-helpers.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Must come before the linux/compiler.h include, which defines several
  4. * macros (e.g. noinline) that conflict with compiler builtins used
  5. * by LLVM.
  6. */
  7. #pragma GCC diagnostic push
  8. #pragma GCC diagnostic ignored "-Wunused-parameter" /* Needed for LLVM <= 15 */
  9. #include <llvm/DebugInfo/Symbolize/Symbolize.h>
  10. #include <llvm/Support/TargetSelect.h>
  11. #pragma GCC diagnostic pop
  12. #include <inttypes.h>
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include <linux/compiler.h>
  16. extern "C" {
  17. #include <linux/zalloc.h>
  18. }
  19. #include "llvm-c-helpers.h"
  20. extern "C"
  21. char *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name);
  22. using namespace llvm;
  23. using llvm::symbolize::LLVMSymbolizer;
  24. /*
  25. * Allocate a static LLVMSymbolizer, which will live to the end of the program.
  26. * Unlike the bfd paths, LLVMSymbolizer has its own cache, so we do not need
  27. * to store anything in the dso struct.
  28. */
  29. static LLVMSymbolizer *get_symbolizer()
  30. {
  31. static LLVMSymbolizer *instance = nullptr;
  32. if (instance == nullptr) {
  33. LLVMSymbolizer::Options opts;
  34. /*
  35. * LLVM sometimes demangles slightly different from the rest
  36. * of the code, and this mismatch can cause new_inline_sym()
  37. * to get confused and mark non-inline symbol as inlined
  38. * (since the name does not properly match up with base_sym).
  39. * Thus, disable the demangling and let the rest of the code
  40. * handle it.
  41. */
  42. opts.Demangle = false;
  43. instance = new LLVMSymbolizer(opts);
  44. }
  45. return instance;
  46. }
  47. /* Returns 0 on error, 1 on success. */
  48. static int extract_file_and_line(const DILineInfo &line_info, char **file,
  49. unsigned int *line)
  50. {
  51. if (file) {
  52. if (line_info.FileName == "<invalid>") {
  53. /* Match the convention of libbfd. */
  54. *file = nullptr;
  55. } else {
  56. /* The caller expects to get something it can free(). */
  57. *file = strdup(line_info.FileName.c_str());
  58. if (*file == nullptr)
  59. return 0;
  60. }
  61. }
  62. if (line)
  63. *line = line_info.Line;
  64. return 1;
  65. }
  66. extern "C"
  67. int llvm_addr2line(const char *dso_name, u64 addr,
  68. char **file, unsigned int *line,
  69. bool unwind_inlines,
  70. llvm_a2l_frame **inline_frames)
  71. {
  72. LLVMSymbolizer *symbolizer = get_symbolizer();
  73. object::SectionedAddress sectioned_addr = {
  74. addr,
  75. object::SectionedAddress::UndefSection
  76. };
  77. if (unwind_inlines) {
  78. Expected<DIInliningInfo> res_or_err =
  79. symbolizer->symbolizeInlinedCode(dso_name,
  80. sectioned_addr);
  81. if (!res_or_err)
  82. return 0;
  83. unsigned num_frames = res_or_err->getNumberOfFrames();
  84. if (num_frames == 0)
  85. return 0;
  86. if (extract_file_and_line(res_or_err->getFrame(0),
  87. file, line) == 0)
  88. return 0;
  89. *inline_frames = (llvm_a2l_frame *)calloc(
  90. num_frames, sizeof(**inline_frames));
  91. if (*inline_frames == nullptr)
  92. return 0;
  93. for (unsigned i = 0; i < num_frames; ++i) {
  94. const DILineInfo &src = res_or_err->getFrame(i);
  95. llvm_a2l_frame &dst = (*inline_frames)[i];
  96. if (src.FileName == "<invalid>")
  97. /* Match the convention of libbfd. */
  98. dst.filename = nullptr;
  99. else
  100. dst.filename = strdup(src.FileName.c_str());
  101. dst.funcname = strdup(src.FunctionName.c_str());
  102. dst.line = src.Line;
  103. if (dst.filename == nullptr ||
  104. dst.funcname == nullptr) {
  105. for (unsigned j = 0; j <= i; ++j) {
  106. zfree(&(*inline_frames)[j].filename);
  107. zfree(&(*inline_frames)[j].funcname);
  108. }
  109. zfree(inline_frames);
  110. return 0;
  111. }
  112. }
  113. return num_frames;
  114. } else {
  115. if (inline_frames)
  116. *inline_frames = nullptr;
  117. Expected<DILineInfo> res_or_err =
  118. symbolizer->symbolizeCode(dso_name, sectioned_addr);
  119. if (!res_or_err)
  120. return 0;
  121. return extract_file_and_line(*res_or_err, file, line);
  122. }
  123. }
  124. static char *
  125. make_symbol_relative_string(struct dso *dso, const char *sym_name,
  126. u64 addr, u64 base_addr)
  127. {
  128. if (!strcmp(sym_name, "<invalid>"))
  129. return NULL;
  130. char *demangled = dso__demangle_sym(dso, 0, sym_name);
  131. if (base_addr && base_addr != addr) {
  132. char buf[256];
  133. snprintf(buf, sizeof(buf), "%s+0x%" PRIx64,
  134. demangled ? demangled : sym_name, addr - base_addr);
  135. free(demangled);
  136. return strdup(buf);
  137. } else {
  138. if (demangled)
  139. return demangled;
  140. else
  141. return strdup(sym_name);
  142. }
  143. }
  144. extern "C"
  145. char *llvm_name_for_code(struct dso *dso, const char *dso_name, u64 addr)
  146. {
  147. LLVMSymbolizer *symbolizer = get_symbolizer();
  148. object::SectionedAddress sectioned_addr = {
  149. addr,
  150. object::SectionedAddress::UndefSection
  151. };
  152. Expected<DILineInfo> res_or_err =
  153. symbolizer->symbolizeCode(dso_name, sectioned_addr);
  154. if (!res_or_err) {
  155. return NULL;
  156. }
  157. return make_symbol_relative_string(
  158. dso, res_or_err->FunctionName.c_str(),
  159. addr, res_or_err->StartAddress ? *res_or_err->StartAddress : 0);
  160. }
  161. extern "C"
  162. char *llvm_name_for_data(struct dso *dso, const char *dso_name, u64 addr)
  163. {
  164. LLVMSymbolizer *symbolizer = get_symbolizer();
  165. object::SectionedAddress sectioned_addr = {
  166. addr,
  167. object::SectionedAddress::UndefSection
  168. };
  169. Expected<DIGlobal> res_or_err =
  170. symbolizer->symbolizeData(dso_name, sectioned_addr);
  171. if (!res_or_err) {
  172. return NULL;
  173. }
  174. return make_symbol_relative_string(
  175. dso, res_or_err->Name.c_str(),
  176. addr, res_or_err->Start);
  177. }