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