sanitizer_stacktrace.cc revision 1ca535700966cf5019dcc6684a62a734a7b96974
1c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany//===-- sanitizer_stacktrace.cc -------------------------------------------===// 2c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// 3c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// The LLVM Compiler Infrastructure 4c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// 5c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// This file is distributed under the University of Illinois Open Source 6c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// License. See LICENSE.TXT for details. 7c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// 8c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany//===----------------------------------------------------------------------===// 9c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// 10c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// This file is shared between AddressSanitizer and ThreadSanitizer 11c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// run-time libraries. 12c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany//===----------------------------------------------------------------------===// 13c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 149ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany#include "sanitizer_common.h" 159ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany#include "sanitizer_procmaps.h" 169ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany#include "sanitizer_stacktrace.h" 179ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany#include "sanitizer_symbolizer.h" 18c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 19c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynamespace __sanitizer { 20c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic const char *StripPathPrefix(const char *filepath, 21c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany const char *strip_file_prefix) { 22c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (filepath == internal_strstr(filepath, strip_file_prefix)) 23c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return filepath + internal_strlen(strip_file_prefix); 24c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return filepath; 25c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 26c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 27c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// ----------------------- StackTrace ----------------------------- {{{1 28c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// PCs in stack traces are actually the return addresses, that is, 29c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// addresses of the next instructions after the call. That's why we 30c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// decrement them. 31c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic uptr patch_pc(uptr pc) { 32c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#ifdef __arm__ 33c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Cancel Thumb bit. 34c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = pc & (~1); 35c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif 36c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return pc - 1; 37c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 38c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 391ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintStackFramePrefix(uptr frame_num, uptr pc) { 401ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" #%zu 0x%zx", frame_num, pc); 411ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 421ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 431ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintSourceLocation(const char *file, int line, int column, 441ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov const char *strip_file_prefix) { 451ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov CHECK(file); 461ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" %s", StripPathPrefix(file, strip_file_prefix)); 471ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (line > 0) { 481ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(":%d", line); 491ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (column > 0) 501ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(":%d", column); 511ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 521ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 531ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 541ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintModuleAndOffset(const char *module, uptr offset, 551ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov const char *strip_file_prefix) { 561ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset); 571ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 581ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 59678e5436c6c1ecbd0cf50ce80bc7a2afb904c0efEvgeniy Stepanovvoid StackTrace::PrintStack(const uptr *addr, uptr size, 60c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany bool symbolize, const char *strip_file_prefix, 61c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany SymbolizeCallback symbolize_callback ) { 62c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany MemoryMappingLayout proc_maps; 634fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany InternalScopedBuffer<char> buff(kPageSize * 2); 644fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany InternalScopedBuffer<AddressInfo> addr_frames(64); 65c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr frame_num = 0; 66c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && addr[i]; i++) { 67c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc = patch_pc(addr[i]); 681ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov uptr addr_frames_num = 0; // The number of stack frames for current 691ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // instruction address. 70c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (symbolize_callback) { 711ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (symbolize_callback((void*)pc, buff.data(), buff.size())) { 721ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov addr_frames_num = 1; 731ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 741ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // We can't know anything about the string returned by external 751ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // symbolizer, but if it starts with filename, try to strip path prefix 761ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // from it. 771ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix)); 781ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov frame_num++; 791ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 801ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } else if (symbolize) { 811ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // Use our own (online) symbolizer, if necessary. 821ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov addr_frames_num = SymbolizeCode(pc, addr_frames.data(), addr_frames.size()); 83c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr j = 0; j < addr_frames_num; j++) { 84c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany AddressInfo &info = addr_frames[j]; 851ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 86c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (info.function) { 87c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf(" in %s", info.function); 88c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 89c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (info.file) { 901ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintSourceLocation(info.file, info.line, info.column, 911ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov strip_file_prefix); 92c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else if (info.module) { 931ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintModuleAndOffset(info.module, info.module_offset, 941ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov strip_file_prefix); 95c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 96c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf("\n"); 97c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany info.Clear(); 98c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame_num++; 99c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 1001ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 1011ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (addr_frames_num == 0) { 1021ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // If online symbolization failed, try to output at least module and 1031ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // offset for instruction. 1041ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 105c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr offset; 106c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (proc_maps.GetObjectNameAndOffset(pc, &offset, 1074fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany buff.data(), buff.size())) { 1081ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintModuleAndOffset(buff.data(), offset, strip_file_prefix); 109c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 1101ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf("\n"); 111c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame_num++; 112c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 113c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 114c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 115c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 116c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyuptr StackTrace::GetCurrentPc() { 117c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return GET_CALLER_PC(); 118c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 119c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 120c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyvoid StackTrace::FastUnwindStack(uptr pc, uptr bp, 121c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr stack_top, uptr stack_bottom) { 122c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(size == 0 && trace[0] == pc); 123c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany size = 1; 124c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr *frame = (uptr*)bp; 125c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr *prev_frame = frame; 126c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany while (frame >= prev_frame && 127c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame < (uptr*)stack_top - 2 && 128c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame > (uptr*)stack_bottom && 129c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany size < max_size) { 130c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc1 = frame[1]; 131c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (pc1 != pc) { 132c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany trace[size++] = pc1; 133c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 134c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_frame = frame; 135c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame = (uptr*)frame[0]; 136c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 137c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 138c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 139c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// On 32-bits we don't compress stack traces. 140c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// On 64-bits we compress stack traces: if a given pc differes slightly from 141c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// the previous one, we record a 31-bit offset instead of the full pc. 142c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya SerebryanySANITIZER_INTERFACE_ATTRIBUTE 143c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyuptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) { 144c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#if __WORDSIZE == 32 145c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Don't compress, just copy. 146c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr res = 0; 147c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < stack->size && i < size; i++) { 148c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[i] = stack->trace[i]; 149c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany res++; 150c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 151c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (stack->size < size) 152c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[stack->size] = 0; 153c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#else // 64 bits, compress. 154c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr prev_pc = 0; 155c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany const uptr kMaxOffset = (1ULL << 30) - 1; 156c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr c_index = 0; 157c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr res = 0; 158c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0, n = stack->size; i < n; i++) { 159c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc = stack->trace[i]; 160c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!pc) break; 161c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if ((s64)pc < 0) break; 162c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C pc[%zu] %zx\n", i, pc); 163c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) { 164c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr offset = (s64)(pc - prev_pc); 165c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany offset |= (1U << 31); 166c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index >= size) break; 167c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C co[%zu] offset %zx\n", i, offset); 168c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = offset; 169c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else { 170c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr hi = pc >> 32; 171c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr lo = (pc << 32) >> 32; 1729ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany CHECK_EQ((hi & (1 << 31)), 0); 173c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index + 1 >= size) break; 174c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C co[%zu] hi/lo: %zx %zx\n", c_index, hi, lo); 175c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = hi; 176c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = lo; 177c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 178c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany res++; 179c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_pc = pc; 180c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 181c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index < size) 182c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index] = 0; 183c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index + 1 < size) 184c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index + 1] = 0; 185c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif // __WORDSIZE 186c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 187c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // debug-only code 188c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#if 0 189c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany StackTrace check_stack; 190c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany UncompressStack(&check_stack, compressed, size); 191c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (res < check_stack.size) { 192c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf("res %zu check_stack.size %zu; c_size %zu\n", res, 193c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany check_stack.size, size); 194c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 195c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // |res| may be greater than check_stack.size, because 196c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames. 197c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(res >= check_stack.size); 1989ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany CHECK_EQ(0, REAL(memcmp)(check_stack.trace, stack->trace, 199c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany check_stack.size * sizeof(uptr))); 200c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif 201c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 202c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return res; 203c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 204c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 205c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya SerebryanySANITIZER_INTERFACE_ATTRIBUTE 206c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyvoid StackTrace::UncompressStack(StackTrace *stack, 207c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany u32 *compressed, uptr size) { 208c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#if __WORDSIZE == 32 209c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Don't uncompress, just copy. 210c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size = 0; 211c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && i < kStackTraceMax; i++) { 212c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!compressed[i]) break; 213c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size++; 214c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->trace[i] = compressed[i]; 215c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 216c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#else // 64 bits, uncompress 217c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr prev_pc = 0; 218c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size = 0; 219c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && stack->size < kStackTraceMax; i++) { 220c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany u32 x = compressed[i]; 221c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc = 0; 222c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (x & (1U << 31)) { 223c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U co[%zu] offset: %x\n", i, x); 224c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // this is an offset 225c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany s32 offset = x; 226c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany offset = (offset << 1) >> 1; // remove the 31-byte and sign-extend. 227c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = prev_pc + offset; 228c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(pc); 229c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else { 230c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // CHECK(i + 1 < size); 231c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (i + 1 >= size) break; 232c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr hi = x; 233c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr lo = compressed[i+1]; 234c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U co[%zu] hi/lo: %zx %zx\n", i, hi, lo); 235c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany i++; 236c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = (hi << 32) | lo; 237c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!pc) break; 238c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 239c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U pc[%zu] %zx\n", stack->size, pc); 240c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->trace[stack->size++] = pc; 241c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_pc = pc; 242c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 243c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif // __WORDSIZE 244c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 245c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 246c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} // namespace __sanitizer 247