1 //===-- asan_debugging.cc -------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of AddressSanitizer, an address sanity checker.
9 //
10 // This file contains various functions that are generally useful to call when
11 // using a debugger (LLDB, GDB).
12 //===----------------------------------------------------------------------===//
13 
14 #include "asan_allocator.h"
15 #include "asan_descriptions.h"
16 #include "asan_flags.h"
17 #include "asan_internal.h"
18 #include "asan_mapping.h"
19 #include "asan_report.h"
20 #include "asan_thread.h"
21 
22 namespace {
23 using namespace __asan;
24 
FindInfoForStackVar(uptr addr,const char * frame_descr,uptr offset,char * name,uptr name_size,uptr & region_address,uptr & region_size)25 static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset,
26                                 char *name, uptr name_size,
27                                 uptr &region_address, uptr &region_size) {
28   InternalMmapVector<StackVarDescr> vars(16);
29   if (!ParseFrameDescription(frame_descr, &vars)) {
30     return;
31   }
32 
33   for (uptr i = 0; i < vars.size(); i++) {
34     if (offset <= vars[i].beg + vars[i].size) {
35       // We use name_len + 1 because strlcpy will guarantee a \0 at the end, so
36       // if we're limiting the copy due to name_len, we add 1 to ensure we copy
37       // the whole name and then terminate with '\0'.
38       internal_strlcpy(name, vars[i].name_pos,
39                        Min(name_size, vars[i].name_len + 1));
40       region_address = addr - (offset - vars[i].beg);
41       region_size = vars[i].size;
42       return;
43     }
44   }
45 }
46 
AsanGetStack(uptr addr,uptr * trace,u32 size,u32 * thread_id,bool alloc_stack)47 uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
48                          bool alloc_stack) {
49   AsanChunkView chunk = FindHeapChunkByAddress(addr);
50   if (!chunk.IsValid()) return 0;
51 
52   StackTrace stack(nullptr, 0);
53   if (alloc_stack) {
54     if (chunk.AllocTid() == kInvalidTid) return 0;
55     stack = chunk.GetAllocStack();
56     if (thread_id) *thread_id = chunk.AllocTid();
57   } else {
58     if (chunk.FreeTid() == kInvalidTid) return 0;
59     stack = chunk.GetFreeStack();
60     if (thread_id) *thread_id = chunk.FreeTid();
61   }
62 
63   if (trace && size) {
64     size = Min(size, Min(stack.size, kStackTraceMax));
65     for (uptr i = 0; i < size; i++)
66       trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
67 
68     return size;
69   }
70 
71   return 0;
72 }
73 
74 }  // namespace
75 
76 SANITIZER_INTERFACE_ATTRIBUTE
__asan_locate_address(uptr addr,char * name,uptr name_size,uptr * region_address_ptr,uptr * region_size_ptr)77 const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
78                                   uptr *region_address_ptr,
79                                   uptr *region_size_ptr) {
80   AddressDescription descr(addr);
81   uptr region_address = 0;
82   uptr region_size = 0;
83   const char *region_kind = nullptr;
84   if (name && name_size > 0) name[0] = 0;
85 
86   if (auto shadow = descr.AsShadow()) {
87     // region_{address,size} are already 0
88     switch (shadow->kind) {
89       case kShadowKindLow:
90         region_kind = "low shadow";
91         break;
92       case kShadowKindGap:
93         region_kind = "shadow gap";
94         break;
95       case kShadowKindHigh:
96         region_kind = "high shadow";
97         break;
98     }
99   } else if (auto heap = descr.AsHeap()) {
100     region_kind = "heap";
101     region_address = heap->chunk_access.chunk_begin;
102     region_size = heap->chunk_access.chunk_size;
103   } else if (auto stack = descr.AsStack()) {
104     region_kind = "stack";
105     if (!stack->frame_descr) {
106       // region_{address,size} are already 0
107     } else {
108       FindInfoForStackVar(addr, stack->frame_descr, stack->offset, name,
109                           name_size, region_address, region_size);
110     }
111   } else if (auto global = descr.AsGlobal()) {
112     region_kind = "global";
113     auto &g = global->globals[0];
114     internal_strlcpy(name, g.name, name_size);
115     region_address = g.beg;
116     region_size = g.size;
117   } else {
118     // region_{address,size} are already 0
119     region_kind = "heap-invalid";
120   }
121 
122   CHECK(region_kind);
123   if (region_address_ptr) *region_address_ptr = region_address;
124   if (region_size_ptr) *region_size_ptr = region_size;
125   return region_kind;
126 }
127 
128 SANITIZER_INTERFACE_ATTRIBUTE
__asan_get_alloc_stack(uptr addr,uptr * trace,uptr size,u32 * thread_id)129 uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
130   return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
131 }
132 
133 SANITIZER_INTERFACE_ATTRIBUTE
__asan_get_free_stack(uptr addr,uptr * trace,uptr size,u32 * thread_id)134 uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
135   return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
136 }
137 
138 SANITIZER_INTERFACE_ATTRIBUTE
__asan_get_shadow_mapping(uptr * shadow_scale,uptr * shadow_offset)139 void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
140   if (shadow_scale)
141     *shadow_scale = SHADOW_SCALE;
142   if (shadow_offset)
143     *shadow_offset = SHADOW_OFFSET;
144 }
145