sanitizer_symbolizer_posix_libcdep.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. //===-- sanitizer_symbolizer_posix_libcdep.cpp ----------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is shared between AddressSanitizer and ThreadSanitizer
  10. // run-time libraries.
  11. // POSIX-specific implementation of symbolizer parts.
  12. //===----------------------------------------------------------------------===//
  13. #include "sanitizer_platform.h"
  14. #if SANITIZER_POSIX
  15. #include "sanitizer_allocator_internal.h"
  16. #include "sanitizer_common.h"
  17. #include "sanitizer_file.h"
  18. #include "sanitizer_flags.h"
  19. #include "sanitizer_internal_defs.h"
  20. #include "sanitizer_linux.h"
  21. #include "sanitizer_placement_new.h"
  22. #include "sanitizer_posix.h"
  23. #include "sanitizer_procmaps.h"
  24. #include "sanitizer_symbolizer_internal.h"
  25. #include "sanitizer_symbolizer_libbacktrace.h"
  26. #include "sanitizer_symbolizer_mac.h"
  27. #include <dlfcn.h> // for dlsym()
  28. #include <errno.h>
  29. #include <stdint.h>
  30. #include <stdlib.h>
  31. #include <sys/wait.h>
  32. #include <unistd.h>
  33. // C++ demangling function, as required by Itanium C++ ABI. This is weak,
  34. // because we do not require a C++ ABI library to be linked to a program
  35. // using sanitizers; if it's not present, we'll just use the mangled name.
  36. namespace __cxxabiv1 {
  37. extern "C" SANITIZER_WEAK_ATTRIBUTE
  38. char *__cxa_demangle(const char *mangled, char *buffer,
  39. size_t *length, int *status);
  40. }
  41. namespace __sanitizer {
  42. // Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
  43. const char *DemangleCXXABI(const char *name) {
  44. // FIXME: __cxa_demangle aggressively insists on allocating memory.
  45. // There's not much we can do about that, short of providing our
  46. // own demangler (libc++abi's implementation could be adapted so that
  47. // it does not allocate). For now, we just call it anyway, and we leak
  48. // the returned value.
  49. if (&__cxxabiv1::__cxa_demangle)
  50. if (const char *demangled_name =
  51. __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
  52. return demangled_name;
  53. return name;
  54. }
  55. // As of now, there are no headers for the Swift runtime. Once they are
  56. // present, we will weakly link since we do not require Swift runtime to be
  57. // linked.
  58. typedef char *(*swift_demangle_ft)(const char *mangledName,
  59. size_t mangledNameLength, char *outputBuffer,
  60. size_t *outputBufferSize, uint32_t flags);
  61. static swift_demangle_ft swift_demangle_f;
  62. // This must not happen lazily at symbolication time, because dlsym uses
  63. // malloc and thread-local storage, which is not a good thing to do during
  64. // symbolication.
  65. static void InitializeSwiftDemangler() {
  66. swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle");
  67. (void)dlerror(); // Cleanup error message in case of failure
  68. }
  69. // Attempts to demangle a Swift name. The demangler will return nullptr if a
  70. // non-Swift name is passed in.
  71. const char *DemangleSwift(const char *name) {
  72. if (swift_demangle_f)
  73. return swift_demangle_f(name, internal_strlen(name), 0, 0, 0);
  74. return nullptr;
  75. }
  76. const char *DemangleSwiftAndCXX(const char *name) {
  77. if (!name) return nullptr;
  78. if (const char *swift_demangled_name = DemangleSwift(name))
  79. return swift_demangled_name;
  80. return DemangleCXXABI(name);
  81. }
  82. static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) {
  83. int *infd = NULL;
  84. int *outfd = NULL;
  85. // The client program may close its stdin and/or stdout and/or stderr
  86. // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
  87. // In this case the communication between the forked processes may be
  88. // broken if either the parent or the child tries to close or duplicate
  89. // these descriptors. The loop below produces two pairs of file
  90. // descriptors, each greater than 2 (stderr).
  91. int sock_pair[5][2];
  92. for (int i = 0; i < 5; i++) {
  93. if (pipe(sock_pair[i]) == -1) {
  94. for (int j = 0; j < i; j++) {
  95. internal_close(sock_pair[j][0]);
  96. internal_close(sock_pair[j][1]);
  97. }
  98. return false;
  99. } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
  100. if (infd == NULL) {
  101. infd = sock_pair[i];
  102. } else {
  103. outfd = sock_pair[i];
  104. for (int j = 0; j < i; j++) {
  105. if (sock_pair[j] == infd) continue;
  106. internal_close(sock_pair[j][0]);
  107. internal_close(sock_pair[j][1]);
  108. }
  109. break;
  110. }
  111. }
  112. }
  113. CHECK(infd);
  114. CHECK(outfd);
  115. infd_[0] = infd[0];
  116. infd_[1] = infd[1];
  117. outfd_[0] = outfd[0];
  118. outfd_[1] = outfd[1];
  119. return true;
  120. }
  121. bool SymbolizerProcess::StartSymbolizerSubprocess() {
  122. if (!FileExists(path_)) {
  123. if (!reported_invalid_path_) {
  124. Report("WARNING: invalid path to external symbolizer!\n");
  125. reported_invalid_path_ = true;
  126. }
  127. return false;
  128. }
  129. const char *argv[kArgVMax];
  130. GetArgV(path_, argv);
  131. pid_t pid;
  132. // Report how symbolizer is being launched for debugging purposes.
  133. if (Verbosity() >= 3) {
  134. // Only use `Report` for first line so subsequent prints don't get prefixed
  135. // with current PID.
  136. Report("Launching Symbolizer process: ");
  137. for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
  138. Printf("%s ", argv[index]);
  139. Printf("\n");
  140. }
  141. if (use_posix_spawn_) {
  142. #if SANITIZER_MAC
  143. fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
  144. if (fd == kInvalidFd) {
  145. Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
  146. errno);
  147. return false;
  148. }
  149. input_fd_ = fd;
  150. output_fd_ = fd;
  151. #else // SANITIZER_MAC
  152. UNIMPLEMENTED();
  153. #endif // SANITIZER_MAC
  154. } else {
  155. fd_t infd[2] = {}, outfd[2] = {};
  156. if (!CreateTwoHighNumberedPipes(infd, outfd)) {
  157. Report("WARNING: Can't create a socket pair to start "
  158. "external symbolizer (errno: %d)\n", errno);
  159. return false;
  160. }
  161. pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
  162. /* stdout */ infd[1]);
  163. if (pid < 0) {
  164. internal_close(infd[0]);
  165. internal_close(outfd[1]);
  166. return false;
  167. }
  168. input_fd_ = infd[0];
  169. output_fd_ = outfd[1];
  170. }
  171. CHECK_GT(pid, 0);
  172. // Check that symbolizer subprocess started successfully.
  173. SleepForMillis(kSymbolizerStartupTimeMillis);
  174. if (!IsProcessRunning(pid)) {
  175. // Either waitpid failed, or child has already exited.
  176. Report("WARNING: external symbolizer didn't start up correctly!\n");
  177. return false;
  178. }
  179. return true;
  180. }
  181. class Addr2LineProcess final : public SymbolizerProcess {
  182. public:
  183. Addr2LineProcess(const char *path, const char *module_name)
  184. : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
  185. const char *module_name() const { return module_name_; }
  186. private:
  187. void GetArgV(const char *path_to_binary,
  188. const char *(&argv)[kArgVMax]) const override {
  189. int i = 0;
  190. argv[i++] = path_to_binary;
  191. if (common_flags()->demangle)
  192. argv[i++] = "-C";
  193. if (common_flags()->symbolize_inline_frames)
  194. argv[i++] = "-i";
  195. argv[i++] = "-fe";
  196. argv[i++] = module_name_;
  197. argv[i++] = nullptr;
  198. CHECK_LE(i, kArgVMax);
  199. }
  200. bool ReachedEndOfOutput(const char *buffer, uptr length) const override;
  201. bool ReadFromSymbolizer(char *buffer, uptr max_length) override {
  202. if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length))
  203. return false;
  204. // The returned buffer is empty when output is valid, but exceeds
  205. // max_length.
  206. if (*buffer == '\0')
  207. return true;
  208. // We should cut out output_terminator_ at the end of given buffer,
  209. // appended by addr2line to mark the end of its meaningful output.
  210. // We cannot scan buffer from it's beginning, because it is legal for it
  211. // to start with output_terminator_ in case given offset is invalid. So,
  212. // scanning from second character.
  213. char *garbage = internal_strstr(buffer + 1, output_terminator_);
  214. // This should never be NULL since buffer must end up with
  215. // output_terminator_.
  216. CHECK(garbage);
  217. // Trim the buffer.
  218. garbage[0] = '\0';
  219. return true;
  220. }
  221. const char *module_name_; // Owned, leaked.
  222. static const char output_terminator_[];
  223. };
  224. const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n";
  225. bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
  226. uptr length) const {
  227. const size_t kTerminatorLen = sizeof(output_terminator_) - 1;
  228. // Skip, if we read just kTerminatorLen bytes, because Addr2Line output
  229. // should consist at least of two pairs of lines:
  230. // 1. First one, corresponding to given offset to be symbolized
  231. // (may be equal to output_terminator_, if offset is not valid).
  232. // 2. Second one for output_terminator_, itself to mark the end of output.
  233. if (length <= kTerminatorLen) return false;
  234. // Addr2Line output should end up with output_terminator_.
  235. return !internal_memcmp(buffer + length - kTerminatorLen,
  236. output_terminator_, kTerminatorLen);
  237. }
  238. class Addr2LinePool final : public SymbolizerTool {
  239. public:
  240. explicit Addr2LinePool(const char *addr2line_path,
  241. LowLevelAllocator *allocator)
  242. : addr2line_path_(addr2line_path), allocator_(allocator) {
  243. addr2line_pool_.reserve(16);
  244. }
  245. bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
  246. if (const char *buf =
  247. SendCommand(stack->info.module, stack->info.module_offset)) {
  248. ParseSymbolizePCOutput(buf, stack);
  249. return true;
  250. }
  251. return false;
  252. }
  253. bool SymbolizeData(uptr addr, DataInfo *info) override {
  254. return false;
  255. }
  256. private:
  257. const char *SendCommand(const char *module_name, uptr module_offset) {
  258. Addr2LineProcess *addr2line = 0;
  259. for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
  260. if (0 ==
  261. internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
  262. addr2line = addr2line_pool_[i];
  263. break;
  264. }
  265. }
  266. if (!addr2line) {
  267. addr2line =
  268. new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
  269. addr2line_pool_.push_back(addr2line);
  270. }
  271. CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
  272. char buffer[kBufferSize];
  273. internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
  274. module_offset, dummy_address_);
  275. return addr2line->SendCommand(buffer);
  276. }
  277. static const uptr kBufferSize = 64;
  278. const char *addr2line_path_;
  279. LowLevelAllocator *allocator_;
  280. InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
  281. static const uptr dummy_address_ =
  282. FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
  283. };
  284. # if SANITIZER_SUPPORTS_WEAK_HOOKS
  285. extern "C" {
  286. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
  287. __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
  288. char *Buffer, int MaxLength);
  289. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
  290. __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
  291. char *Buffer, int MaxLength);
  292. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
  293. __sanitizer_symbolize_flush();
  294. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int
  295. __sanitizer_symbolize_demangle(const char *Name, char *Buffer, int MaxLength);
  296. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
  297. __sanitizer_symbolize_set_demangle(bool Demangle);
  298. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
  299. __sanitizer_symbolize_set_inline_frames(bool InlineFrames);
  300. } // extern "C"
  301. class InternalSymbolizer final : public SymbolizerTool {
  302. public:
  303. static InternalSymbolizer *get(LowLevelAllocator *alloc) {
  304. if (__sanitizer_symbolize_set_demangle)
  305. CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
  306. if (__sanitizer_symbolize_set_inline_frames)
  307. CHECK(__sanitizer_symbolize_set_inline_frames(
  308. common_flags()->symbolize_inline_frames));
  309. if (__sanitizer_symbolize_code && __sanitizer_symbolize_data)
  310. return new (*alloc) InternalSymbolizer();
  311. return 0;
  312. }
  313. bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
  314. bool result = __sanitizer_symbolize_code(
  315. stack->info.module, stack->info.module_offset, buffer_, kBufferSize);
  316. if (result)
  317. ParseSymbolizePCOutput(buffer_, stack);
  318. return result;
  319. }
  320. bool SymbolizeData(uptr addr, DataInfo *info) override {
  321. bool result = __sanitizer_symbolize_data(info->module, info->module_offset,
  322. buffer_, kBufferSize);
  323. if (result) {
  324. ParseSymbolizeDataOutput(buffer_, info);
  325. info->start += (addr - info->module_offset); // Add the base address.
  326. }
  327. return result;
  328. }
  329. void Flush() override {
  330. if (__sanitizer_symbolize_flush)
  331. __sanitizer_symbolize_flush();
  332. }
  333. const char *Demangle(const char *name) override {
  334. if (__sanitizer_symbolize_demangle) {
  335. for (uptr res_length = 1024;
  336. res_length <= InternalSizeClassMap::kMaxSize;) {
  337. char *res_buff = static_cast<char *>(InternalAlloc(res_length));
  338. uptr req_length =
  339. __sanitizer_symbolize_demangle(name, res_buff, res_length);
  340. if (req_length > res_length) {
  341. res_length = req_length + 1;
  342. InternalFree(res_buff);
  343. continue;
  344. }
  345. return res_buff;
  346. }
  347. }
  348. return name;
  349. }
  350. private:
  351. InternalSymbolizer() {}
  352. static const int kBufferSize = 16 * 1024;
  353. char buffer_[kBufferSize];
  354. };
  355. # else // SANITIZER_SUPPORTS_WEAK_HOOKS
  356. class InternalSymbolizer final : public SymbolizerTool {
  357. public:
  358. static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
  359. };
  360. # endif // SANITIZER_SUPPORTS_WEAK_HOOKS
  361. const char *Symbolizer::PlatformDemangle(const char *name) {
  362. return DemangleSwiftAndCXX(name);
  363. }
  364. static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
  365. const char *path = common_flags()->external_symbolizer_path;
  366. if (path && internal_strchr(path, '%')) {
  367. char *new_path = (char *)InternalAlloc(kMaxPathLength);
  368. SubstituteForFlagValue(path, new_path, kMaxPathLength);
  369. path = new_path;
  370. }
  371. const char *binary_name = path ? StripModuleName(path) : "";
  372. static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
  373. if (path && path[0] == '\0') {
  374. VReport(2, "External symbolizer is explicitly disabled.\n");
  375. return nullptr;
  376. } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
  377. internal_strlen(kLLVMSymbolizerPrefix))) {
  378. VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
  379. return new(*allocator) LLVMSymbolizer(path, allocator);
  380. } else if (!internal_strcmp(binary_name, "atos")) {
  381. #if SANITIZER_MAC
  382. VReport(2, "Using atos at user-specified path: %s\n", path);
  383. return new(*allocator) AtosSymbolizer(path, allocator);
  384. #else // SANITIZER_MAC
  385. Report("ERROR: Using `atos` is only supported on Darwin.\n");
  386. Die();
  387. #endif // SANITIZER_MAC
  388. } else if (!internal_strcmp(binary_name, "addr2line")) {
  389. VReport(2, "Using addr2line at user-specified path: %s\n", path);
  390. return new(*allocator) Addr2LinePool(path, allocator);
  391. } else if (path) {
  392. Report("ERROR: External symbolizer path is set to '%s' which isn't "
  393. "a known symbolizer. Please set the path to the llvm-symbolizer "
  394. "binary or other known tool.\n", path);
  395. Die();
  396. }
  397. // Otherwise symbolizer program is unknown, let's search $PATH
  398. CHECK(path == nullptr);
  399. #if SANITIZER_MAC
  400. if (const char *found_path = FindPathToBinary("atos")) {
  401. VReport(2, "Using atos found at: %s\n", found_path);
  402. return new(*allocator) AtosSymbolizer(found_path, allocator);
  403. }
  404. #endif // SANITIZER_MAC
  405. if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
  406. VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
  407. return new(*allocator) LLVMSymbolizer(found_path, allocator);
  408. }
  409. if (common_flags()->allow_addr2line) {
  410. if (const char *found_path = FindPathToBinary("addr2line")) {
  411. VReport(2, "Using addr2line found at: %s\n", found_path);
  412. return new(*allocator) Addr2LinePool(found_path, allocator);
  413. }
  414. }
  415. return nullptr;
  416. }
  417. static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
  418. LowLevelAllocator *allocator) {
  419. if (!common_flags()->symbolize) {
  420. VReport(2, "Symbolizer is disabled.\n");
  421. return;
  422. }
  423. if (IsAllocatorOutOfMemory()) {
  424. VReport(2, "Cannot use internal symbolizer: out of memory\n");
  425. } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
  426. VReport(2, "Using internal symbolizer.\n");
  427. list->push_back(tool);
  428. return;
  429. }
  430. if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
  431. VReport(2, "Using libbacktrace symbolizer.\n");
  432. list->push_back(tool);
  433. return;
  434. }
  435. if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
  436. list->push_back(tool);
  437. }
  438. #if SANITIZER_MAC
  439. VReport(2, "Using dladdr symbolizer.\n");
  440. list->push_back(new(*allocator) DlAddrSymbolizer());
  441. #endif // SANITIZER_MAC
  442. }
  443. Symbolizer *Symbolizer::PlatformInit() {
  444. IntrusiveList<SymbolizerTool> list;
  445. list.clear();
  446. ChooseSymbolizerTools(&list, &symbolizer_allocator_);
  447. return new(symbolizer_allocator_) Symbolizer(list);
  448. }
  449. void Symbolizer::LateInitialize() {
  450. Symbolizer::GetOrInit();
  451. InitializeSwiftDemangler();
  452. }
  453. } // namespace __sanitizer
  454. #endif // SANITIZER_POSIX