sanitizer_stacktrace_printer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //===-- sanitizer_common.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 sanitizers' run-time libraries.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "sanitizer_stacktrace_printer.h"
  13. #include "sanitizer_file.h"
  14. #include "sanitizer_fuchsia.h"
  15. namespace __sanitizer {
  16. // sanitizer_symbolizer_markup.cpp implements these differently.
  17. #if !SANITIZER_SYMBOLIZER_MARKUP
  18. static const char *StripFunctionName(const char *function, const char *prefix) {
  19. if (!function) return nullptr;
  20. if (!prefix) return function;
  21. uptr prefix_len = internal_strlen(prefix);
  22. if (0 == internal_strncmp(function, prefix, prefix_len))
  23. return function + prefix_len;
  24. return function;
  25. }
  26. static const char *DemangleFunctionName(const char *function) {
  27. if (!function) return nullptr;
  28. // NetBSD uses indirection for old threading functions for historical reasons
  29. // The mangled names are internal implementation detail and should not be
  30. // exposed even in backtraces.
  31. #if SANITIZER_NETBSD
  32. if (!internal_strcmp(function, "__libc_mutex_init"))
  33. return "pthread_mutex_init";
  34. if (!internal_strcmp(function, "__libc_mutex_lock"))
  35. return "pthread_mutex_lock";
  36. if (!internal_strcmp(function, "__libc_mutex_trylock"))
  37. return "pthread_mutex_trylock";
  38. if (!internal_strcmp(function, "__libc_mutex_unlock"))
  39. return "pthread_mutex_unlock";
  40. if (!internal_strcmp(function, "__libc_mutex_destroy"))
  41. return "pthread_mutex_destroy";
  42. if (!internal_strcmp(function, "__libc_mutexattr_init"))
  43. return "pthread_mutexattr_init";
  44. if (!internal_strcmp(function, "__libc_mutexattr_settype"))
  45. return "pthread_mutexattr_settype";
  46. if (!internal_strcmp(function, "__libc_mutexattr_destroy"))
  47. return "pthread_mutexattr_destroy";
  48. if (!internal_strcmp(function, "__libc_cond_init"))
  49. return "pthread_cond_init";
  50. if (!internal_strcmp(function, "__libc_cond_signal"))
  51. return "pthread_cond_signal";
  52. if (!internal_strcmp(function, "__libc_cond_broadcast"))
  53. return "pthread_cond_broadcast";
  54. if (!internal_strcmp(function, "__libc_cond_wait"))
  55. return "pthread_cond_wait";
  56. if (!internal_strcmp(function, "__libc_cond_timedwait"))
  57. return "pthread_cond_timedwait";
  58. if (!internal_strcmp(function, "__libc_cond_destroy"))
  59. return "pthread_cond_destroy";
  60. if (!internal_strcmp(function, "__libc_rwlock_init"))
  61. return "pthread_rwlock_init";
  62. if (!internal_strcmp(function, "__libc_rwlock_rdlock"))
  63. return "pthread_rwlock_rdlock";
  64. if (!internal_strcmp(function, "__libc_rwlock_wrlock"))
  65. return "pthread_rwlock_wrlock";
  66. if (!internal_strcmp(function, "__libc_rwlock_tryrdlock"))
  67. return "pthread_rwlock_tryrdlock";
  68. if (!internal_strcmp(function, "__libc_rwlock_trywrlock"))
  69. return "pthread_rwlock_trywrlock";
  70. if (!internal_strcmp(function, "__libc_rwlock_unlock"))
  71. return "pthread_rwlock_unlock";
  72. if (!internal_strcmp(function, "__libc_rwlock_destroy"))
  73. return "pthread_rwlock_destroy";
  74. if (!internal_strcmp(function, "__libc_thr_keycreate"))
  75. return "pthread_key_create";
  76. if (!internal_strcmp(function, "__libc_thr_setspecific"))
  77. return "pthread_setspecific";
  78. if (!internal_strcmp(function, "__libc_thr_getspecific"))
  79. return "pthread_getspecific";
  80. if (!internal_strcmp(function, "__libc_thr_keydelete"))
  81. return "pthread_key_delete";
  82. if (!internal_strcmp(function, "__libc_thr_once"))
  83. return "pthread_once";
  84. if (!internal_strcmp(function, "__libc_thr_self"))
  85. return "pthread_self";
  86. if (!internal_strcmp(function, "__libc_thr_exit"))
  87. return "pthread_exit";
  88. if (!internal_strcmp(function, "__libc_thr_setcancelstate"))
  89. return "pthread_setcancelstate";
  90. if (!internal_strcmp(function, "__libc_thr_equal"))
  91. return "pthread_equal";
  92. if (!internal_strcmp(function, "__libc_thr_curcpu"))
  93. return "pthread_curcpu_np";
  94. if (!internal_strcmp(function, "__libc_thr_sigsetmask"))
  95. return "pthread_sigmask";
  96. #endif
  97. return function;
  98. }
  99. static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,
  100. InternalScopedString *buffer) {
  101. if (info.uuid_size) {
  102. if (PrefixSpace)
  103. buffer->append(" ");
  104. buffer->append("(BuildId: ");
  105. for (uptr i = 0; i < info.uuid_size; ++i) {
  106. buffer->append("%02x", info.uuid[i]);
  107. }
  108. buffer->append(")");
  109. }
  110. }
  111. static const char kDefaultFormat[] = " #%n %p %F %L";
  112. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
  113. uptr address, const AddressInfo *info, bool vs_style,
  114. const char *strip_path_prefix, const char *strip_func_prefix) {
  115. // info will be null in the case where symbolization is not needed for the
  116. // given format. This ensures that the code below will get a hard failure
  117. // rather than print incorrect information in case RenderNeedsSymbolization
  118. // ever ends up out of sync with this function. If non-null, the addresses
  119. // should match.
  120. CHECK(!info || address == info->address);
  121. if (0 == internal_strcmp(format, "DEFAULT"))
  122. format = kDefaultFormat;
  123. for (const char *p = format; *p != '\0'; p++) {
  124. if (*p != '%') {
  125. buffer->append("%c", *p);
  126. continue;
  127. }
  128. p++;
  129. switch (*p) {
  130. case '%':
  131. buffer->append("%%");
  132. break;
  133. // Frame number and all fields of AddressInfo structure.
  134. case 'n':
  135. buffer->append("%u", frame_no);
  136. break;
  137. case 'p':
  138. buffer->append("0x%zx", address);
  139. break;
  140. case 'm':
  141. buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix));
  142. break;
  143. case 'o':
  144. buffer->append("0x%zx", info->module_offset);
  145. break;
  146. case 'b':
  147. MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer);
  148. break;
  149. case 'f':
  150. buffer->append("%s", DemangleFunctionName(StripFunctionName(
  151. info->function, strip_func_prefix)));
  152. break;
  153. case 'q':
  154. buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown
  155. ? info->function_offset
  156. : 0x0);
  157. break;
  158. case 's':
  159. buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix));
  160. break;
  161. case 'l':
  162. buffer->append("%d", info->line);
  163. break;
  164. case 'c':
  165. buffer->append("%d", info->column);
  166. break;
  167. // Smarter special cases.
  168. case 'F':
  169. // Function name and offset, if file is unknown.
  170. if (info->function) {
  171. buffer->append("in %s", DemangleFunctionName(StripFunctionName(
  172. info->function, strip_func_prefix)));
  173. if (!info->file && info->function_offset != AddressInfo::kUnknown)
  174. buffer->append("+0x%zx", info->function_offset);
  175. }
  176. break;
  177. case 'S':
  178. // File/line information.
  179. RenderSourceLocation(buffer, info->file, info->line, info->column,
  180. vs_style, strip_path_prefix);
  181. break;
  182. case 'L':
  183. // Source location, or module location.
  184. if (info->file) {
  185. RenderSourceLocation(buffer, info->file, info->line, info->column,
  186. vs_style, strip_path_prefix);
  187. } else if (info->module) {
  188. RenderModuleLocation(buffer, info->module, info->module_offset,
  189. info->module_arch, strip_path_prefix);
  190. MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
  191. } else {
  192. buffer->append("(<unknown module>)");
  193. }
  194. break;
  195. case 'M':
  196. // Module basename and offset, or PC.
  197. if (address & kExternalPCBit) {
  198. // There PCs are not meaningful.
  199. } else if (info->module) {
  200. // Always strip the module name for %M.
  201. RenderModuleLocation(buffer, StripModuleName(info->module),
  202. info->module_offset, info->module_arch, "");
  203. MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
  204. } else {
  205. buffer->append("(%p)", (void *)address);
  206. }
  207. break;
  208. default:
  209. Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
  210. (void *)p);
  211. Die();
  212. }
  213. }
  214. }
  215. bool RenderNeedsSymbolization(const char *format) {
  216. if (0 == internal_strcmp(format, "DEFAULT"))
  217. format = kDefaultFormat;
  218. for (const char *p = format; *p != '\0'; p++) {
  219. if (*p != '%')
  220. continue;
  221. p++;
  222. switch (*p) {
  223. case '%':
  224. break;
  225. case 'n':
  226. // frame_no
  227. break;
  228. case 'p':
  229. // address
  230. break;
  231. default:
  232. return true;
  233. }
  234. }
  235. return false;
  236. }
  237. void RenderData(InternalScopedString *buffer, const char *format,
  238. const DataInfo *DI, const char *strip_path_prefix) {
  239. for (const char *p = format; *p != '\0'; p++) {
  240. if (*p != '%') {
  241. buffer->append("%c", *p);
  242. continue;
  243. }
  244. p++;
  245. switch (*p) {
  246. case '%':
  247. buffer->append("%%");
  248. break;
  249. case 's':
  250. buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
  251. break;
  252. case 'l':
  253. buffer->append("%zu", DI->line);
  254. break;
  255. case 'g':
  256. buffer->append("%s", DI->name);
  257. break;
  258. default:
  259. Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
  260. (void *)p);
  261. Die();
  262. }
  263. }
  264. }
  265. #endif // !SANITIZER_SYMBOLIZER_MARKUP
  266. void RenderSourceLocation(InternalScopedString *buffer, const char *file,
  267. int line, int column, bool vs_style,
  268. const char *strip_path_prefix) {
  269. if (vs_style && line > 0) {
  270. buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
  271. if (column > 0)
  272. buffer->append(",%d", column);
  273. buffer->append(")");
  274. return;
  275. }
  276. buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
  277. if (line > 0) {
  278. buffer->append(":%d", line);
  279. if (column > 0)
  280. buffer->append(":%d", column);
  281. }
  282. }
  283. void RenderModuleLocation(InternalScopedString *buffer, const char *module,
  284. uptr offset, ModuleArch arch,
  285. const char *strip_path_prefix) {
  286. buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
  287. if (arch != kModuleArchUnknown) {
  288. buffer->append(":%s", ModuleArchToString(arch));
  289. }
  290. buffer->append("+0x%zx)", offset);
  291. }
  292. } // namespace __sanitizer