debuginfod-support.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /* debuginfod utilities for GDB.
  2. Copyright (C) 2020-2022 Free Software Foundation, Inc.
  3. This file is part of GDB.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include "defs.h"
  15. #include <errno.h>
  16. #include "gdbsupport/scoped_fd.h"
  17. #include "debuginfod-support.h"
  18. #include "gdbsupport/gdb_optional.h"
  19. #include "cli/cli-cmds.h"
  20. #include "cli/cli-style.h"
  21. #include "target.h"
  22. /* Set/show debuginfod commands. */
  23. static cmd_list_element *set_debuginfod_prefix_list;
  24. static cmd_list_element *show_debuginfod_prefix_list;
  25. static const char debuginfod_on[] = "on";
  26. static const char debuginfod_off[] = "off";
  27. static const char debuginfod_ask[] = "ask";
  28. static const char *debuginfod_enabled_enum[] =
  29. {
  30. debuginfod_on,
  31. debuginfod_off,
  32. debuginfod_ask,
  33. nullptr
  34. };
  35. static const char *debuginfod_enabled =
  36. #if defined(HAVE_LIBDEBUGINFOD)
  37. debuginfod_ask;
  38. #else
  39. debuginfod_off;
  40. #endif
  41. static unsigned int debuginfod_verbose = 1;
  42. #ifndef HAVE_LIBDEBUGINFOD
  43. scoped_fd
  44. debuginfod_source_query (const unsigned char *build_id,
  45. int build_id_len,
  46. const char *srcpath,
  47. gdb::unique_xmalloc_ptr<char> *destname)
  48. {
  49. return scoped_fd (-ENOSYS);
  50. }
  51. scoped_fd
  52. debuginfod_debuginfo_query (const unsigned char *build_id,
  53. int build_id_len,
  54. const char *filename,
  55. gdb::unique_xmalloc_ptr<char> *destname)
  56. {
  57. return scoped_fd (-ENOSYS);
  58. }
  59. scoped_fd
  60. debuginfod_exec_query (const unsigned char *build_id,
  61. int build_id_len,
  62. const char *filename,
  63. gdb::unique_xmalloc_ptr<char> *destname)
  64. {
  65. return scoped_fd (-ENOSYS);
  66. }
  67. #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
  68. #else
  69. #include <elfutils/debuginfod.h>
  70. struct user_data
  71. {
  72. user_data (const char *desc, const char *fname)
  73. : desc (desc), fname (fname), has_printed (false)
  74. { }
  75. const char * const desc;
  76. const char * const fname;
  77. bool has_printed;
  78. };
  79. /* Deleter for a debuginfod_client. */
  80. struct debuginfod_client_deleter
  81. {
  82. void operator() (debuginfod_client *c)
  83. {
  84. debuginfod_end (c);
  85. }
  86. };
  87. using debuginfod_client_up
  88. = std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
  89. static int
  90. progressfn (debuginfod_client *c, long cur, long total)
  91. {
  92. user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
  93. gdb_assert (data != nullptr);
  94. if (check_quit_flag ())
  95. {
  96. gdb_printf ("Cancelling download of %s %ps...\n",
  97. data->desc,
  98. styled_string (file_name_style.style (), data->fname));
  99. return 1;
  100. }
  101. if (!data->has_printed)
  102. {
  103. /* Include the transfer size, if available. */
  104. if (total > 0)
  105. {
  106. float size = 1.0f * total / 1024;
  107. const char *unit = "KB";
  108. /* If size is greater than 0.01 MB, set unit to MB. */
  109. if (size > 10.24)
  110. {
  111. size /= 1024;
  112. unit = "MB";
  113. }
  114. gdb_printf ("Downloading %.2f %s %s %ps...\n",
  115. size, unit, data->desc,
  116. styled_string (file_name_style.style (),
  117. data->fname));
  118. }
  119. else
  120. gdb_printf ("Downloading %s %ps...\n", data->desc,
  121. styled_string (file_name_style.style (), data->fname));
  122. data->has_printed = true;
  123. }
  124. return 0;
  125. }
  126. static debuginfod_client *
  127. get_debuginfod_client ()
  128. {
  129. static debuginfod_client_up global_client;
  130. if (global_client == nullptr)
  131. {
  132. global_client.reset (debuginfod_begin ());
  133. if (global_client != nullptr)
  134. debuginfod_set_progressfn (global_client.get (), progressfn);
  135. }
  136. return global_client.get ();
  137. }
  138. /* Check if debuginfod is enabled. If configured to do so, ask the user
  139. whether to enable debuginfod. */
  140. static bool
  141. debuginfod_is_enabled ()
  142. {
  143. const char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
  144. if (urls == nullptr || urls[0] == '\0'
  145. || debuginfod_enabled == debuginfod_off)
  146. return false;
  147. if (debuginfod_enabled == debuginfod_ask)
  148. {
  149. gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
  150. "from the following URLs:\n"));
  151. gdb::string_view url_view (urls);
  152. while (true)
  153. {
  154. url_view = url_view.substr (url_view.find_first_not_of (' '));
  155. if (url_view.empty ())
  156. break;
  157. size_t off = url_view.find_first_of (' ');
  158. gdb_printf
  159. (_(" <%ps>\n"),
  160. styled_string (file_name_style.style (),
  161. gdb::to_string (url_view.substr (0,
  162. off)).c_str ()));
  163. if (off == gdb::string_view::npos)
  164. break;
  165. url_view = url_view.substr (off);
  166. }
  167. int resp = nquery (_("Enable debuginfod for this session? "));
  168. if (!resp)
  169. {
  170. gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
  171. "setting permanent, add \'set debuginfod " \
  172. "enabled off\' to .gdbinit.\n"));
  173. debuginfod_enabled = debuginfod_off;
  174. return false;
  175. }
  176. gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
  177. "setting permanent, add \'set debuginfod enabled " \
  178. "on\' to .gdbinit.\n"));
  179. debuginfod_enabled = debuginfod_on;
  180. }
  181. return true;
  182. }
  183. /* See debuginfod-support.h */
  184. scoped_fd
  185. debuginfod_source_query (const unsigned char *build_id,
  186. int build_id_len,
  187. const char *srcpath,
  188. gdb::unique_xmalloc_ptr<char> *destname)
  189. {
  190. if (!debuginfod_is_enabled ())
  191. return scoped_fd (-ENOSYS);
  192. debuginfod_client *c = get_debuginfod_client ();
  193. if (c == nullptr)
  194. return scoped_fd (-ENOMEM);
  195. char *dname = nullptr;
  196. user_data data ("source file", srcpath);
  197. debuginfod_set_user_data (c, &data);
  198. gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
  199. if (target_supports_terminal_ours ())
  200. {
  201. term_state.emplace ();
  202. target_terminal::ours ();
  203. }
  204. scoped_fd fd (debuginfod_find_source (c,
  205. build_id,
  206. build_id_len,
  207. srcpath,
  208. &dname));
  209. debuginfod_set_user_data (c, nullptr);
  210. if (fd.get () < 0 && fd.get () != -ENOENT)
  211. gdb_printf (_("Download failed: %s. Continuing without source file %ps.\n"),
  212. safe_strerror (-fd.get ()),
  213. styled_string (file_name_style.style (), srcpath));
  214. if (fd.get () >= 0)
  215. destname->reset (dname);
  216. return fd;
  217. }
  218. /* See debuginfod-support.h */
  219. scoped_fd
  220. debuginfod_debuginfo_query (const unsigned char *build_id,
  221. int build_id_len,
  222. const char *filename,
  223. gdb::unique_xmalloc_ptr<char> *destname)
  224. {
  225. if (!debuginfod_is_enabled ())
  226. return scoped_fd (-ENOSYS);
  227. debuginfod_client *c = get_debuginfod_client ();
  228. if (c == nullptr)
  229. return scoped_fd (-ENOMEM);
  230. char *dname = nullptr;
  231. user_data data ("separate debug info for", filename);
  232. debuginfod_set_user_data (c, &data);
  233. gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
  234. if (target_supports_terminal_ours ())
  235. {
  236. term_state.emplace ();
  237. target_terminal::ours ();
  238. }
  239. scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
  240. &dname));
  241. debuginfod_set_user_data (c, nullptr);
  242. if (fd.get () < 0 && fd.get () != -ENOENT)
  243. gdb_printf (_("Download failed: %s. Continuing without debug info for %ps.\n"),
  244. safe_strerror (-fd.get ()),
  245. styled_string (file_name_style.style (), filename));
  246. if (fd.get () >= 0)
  247. destname->reset (dname);
  248. return fd;
  249. }
  250. /* See debuginfod-support.h */
  251. scoped_fd
  252. debuginfod_exec_query (const unsigned char *build_id,
  253. int build_id_len,
  254. const char *filename,
  255. gdb::unique_xmalloc_ptr<char> *destname)
  256. {
  257. if (!debuginfod_is_enabled ())
  258. return scoped_fd (-ENOSYS);
  259. debuginfod_client *c = get_debuginfod_client ();
  260. if (c == nullptr)
  261. return scoped_fd (-ENOMEM);
  262. char *dname = nullptr;
  263. user_data data ("executable for", filename);
  264. debuginfod_set_user_data (c, &data);
  265. gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
  266. if (target_supports_terminal_ours ())
  267. {
  268. term_state.emplace ();
  269. target_terminal::ours ();
  270. }
  271. scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
  272. debuginfod_set_user_data (c, nullptr);
  273. if (fd.get () < 0 && fd.get () != -ENOENT)
  274. gdb_printf (_("Download failed: %s. " \
  275. "Continuing without executable for %ps.\n"),
  276. safe_strerror (-fd.get ()),
  277. styled_string (file_name_style.style (), filename));
  278. if (fd.get () >= 0)
  279. destname->reset (dname);
  280. return fd;
  281. }
  282. #endif
  283. /* Set callback for "set debuginfod enabled". */
  284. static void
  285. set_debuginfod_enabled (const char *value)
  286. {
  287. #if defined(HAVE_LIBDEBUGINFOD)
  288. debuginfod_enabled = value;
  289. #else
  290. error (NO_IMPL);
  291. #endif
  292. }
  293. /* Get callback for "set debuginfod enabled". */
  294. static const char *
  295. get_debuginfod_enabled ()
  296. {
  297. return debuginfod_enabled;
  298. }
  299. /* Show callback for "set debuginfod enabled". */
  300. static void
  301. show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
  302. const char *value)
  303. {
  304. gdb_printf (file,
  305. _("Debuginfod functionality is currently set to "
  306. "\"%s\".\n"), debuginfod_enabled);
  307. }
  308. /* Set callback for "set debuginfod urls". */
  309. static void
  310. set_debuginfod_urls (const std::string &urls)
  311. {
  312. #if defined(HAVE_LIBDEBUGINFOD)
  313. if (setenv (DEBUGINFOD_URLS_ENV_VAR, urls.c_str (), 1) != 0)
  314. warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno));
  315. #else
  316. error (NO_IMPL);
  317. #endif
  318. }
  319. /* Get callback for "set debuginfod urls". */
  320. static const std::string&
  321. get_debuginfod_urls ()
  322. {
  323. static std::string urls;
  324. #if defined(HAVE_LIBDEBUGINFOD)
  325. const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
  326. if (envvar != nullptr)
  327. urls = envvar;
  328. else
  329. urls.clear ();
  330. #endif
  331. return urls;
  332. }
  333. /* Show callback for "set debuginfod urls". */
  334. static void
  335. show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
  336. const char *value)
  337. {
  338. if (value[0] == '\0')
  339. gdb_printf (file, _("Debuginfod URLs have not been set.\n"));
  340. else
  341. gdb_printf (file, _("Debuginfod URLs are currently set to:\n%s\n"),
  342. value);
  343. }
  344. /* Show callback for "set debuginfod verbose". */
  345. static void
  346. show_debuginfod_verbose_command (ui_file *file, int from_tty,
  347. cmd_list_element *cmd, const char *value)
  348. {
  349. gdb_printf (file, _("Debuginfod verbose output is set to %s.\n"),
  350. value);
  351. }
  352. /* Register debuginfod commands. */
  353. void _initialize_debuginfod ();
  354. void
  355. _initialize_debuginfod ()
  356. {
  357. /* set/show debuginfod */
  358. add_setshow_prefix_cmd ("debuginfod", class_run,
  359. _("Set debuginfod options."),
  360. _("Show debuginfod options."),
  361. &set_debuginfod_prefix_list,
  362. &show_debuginfod_prefix_list,
  363. &setlist, &showlist);
  364. add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
  365. _("Set whether to use debuginfod."),
  366. _("Show whether to use debuginfod."),
  367. _("\
  368. When on, enable the use of debuginfod to download missing debug info and\n\
  369. source files."),
  370. set_debuginfod_enabled,
  371. get_debuginfod_enabled,
  372. show_debuginfod_enabled,
  373. &set_debuginfod_prefix_list,
  374. &show_debuginfod_prefix_list);
  375. /* set/show debuginfod urls */
  376. add_setshow_string_noescape_cmd ("urls", class_run, _("\
  377. Set the list of debuginfod server URLs."), _("\
  378. Show the list of debuginfod server URLs."), _("\
  379. Manage the space-separated list of debuginfod server URLs that GDB will query \
  380. when missing debuginfo, executables or source files.\nThe default value is \
  381. copied from the DEBUGINFOD_URLS environment variable."),
  382. set_debuginfod_urls,
  383. get_debuginfod_urls,
  384. show_debuginfod_urls,
  385. &set_debuginfod_prefix_list,
  386. &show_debuginfod_prefix_list);
  387. /* set/show debuginfod verbose */
  388. add_setshow_zuinteger_cmd ("verbose", class_support,
  389. &debuginfod_verbose, _("\
  390. Set verbosity of debuginfod output."), _("\
  391. Show debuginfod debugging."), _("\
  392. When set to a non-zero value, display verbose output for each debuginfod \
  393. query.\nTo disable, set to zero. Verbose output is displayed by default."),
  394. nullptr,
  395. show_debuginfod_verbose_command,
  396. &set_debuginfod_prefix_list,
  397. &show_debuginfod_prefix_list);
  398. }