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 { 202673fd8406197c42f16cede6d287f72169298c2eKostya Serebryanyconst char *StripPathPrefix(const char *filepath, 212673fd8406197c42f16cede6d287f72169298c2eKostya Serebryany const char *strip_file_prefix) { 221d333c5a34d896f239001e3fe69a660e40d15301Kostya Serebryany if (filepath == 0) return 0; 23ae894455254b9a15b6f11df7c2362f5f45586862Sergey Matveev const char *prefix_beg = internal_strstr(filepath, strip_file_prefix); 24ae894455254b9a15b6f11df7c2362f5f45586862Sergey Matveev if (prefix_beg) 25ae894455254b9a15b6f11df7c2362f5f45586862Sergey Matveev return prefix_beg + internal_strlen(strip_file_prefix); 26c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return filepath; 27c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 28c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 29c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// ----------------------- StackTrace ----------------------------- {{{1 30d2f08ffcb97726452f4ba11c199a1e06dc2a7e54Alexey Samsonovuptr StackTrace::GetPreviousInstructionPc(uptr pc) { 31c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#ifdef __arm__ 32c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Cancel Thumb bit. 33c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = pc & (~1); 34c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif 35d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany#if defined(__powerpc__) || defined(__powerpc64__) 36d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany // PCs are always 4 byte aligned. 37d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany return pc - 4; 3868aad43bee8b49d41dec72cb4b4eb34cdcd80e9cKostya Serebryany#elif defined(__sparc__) 3968aad43bee8b49d41dec72cb4b4eb34cdcd80e9cKostya Serebryany return pc - 8; 40d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany#else 41c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return pc - 1; 42d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany#endif 43c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 44c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 451ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintStackFramePrefix(uptr frame_num, uptr pc) { 461ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" #%zu 0x%zx", frame_num, pc); 471ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 481ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 491ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintSourceLocation(const char *file, int line, int column, 501ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov const char *strip_file_prefix) { 511ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov CHECK(file); 521ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" %s", StripPathPrefix(file, strip_file_prefix)); 531ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (line > 0) { 541ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(":%d", line); 551ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (column > 0) 561ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(":%d", column); 571ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 581ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 591ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 601ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic void PrintModuleAndOffset(const char *module, uptr offset, 611ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov const char *strip_file_prefix) { 621ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset); 631ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov} 641ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 65678e5436c6c1ecbd0cf50ce80bc7a2afb904c0efEvgeniy Stepanovvoid StackTrace::PrintStack(const uptr *addr, uptr size, 66c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany bool symbolize, const char *strip_file_prefix, 67c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany SymbolizeCallback symbolize_callback ) { 689ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(/*cache_enabled*/true); 69e89f1846d58550f919a0ef9081b11d4b0405019dKostya Serebryany InternalScopedBuffer<char> buff(GetPageSizeCached() * 2); 704fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany InternalScopedBuffer<AddressInfo> addr_frames(64); 71c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr frame_num = 0; 72c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && addr[i]; i++) { 73d2f08ffcb97726452f4ba11c199a1e06dc2a7e54Alexey Samsonov // PCs in stack traces are actually the return addresses, that is, 74d2f08ffcb97726452f4ba11c199a1e06dc2a7e54Alexey Samsonov // addresses of the next instructions after the call. 75d2f08ffcb97726452f4ba11c199a1e06dc2a7e54Alexey Samsonov uptr pc = GetPreviousInstructionPc(addr[i]); 761ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov uptr addr_frames_num = 0; // The number of stack frames for current 771ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // instruction address. 78c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (symbolize_callback) { 791ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (symbolize_callback((void*)pc, buff.data(), buff.size())) { 801ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov addr_frames_num = 1; 811ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 821ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // We can't know anything about the string returned by external 831ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // symbolizer, but if it starts with filename, try to strip path prefix 841ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // from it. 851ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix)); 861ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov frame_num++; 871ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 88d5951e6b869dc973dd442bf3c79dc9d852d404f7Alexey Samsonov } 8943e99ae95299017fb3cbb7d1c8677c6006d3537fPeter Collingbourne if (symbolize && addr_frames_num == 0 && &SymbolizeCode) { 901ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // Use our own (online) symbolizer, if necessary. 9173ed35f0b6cdc8ce8c23e839a3973212f448ef8dAlexey Samsonov addr_frames_num = SymbolizeCode(pc, addr_frames.data(), 9273ed35f0b6cdc8ce8c23e839a3973212f448ef8dAlexey Samsonov addr_frames.size()); 93c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr j = 0; j < addr_frames_num; j++) { 94c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany AddressInfo &info = addr_frames[j]; 951ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 96c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (info.function) { 97c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf(" in %s", info.function); 98c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 99c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (info.file) { 1001ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintSourceLocation(info.file, info.line, info.column, 1011ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov strip_file_prefix); 102c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else if (info.module) { 1031ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintModuleAndOffset(info.module, info.module_offset, 1041ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov strip_file_prefix); 105c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 106c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf("\n"); 107c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany info.Clear(); 108c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame_num++; 109c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 1101ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 1111ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (addr_frames_num == 0) { 1121ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // If online symbolization failed, try to output at least module and 1131ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov // offset for instruction. 1141ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintStackFramePrefix(frame_num, pc); 115c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr offset; 116c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (proc_maps.GetObjectNameAndOffset(pc, &offset, 11745717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov buff.data(), buff.size(), 11845717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov /* protection */0)) { 1191ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov PrintModuleAndOffset(buff.data(), offset, strip_file_prefix); 120c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 1211ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov Printf("\n"); 122c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany frame_num++; 123c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 124c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 125c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 126c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 127c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyuptr StackTrace::GetCurrentPc() { 128c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return GET_CALLER_PC(); 129c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 130c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 131c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyvoid StackTrace::FastUnwindStack(uptr pc, uptr bp, 132c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr stack_top, uptr stack_bottom) { 133c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(size == 0 && trace[0] == pc); 134c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany size = 1; 135574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany uhwptr *frame = (uhwptr *)bp; 13620aed578bf010a91222aed0096d87e0d887a28e9Reid Kleckner uhwptr *prev_frame = frame - 1; 1378301c7355309518084903611ba96665bd31c15f8Kostya Serebryany if (stack_top < 4096) return; // Sanity check for stack top. 13820aed578bf010a91222aed0096d87e0d887a28e9Reid Kleckner // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. 13920aed578bf010a91222aed0096d87e0d887a28e9Reid Kleckner while (frame > prev_frame && 140574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany frame < (uhwptr *)stack_top - 2 && 141574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany frame > (uhwptr *)stack_bottom && 142583025ddc52988cdcedb5dee57e0d66a0c586340Kostya Serebryany IsAligned((uptr)frame, sizeof(*frame)) && 143c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany size < max_size) { 144574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany uhwptr pc1 = frame[1]; 145c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (pc1 != pc) { 146574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany trace[size++] = (uptr) pc1; 147c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 148c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_frame = frame; 149574618acc0c6e934c25379c59d074864a1fd2186Kostya Serebryany frame = (uhwptr *)frame[0]; 150c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 151c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 152c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 153d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryanyvoid StackTrace::PopStackFrames(uptr count) { 1546523fe2ad35426bf37f10cbb6b45ef65dcdb2769Evgeniy Stepanov CHECK(size >= count); 155d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany size -= count; 156d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany for (uptr i = 0; i < size; i++) { 157d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany trace[i] = trace[i + count]; 158d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany } 159d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany} 160d7d4650dd754aafc874e3b8cd5ab5b38005c84ecKostya Serebryany 161c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// On 32-bits we don't compress stack traces. 162c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// On 64-bits we compress stack traces: if a given pc differes slightly from 163c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany// the previous one, we record a 31-bit offset instead of the full pc. 164c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya SerebryanySANITIZER_INTERFACE_ATTRIBUTE 165c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyuptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) { 1665af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany#if SANITIZER_WORDSIZE == 32 167c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Don't compress, just copy. 168c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr res = 0; 169c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < stack->size && i < size; i++) { 170c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[i] = stack->trace[i]; 171c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany res++; 172c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 173c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (stack->size < size) 174c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[stack->size] = 0; 175c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#else // 64 bits, compress. 176c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr prev_pc = 0; 177c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany const uptr kMaxOffset = (1ULL << 30) - 1; 178c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr c_index = 0; 179c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr res = 0; 180c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0, n = stack->size; i < n; i++) { 181c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc = stack->trace[i]; 182c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!pc) break; 183c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if ((s64)pc < 0) break; 184c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C pc[%zu] %zx\n", i, pc); 185c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) { 186c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr offset = (s64)(pc - prev_pc); 187c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany offset |= (1U << 31); 188c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index >= size) break; 189c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C co[%zu] offset %zx\n", i, offset); 190c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = offset; 191c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else { 192c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr hi = pc >> 32; 193c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr lo = (pc << 32) >> 32; 1949ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany CHECK_EQ((hi & (1 << 31)), 0); 195c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index + 1 >= size) break; 196c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("C co[%zu] hi/lo: %zx %zx\n", c_index, hi, lo); 197c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = hi; 198c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index++] = lo; 199c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 200c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany res++; 201c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_pc = pc; 202c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 203c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index < size) 204c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index] = 0; 205c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (c_index + 1 < size) 206c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany compressed[c_index + 1] = 0; 2075af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany#endif // SANITIZER_WORDSIZE 208c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 209c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // debug-only code 210c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#if 0 211c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany StackTrace check_stack; 212c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany UncompressStack(&check_stack, compressed, size); 213c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (res < check_stack.size) { 214c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany Printf("res %zu check_stack.size %zu; c_size %zu\n", res, 215c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany check_stack.size, size); 216c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 217c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // |res| may be greater than check_stack.size, because 218c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames. 219c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(res >= check_stack.size); 2209ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany CHECK_EQ(0, REAL(memcmp)(check_stack.trace, stack->trace, 221c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany check_stack.size * sizeof(uptr))); 222c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#endif 223c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 224c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return res; 225c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 226c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 227c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya SerebryanySANITIZER_INTERFACE_ATTRIBUTE 228c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyvoid StackTrace::UncompressStack(StackTrace *stack, 229c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany u32 *compressed, uptr size) { 2305af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany#if SANITIZER_WORDSIZE == 32 231c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Don't uncompress, just copy. 232c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size = 0; 233c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && i < kStackTraceMax; i++) { 234c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!compressed[i]) break; 235c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size++; 236c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->trace[i] = compressed[i]; 237c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 238c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#else // 64 bits, uncompress 239c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr prev_pc = 0; 240c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->size = 0; 241c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (uptr i = 0; i < size && stack->size < kStackTraceMax; i++) { 242c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany u32 x = compressed[i]; 243c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr pc = 0; 244c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (x & (1U << 31)) { 245c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U co[%zu] offset: %x\n", i, x); 246c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // this is an offset 247c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany s32 offset = x; 248c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany offset = (offset << 1) >> 1; // remove the 31-byte and sign-extend. 249c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = prev_pc + offset; 250c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany CHECK(pc); 251c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } else { 252c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // CHECK(i + 1 < size); 253c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (i + 1 >= size) break; 254c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr hi = x; 255c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany uptr lo = compressed[i+1]; 256c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U co[%zu] hi/lo: %zx %zx\n", i, hi, lo); 257c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany i++; 258c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany pc = (hi << 32) | lo; 259c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (!pc) break; 260c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 261c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany // Printf("U pc[%zu] %zx\n", stack->size, pc); 262c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany stack->trace[stack->size++] = pc; 263c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany prev_pc = pc; 264c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 2655af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany#endif // SANITIZER_WORDSIZE 266c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 267c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 268c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} // namespace __sanitizer 269