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