LLDB  mainline
MemoryHistoryASan.cpp
Go to the documentation of this file.
1 //===-- MemoryHistoryASan.cpp -----------------------------------*- C++ -*-===//
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 #include "MemoryHistoryASan.h"
10 
12 
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/Module.h"
18 #include "lldb/Core/ValueObject.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Target/ThreadList.h"
24 #include "lldb/lldb-private.h"
25 
26 #include <sstream>
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 MemoryHistorySP MemoryHistoryASan::CreateInstance(const ProcessSP &process_sp) {
32  if (!process_sp.get())
33  return NULL;
34 
35  Target &target = process_sp->GetTarget();
36 
37  const ModuleList &target_modules = target.GetImages();
38  std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
39  const size_t num_modules = target_modules.GetSize();
40  for (size_t i = 0; i < num_modules; ++i) {
41  Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
42 
43  const Symbol *symbol = module_pointer->FindFirstSymbolWithNameAndType(
44  ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny);
45 
46  if (symbol != nullptr)
47  return MemoryHistorySP(new MemoryHistoryASan(process_sp));
48  }
49 
50  return MemoryHistorySP();
51 }
52 
53 void MemoryHistoryASan::Initialize() {
54  PluginManager::RegisterPlugin(
55  GetPluginNameStatic(), "ASan memory history provider.", CreateInstance);
56 }
57 
58 void MemoryHistoryASan::Terminate() {
59  PluginManager::UnregisterPlugin(CreateInstance);
60 }
61 
62 ConstString MemoryHistoryASan::GetPluginNameStatic() {
63  static ConstString g_name("asan");
64  return g_name;
65 }
66 
67 MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp) {
68  if (process_sp)
69  m_process_wp = process_sp;
70 }
71 
73  extern "C"
74  {
75  size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size, int *thread_id);
76  size_t __asan_get_free_stack(void *addr, void **trace, size_t size, int *thread_id);
77  }
78 
79  struct data {
80  void *alloc_trace[256];
81  size_t alloc_count;
82  int alloc_tid;
83 
84  void *free_trace[256];
85  size_t free_count;
86  int free_tid;
87  };
88 )";
89 
91  R"(
92  data t;
93 
94  t.alloc_count = __asan_get_alloc_stack((void *)0x%)" PRIx64
95  R"(, t.alloc_trace, 256, &t.alloc_tid);
96  t.free_count = __asan_get_free_stack((void *)0x%)" PRIx64
97  R"(, t.free_trace, 256, &t.free_tid);
98 
99  t;
100 )";
101 
102 static void CreateHistoryThreadFromValueObject(ProcessSP process_sp,
103  ValueObjectSP return_value_sp,
104  const char *type,
105  const char *thread_name,
106  HistoryThreads &result) {
107  std::string count_path = "." + std::string(type) + "_count";
108  std::string tid_path = "." + std::string(type) + "_tid";
109  std::string trace_path = "." + std::string(type) + "_trace";
110 
111  ValueObjectSP count_sp =
112  return_value_sp->GetValueForExpressionPath(count_path.c_str());
113  ValueObjectSP tid_sp =
114  return_value_sp->GetValueForExpressionPath(tid_path.c_str());
115 
116  if (!count_sp || !tid_sp)
117  return;
118 
119  int count = count_sp->GetValueAsUnsigned(0);
120  tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1;
121 
122  if (count <= 0)
123  return;
124 
125  ValueObjectSP trace_sp =
126  return_value_sp->GetValueForExpressionPath(trace_path.c_str());
127 
128  if (!trace_sp)
129  return;
130 
131  std::vector<lldb::addr_t> pcs;
132  for (int i = 0; i < count; i++) {
133  addr_t pc = trace_sp->GetChildAtIndex(i, true)->GetValueAsUnsigned(0);
134  if (pc == 0 || pc == 1 || pc == LLDB_INVALID_ADDRESS)
135  continue;
136  pcs.push_back(pc);
137  }
138 
139  HistoryThread *history_thread =
140  new HistoryThread(*process_sp, tid, pcs, 0, false);
141  ThreadSP new_thread_sp(history_thread);
142  std::ostringstream thread_name_with_number;
143  thread_name_with_number << thread_name << " Thread " << tid;
144  history_thread->SetThreadName(thread_name_with_number.str().c_str());
145  // Save this in the Process' ExtendedThreadList so a strong pointer retains
146  // the object
147  process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
148  result.push_back(new_thread_sp);
149 }
150 
151 HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
152  HistoryThreads result;
153 
154  ProcessSP process_sp = m_process_wp.lock();
155  if (!process_sp)
156  return result;
157 
158  ThreadSP thread_sp =
159  process_sp->GetThreadList().GetExpressionExecutionThread();
160  if (!thread_sp)
161  return result;
162 
163  StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
164  if (!frame_sp)
165  return result;
166 
167  ExecutionContext exe_ctx(frame_sp);
168  ValueObjectSP return_value_sp;
169  StreamString expr;
170  Status eval_error;
171  expr.Printf(memory_history_asan_command_format, address, address);
172 
174  options.SetUnwindOnError(true);
175  options.SetTryAllThreads(true);
176  options.SetStopOthers(true);
177  options.SetIgnoreBreakpoints(true);
178  options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
180  options.SetAutoApplyFixIts(false);
182 
183  ExpressionResults expr_result = UserExpression::Evaluate(
184  exe_ctx, options, expr.GetString(), "", return_value_sp, eval_error);
185  if (expr_result != eExpressionCompleted) {
186  process_sp->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf(
187  "Warning: Cannot evaluate AddressSanitizer expression:\n%s\n",
188  eval_error.AsCString());
189  return result;
190  }
191 
192  if (!return_value_sp)
193  return result;
194 
195  CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "free",
196  "Memory deallocated by", result);
197  CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "alloc",
198  "Memory allocated by", result);
199 
200  return result;
201 }
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:289
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
void SetPrefix(const char *prefix)
Definition: Target.h:274
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:285
const Symbol * FindFirstSymbolWithNameAndType(ConstString name, lldb::SymbolType symbol_type=lldb::eSymbolTypeAny)
Find a symbol in the object file&#39;s symbol table.
Definition: Module.cpp:1315
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
void SetTimeout(const Timeout< std::micro > &timeout)
Definition: Target.h:306
Module * GetModulePointerAtIndexUnlocked(size_t idx) const
Get the module pointer for the module at index idx without acquiring the ModuleList mutex...
Definition: ModuleList.cpp:320
static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, ValueObjectSP return_value_sp, const char *type, const char *thread_name, HistoryThreads &result)
A collection class for Module objects.
Definition: ModuleList.h:91
const char * memory_history_asan_command_prefix
A class that describes an executable image and its associated object and symbol files.
Definition: Module.h:109
uint64_t tid_t
Definition: lldb-types.h:86
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
void SetThreadName(const char *name)
Definition: HistoryThread.h:71
A thread object representing a backtrace from a previous point in the process execution.
Definition: HistoryThread.h:34
void SetLanguage(lldb::LanguageType language)
Definition: Target.h:266
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:899
void SetStopOthers(bool stop_others=true)
Definition: Target.h:322
uint64_t addr_t
Definition: lldb-types.h:83
size_t GetSize() const
Gets the size of the module list.
Definition: ModuleList.cpp:611
A uniqued constant string class.
Definition: ConstString.h:38
Definition: SBAddress.h:15
void SetTryAllThreads(bool try_others=true)
Definition: Target.h:318
std::vector< lldb::ThreadSP > HistoryThreads
Definition: MemoryHistory.h:21
const char * memory_history_asan_command_format
std::recursive_mutex & GetMutex() const
Definition: ModuleList.h:214
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
An error handling class.
Definition: Status.h:44