sanitizer_stacktrace_printer.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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 const char kDefaultFormat[] = " #%n %p %F %L";
  100. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
  101. uptr address, const AddressInfo *info, bool vs_style,
  102. const char *strip_path_prefix, const char *strip_func_prefix) {
  103. // info will be null in the case where symbolization is not needed for the
  104. // given format. This ensures that the code below will get a hard failure
  105. // rather than print incorrect information in case RenderNeedsSymbolization
  106. // ever ends up out of sync with this function. If non-null, the addresses
  107. // should match.
  108. CHECK(!info || address == info->address);
  109. if (0 == internal_strcmp(format, "DEFAULT"))
  110. format = kDefaultFormat;
  111. for (const char *p = format; *p != '\0'; p++) {
  112. if (*p != '%') {
  113. buffer->append("%c", *p);
  114. continue;
  115. }
  116. p++;
  117. switch (*p) {
  118. case '%':
  119. buffer->append("%%");
  120. break;
  121. // Frame number and all fields of AddressInfo structure.
  122. case 'n':
  123. buffer->append("%u", frame_no);
  124. break;
  125. case 'p':
  126. buffer->append("0x%zx", address);
  127. break;
  128. case 'm':
  129. buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix));
  130. break;
  131. case 'o':
  132. buffer->append("0x%zx", info->module_offset);
  133. break;
  134. case 'f':
  135. buffer->append("%s", DemangleFunctionName(StripFunctionName(
  136. info->function, strip_func_prefix)));
  137. break;
  138. case 'q':
  139. buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown
  140. ? info->function_offset
  141. : 0x0);
  142. break;
  143. case 's':
  144. buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix));
  145. break;
  146. case 'l':
  147. buffer->append("%d", info->line);
  148. break;
  149. case 'c':
  150. buffer->append("%d", info->column);
  151. break;
  152. // Smarter special cases.
  153. case 'F':
  154. // Function name and offset, if file is unknown.
  155. if (info->function) {
  156. buffer->append("in %s", DemangleFunctionName(StripFunctionName(
  157. info->function, strip_func_prefix)));
  158. if (!info->file && info->function_offset != AddressInfo::kUnknown)
  159. buffer->append("+0x%zx", info->function_offset);
  160. }
  161. break;
  162. case 'S':
  163. // File/line information.
  164. RenderSourceLocation(buffer, info->file, info->line, info->column,
  165. vs_style, strip_path_prefix);
  166. break;
  167. case 'L':
  168. // Source location, or module location.
  169. if (info->file) {
  170. RenderSourceLocation(buffer, info->file, info->line, info->column,
  171. vs_style, strip_path_prefix);
  172. } else if (info->module) {
  173. RenderModuleLocation(buffer, info->module, info->module_offset,
  174. info->module_arch, strip_path_prefix);
  175. } else {
  176. buffer->append("(<unknown module>)");
  177. }
  178. break;
  179. case 'M':
  180. // Module basename and offset, or PC.
  181. if (address & kExternalPCBit) {
  182. // There PCs are not meaningful.
  183. } else if (info->module) {
  184. // Always strip the module name for %M.
  185. RenderModuleLocation(buffer, StripModuleName(info->module),
  186. info->module_offset, info->module_arch, "");
  187. } else {
  188. buffer->append("(%p)", (void *)address);
  189. }
  190. break;
  191. default:
  192. Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
  193. (void *)p);
  194. Die();
  195. }
  196. }
  197. }
  198. bool RenderNeedsSymbolization(const char *format) {
  199. if (0 == internal_strcmp(format, "DEFAULT"))
  200. format = kDefaultFormat;
  201. for (const char *p = format; *p != '\0'; p++) {
  202. if (*p != '%')
  203. continue;
  204. p++;
  205. switch (*p) {
  206. case '%':
  207. break;
  208. case 'n':
  209. // frame_no
  210. break;
  211. case 'p':
  212. // address
  213. break;
  214. default:
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. void RenderData(InternalScopedString *buffer, const char *format,
  221. const DataInfo *DI, const char *strip_path_prefix) {
  222. for (const char *p = format; *p != '\0'; p++) {
  223. if (*p != '%') {
  224. buffer->append("%c", *p);
  225. continue;
  226. }
  227. p++;
  228. switch (*p) {
  229. case '%':
  230. buffer->append("%%");
  231. break;
  232. case 's':
  233. buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
  234. break;
  235. case 'l':
  236. buffer->append("%zu", DI->line);
  237. break;
  238. case 'g':
  239. buffer->append("%s", DI->name);
  240. break;
  241. default:
  242. Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
  243. (void *)p);
  244. Die();
  245. }
  246. }
  247. }
  248. #endif // !SANITIZER_SYMBOLIZER_MARKUP
  249. void RenderSourceLocation(InternalScopedString *buffer, const char *file,
  250. int line, int column, bool vs_style,
  251. const char *strip_path_prefix) {
  252. if (vs_style && line > 0) {
  253. buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
  254. if (column > 0)
  255. buffer->append(",%d", column);
  256. buffer->append(")");
  257. return;
  258. }
  259. buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
  260. if (line > 0) {
  261. buffer->append(":%d", line);
  262. if (column > 0)
  263. buffer->append(":%d", column);
  264. }
  265. }
  266. void RenderModuleLocation(InternalScopedString *buffer, const char *module,
  267. uptr offset, ModuleArch arch,
  268. const char *strip_path_prefix) {
  269. buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
  270. if (arch != kModuleArchUnknown) {
  271. buffer->append(":%s", ModuleArchToString(arch));
  272. }
  273. buffer->append("+0x%zx)", offset);
  274. }
  275. } // namespace __sanitizer