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