addr2line.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "addr2line.h"
  3. #include "debug.h"
  4. #include "dso.h"
  5. #include "string2.h"
  6. #include "srcline.h"
  7. #include "symbol.h"
  8. #include "symbol_conf.h"
  9. #include <api/io.h>
  10. #include <linux/zalloc.h>
  11. #include <subcmd/run-command.h>
  12. #include <inttypes.h>
  13. #include <signal.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #define MAX_INLINE_NEST 1024
  17. /* If addr2line doesn't return data for 5 seconds then timeout. */
  18. int addr2line_timeout_ms = 5 * 1000;
  19. static int filename_split(char *filename, unsigned int *line_nr)
  20. {
  21. char *sep;
  22. sep = strchr(filename, '\n');
  23. if (sep)
  24. *sep = '\0';
  25. if (!strcmp(filename, "??:0"))
  26. return 0;
  27. sep = strchr(filename, ':');
  28. if (sep) {
  29. *sep++ = '\0';
  30. *line_nr = strtoul(sep, NULL, 0);
  31. return 1;
  32. }
  33. pr_debug("addr2line missing ':' in filename split\n");
  34. return 0;
  35. }
  36. static void addr2line_subprocess_cleanup(struct child_process *a2l)
  37. {
  38. if (a2l->pid != -1) {
  39. kill(a2l->pid, SIGKILL);
  40. finish_command(a2l); /* ignore result, we don't care */
  41. a2l->pid = -1;
  42. close(a2l->in);
  43. close(a2l->out);
  44. }
  45. free(a2l);
  46. }
  47. static struct child_process *addr2line_subprocess_init(const char *addr2line_path,
  48. const char *binary_path)
  49. {
  50. const char *argv[] = {
  51. addr2line_path ?: "addr2line",
  52. "-e", binary_path,
  53. "-a", "-i", "-f", NULL
  54. };
  55. struct child_process *a2l = zalloc(sizeof(*a2l));
  56. int start_command_status = 0;
  57. if (a2l == NULL) {
  58. pr_err("Failed to allocate memory for addr2line");
  59. return NULL;
  60. }
  61. a2l->pid = -1;
  62. a2l->in = -1;
  63. a2l->out = -1;
  64. a2l->no_stderr = 1;
  65. a2l->argv = argv;
  66. start_command_status = start_command(a2l);
  67. a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */
  68. if (start_command_status != 0) {
  69. pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n",
  70. addr2line_path, binary_path, start_command_status);
  71. addr2line_subprocess_cleanup(a2l);
  72. return NULL;
  73. }
  74. return a2l;
  75. }
  76. enum cmd_a2l_style {
  77. BROKEN,
  78. GNU_BINUTILS,
  79. LLVM,
  80. };
  81. static enum cmd_a2l_style cmd_addr2line_configure(struct child_process *a2l, const char *dso_name)
  82. {
  83. static bool cached;
  84. static enum cmd_a2l_style style;
  85. if (!cached) {
  86. char buf[128];
  87. struct io io;
  88. int ch;
  89. int lines;
  90. if (write(a2l->in, ",\n", 2) != 2)
  91. return BROKEN;
  92. io__init(&io, a2l->out, buf, sizeof(buf));
  93. ch = io__get_char(&io);
  94. if (ch == ',') {
  95. style = LLVM;
  96. cached = true;
  97. lines = 1;
  98. pr_debug3("Detected LLVM addr2line style\n");
  99. } else if (ch == '0') {
  100. style = GNU_BINUTILS;
  101. cached = true;
  102. lines = 3;
  103. pr_debug3("Detected binutils addr2line style\n");
  104. } else {
  105. if (!symbol_conf.disable_add2line_warn) {
  106. char *output = NULL;
  107. size_t output_len;
  108. io__getline(&io, &output, &output_len);
  109. pr_warning("%s %s: addr2line configuration failed\n",
  110. __func__, dso_name);
  111. pr_warning("\t%c%s", ch, output);
  112. }
  113. pr_debug("Unknown/broken addr2line style\n");
  114. return BROKEN;
  115. }
  116. while (lines) {
  117. ch = io__get_char(&io);
  118. if (ch <= 0)
  119. break;
  120. if (ch == '\n')
  121. lines--;
  122. }
  123. /* Ignore SIGPIPE in the event addr2line exits. */
  124. signal(SIGPIPE, SIG_IGN);
  125. }
  126. return style;
  127. }
  128. static int read_addr2line_record(struct io *io,
  129. enum cmd_a2l_style style,
  130. const char *dso_name,
  131. u64 addr,
  132. bool first,
  133. char **function,
  134. char **filename,
  135. unsigned int *line_nr)
  136. {
  137. /*
  138. * Returns:
  139. * -1 ==> error
  140. * 0 ==> sentinel (or other ill-formed) record read
  141. * 1 ==> a genuine record read
  142. */
  143. char *line = NULL;
  144. size_t line_len = 0;
  145. unsigned int dummy_line_nr = 0;
  146. int ret = -1;
  147. if (function != NULL)
  148. zfree(function);
  149. if (filename != NULL)
  150. zfree(filename);
  151. if (line_nr != NULL)
  152. *line_nr = 0;
  153. /*
  154. * Read the first line. Without an error this will be:
  155. * - for the first line an address like 0x1234,
  156. * - the binutils sentinel 0x0000000000000000,
  157. * - the llvm-addr2line the sentinel ',' character,
  158. * - the function name line for an inlined function.
  159. */
  160. if (io__getline(io, &line, &line_len) < 0 || !line_len)
  161. goto error;
  162. pr_debug3("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line);
  163. if (style == LLVM && line_len == 2 && line[0] == ',') {
  164. /* Found the llvm-addr2line sentinel character. */
  165. zfree(&line);
  166. return 0;
  167. } else if (style == GNU_BINUTILS && (!first || addr != 0)) {
  168. int zero_count = 0, non_zero_count = 0;
  169. /*
  170. * Check for binutils sentinel ignoring it for the case the
  171. * requested address is 0.
  172. */
  173. /* A given address should always start 0x. */
  174. if (line_len >= 2 || line[0] != '0' || line[1] != 'x') {
  175. for (size_t i = 2; i < line_len; i++) {
  176. if (line[i] == '0')
  177. zero_count++;
  178. else if (line[i] != '\n')
  179. non_zero_count++;
  180. }
  181. if (!non_zero_count) {
  182. int ch;
  183. if (first && !zero_count) {
  184. /* Line was erroneous just '0x'. */
  185. goto error;
  186. }
  187. /*
  188. * Line was 0x0..0, the sentinel for binutils. Remove
  189. * the function and filename lines.
  190. */
  191. zfree(&line);
  192. do {
  193. ch = io__get_char(io);
  194. } while (ch > 0 && ch != '\n');
  195. do {
  196. ch = io__get_char(io);
  197. } while (ch > 0 && ch != '\n');
  198. return 0;
  199. }
  200. }
  201. }
  202. /* Read the second function name line (if inline data then this is the first line). */
  203. if (first && (io__getline(io, &line, &line_len) < 0 || !line_len))
  204. goto error;
  205. pr_debug3("%s %s: addr2line read line: %s", __func__, dso_name, line);
  206. if (function != NULL)
  207. *function = strdup(strim(line));
  208. zfree(&line);
  209. line_len = 0;
  210. /* Read the third filename and line number line. */
  211. if (io__getline(io, &line, &line_len) < 0 || !line_len)
  212. goto error;
  213. pr_debug3("%s %s: addr2line filename:number : %s", __func__, dso_name, line);
  214. if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 &&
  215. style == GNU_BINUTILS) {
  216. ret = 0;
  217. goto error;
  218. }
  219. if (filename != NULL)
  220. *filename = strdup(line);
  221. zfree(&line);
  222. line_len = 0;
  223. return 1;
  224. error:
  225. free(line);
  226. if (function != NULL)
  227. zfree(function);
  228. if (filename != NULL)
  229. zfree(filename);
  230. return ret;
  231. }
  232. static int inline_list__append_record(struct dso *dso,
  233. struct inline_node *node,
  234. struct symbol *sym,
  235. const char *function,
  236. const char *filename,
  237. unsigned int line_nr)
  238. {
  239. struct symbol *inline_sym = new_inline_sym(dso, sym, function);
  240. return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node);
  241. }
  242. int cmd__addr2line(const char *dso_name, u64 addr,
  243. char **file, unsigned int *line_nr,
  244. struct dso *dso,
  245. bool unwind_inlines,
  246. struct inline_node *node,
  247. struct symbol *sym __maybe_unused)
  248. {
  249. struct child_process *a2l = dso__a2l(dso);
  250. char *record_function = NULL;
  251. char *record_filename = NULL;
  252. unsigned int record_line_nr = 0;
  253. int record_status = -1;
  254. int ret = 0;
  255. size_t inline_count = 0;
  256. int len;
  257. char buf[128];
  258. ssize_t written;
  259. struct io io = { .eof = false };
  260. enum cmd_a2l_style cmd_a2l_style;
  261. if (!a2l) {
  262. if (!filename__has_section(dso_name, ".debug_line"))
  263. goto out;
  264. dso__set_a2l(dso,
  265. addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name));
  266. a2l = dso__a2l(dso);
  267. }
  268. if (a2l == NULL) {
  269. if (!symbol_conf.disable_add2line_warn)
  270. pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name);
  271. goto out;
  272. }
  273. cmd_a2l_style = cmd_addr2line_configure(a2l, dso_name);
  274. if (cmd_a2l_style == BROKEN)
  275. goto out;
  276. /*
  277. * Send our request and then *deliberately* send something that can't be
  278. * interpreted as a valid address to ask addr2line about (namely,
  279. * ","). This causes addr2line to first write out the answer to our
  280. * request, in an unbounded/unknown number of records, and then to write
  281. * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or ","
  282. * for llvm-addr2line, so that we can detect when it has finished giving
  283. * us anything useful.
  284. */
  285. len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr);
  286. written = len > 0 ? write(a2l->in, buf, len) : -1;
  287. if (written != len) {
  288. if (!symbol_conf.disable_add2line_warn)
  289. pr_warning("%s %s: could not send request\n", __func__, dso_name);
  290. goto out;
  291. }
  292. io__init(&io, a2l->out, buf, sizeof(buf));
  293. io.timeout_ms = addr2line_timeout_ms;
  294. switch (read_addr2line_record(&io, cmd_a2l_style, dso_name, addr, /*first=*/true,
  295. &record_function, &record_filename, &record_line_nr)) {
  296. case -1:
  297. if (!symbol_conf.disable_add2line_warn)
  298. pr_warning("%s %s: could not read first record\n", __func__, dso_name);
  299. goto out;
  300. case 0:
  301. /*
  302. * The first record was invalid, so return failure, but first
  303. * read another record, since we sent a sentinel ',' for the
  304. * sake of detected the last inlined function. Treat this as the
  305. * first of a record as the ',' generates a new start with GNU
  306. * binutils, also force a non-zero address as we're no longer
  307. * reading that record.
  308. */
  309. switch (read_addr2line_record(&io, cmd_a2l_style, dso_name,
  310. /*addr=*/1, /*first=*/true,
  311. NULL, NULL, NULL)) {
  312. case -1:
  313. if (!symbol_conf.disable_add2line_warn)
  314. pr_warning("%s %s: could not read sentinel record\n",
  315. __func__, dso_name);
  316. break;
  317. case 0:
  318. /* The sentinel as expected. */
  319. break;
  320. default:
  321. if (!symbol_conf.disable_add2line_warn)
  322. pr_warning("%s %s: unexpected record instead of sentinel",
  323. __func__, dso_name);
  324. break;
  325. }
  326. goto out;
  327. default:
  328. /* First record as expected. */
  329. break;
  330. }
  331. if (file) {
  332. *file = strdup(record_filename);
  333. ret = 1;
  334. }
  335. if (line_nr)
  336. *line_nr = record_line_nr;
  337. if (unwind_inlines) {
  338. if (node && inline_list__append_record(dso, node, sym,
  339. record_function,
  340. record_filename,
  341. record_line_nr)) {
  342. ret = 0;
  343. goto out;
  344. }
  345. }
  346. /*
  347. * We have to read the records even if we don't care about the inline
  348. * info. This isn't the first record and force the address to non-zero
  349. * as we're reading records beyond the first.
  350. */
  351. while ((record_status = read_addr2line_record(&io,
  352. cmd_a2l_style,
  353. dso_name,
  354. /*addr=*/1,
  355. /*first=*/false,
  356. &record_function,
  357. &record_filename,
  358. &record_line_nr)) == 1) {
  359. if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) {
  360. if (inline_list__append_record(dso, node, sym,
  361. record_function,
  362. record_filename,
  363. record_line_nr)) {
  364. ret = 0;
  365. goto out;
  366. }
  367. ret = 1; /* found at least one inline frame */
  368. }
  369. }
  370. out:
  371. free(record_function);
  372. free(record_filename);
  373. if (io.eof) {
  374. dso__set_a2l(dso, NULL);
  375. addr2line_subprocess_cleanup(a2l);
  376. }
  377. return ret;
  378. }
  379. void dso__free_a2l(struct dso *dso)
  380. {
  381. struct child_process *a2l = dso__a2l(dso);
  382. if (!a2l)
  383. return;
  384. addr2line_subprocess_cleanup(a2l);
  385. dso__set_a2l(dso, NULL);
  386. }