LLDB  mainline
InstrumentationRuntimeASan.cpp
Go to the documentation of this file.
1 //===-- InstrumentationRuntimeASan.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 
10 
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/Module.h"
16 #include "lldb/Core/StreamFile.h"
17 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Symbol/Symbol.h"
22 #include "lldb/Target/StopInfo.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
26 #include "lldb/Utility/Stream.h"
27 
28 #include "llvm/ADT/StringSwitch.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
34 
35 lldb::InstrumentationRuntimeSP
36 InstrumentationRuntimeASan::CreateInstance(const lldb::ProcessSP &process_sp) {
37  return InstrumentationRuntimeSP(new InstrumentationRuntimeASan(process_sp));
38 }
39 
40 void InstrumentationRuntimeASan::Initialize() {
41  PluginManager::RegisterPlugin(
42  GetPluginNameStatic(), "AddressSanitizer instrumentation runtime plugin.",
43  CreateInstance, GetTypeStatic);
44 }
45 
46 void InstrumentationRuntimeASan::Terminate() {
47  PluginManager::UnregisterPlugin(CreateInstance);
48 }
49 
50 lldb_private::ConstString InstrumentationRuntimeASan::GetPluginNameStatic() {
51  return ConstString("AddressSanitizer");
52 }
53 
54 lldb::InstrumentationRuntimeType InstrumentationRuntimeASan::GetTypeStatic() {
56 }
57 
58 InstrumentationRuntimeASan::~InstrumentationRuntimeASan() { Deactivate(); }
59 
60 const RegularExpression &
61 InstrumentationRuntimeASan::GetPatternForRuntimeLibrary() {
62  // FIXME: This shouldn't include the "dylib" suffix.
63  static RegularExpression regex(
64  llvm::StringRef("libclang_rt.asan_(.*)_dynamic\\.dylib"));
65  return regex;
66 }
67 
68 bool InstrumentationRuntimeASan::CheckIfRuntimeIsValid(
69  const lldb::ModuleSP module_sp) {
70  const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
71  ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny);
72 
73  return symbol != nullptr;
74 }
75 
77 extern "C"
78 {
79 int __asan_report_present();
80 void *__asan_get_report_pc();
81 void *__asan_get_report_bp();
82 void *__asan_get_report_sp();
83 void *__asan_get_report_address();
84 const char *__asan_get_report_description();
85 int __asan_get_report_access_type();
86 size_t __asan_get_report_access_size();
87 }
88 )";
89 
91 struct {
92  int present;
93  int access_type;
94  void *pc;
95  void *bp;
96  void *sp;
97  void *address;
98  size_t access_size;
99  const char *description;
100 } t;
101 
102 t.present = __asan_report_present();
103 t.access_type = __asan_get_report_access_type();
104 t.pc = __asan_get_report_pc();
105 t.bp = __asan_get_report_bp();
106 t.sp = __asan_get_report_sp();
107 t.address = __asan_get_report_address();
108 t.access_size = __asan_get_report_access_size();
109 t.description = __asan_get_report_description();
110 t
111 )";
112 
113 StructuredData::ObjectSP InstrumentationRuntimeASan::RetrieveReportData() {
114  ProcessSP process_sp = GetProcessSP();
115  if (!process_sp)
116  return StructuredData::ObjectSP();
117 
118  ThreadSP thread_sp =
119  process_sp->GetThreadList().GetExpressionExecutionThread();
120  StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
121 
122  if (!frame_sp)
123  return StructuredData::ObjectSP();
124 
126  options.SetUnwindOnError(true);
127  options.SetTryAllThreads(true);
128  options.SetStopOthers(true);
129  options.SetIgnoreBreakpoints(true);
130  options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
132  options.SetAutoApplyFixIts(false);
134 
135  ValueObjectSP return_value_sp;
136  ExecutionContext exe_ctx;
137  Status eval_error;
138  frame_sp->CalculateExecutionContext(exe_ctx);
139  ExpressionResults result = UserExpression::Evaluate(
141  return_value_sp, eval_error);
142  if (result != eExpressionCompleted) {
143  process_sp->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf(
144  "Warning: Cannot evaluate AddressSanitizer expression:\n%s\n",
145  eval_error.AsCString());
146  return StructuredData::ObjectSP();
147  }
148 
149  int present = return_value_sp->GetValueForExpressionPath(".present")
150  ->GetValueAsUnsigned(0);
151  if (present != 1)
152  return StructuredData::ObjectSP();
153 
154  addr_t pc =
155  return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
156  /* commented out because rdar://problem/18533301
157  addr_t bp =
158  return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
159  addr_t sp =
160  return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
161  */
162  addr_t address = return_value_sp->GetValueForExpressionPath(".address")
163  ->GetValueAsUnsigned(0);
164  addr_t access_type =
165  return_value_sp->GetValueForExpressionPath(".access_type")
166  ->GetValueAsUnsigned(0);
167  addr_t access_size =
168  return_value_sp->GetValueForExpressionPath(".access_size")
169  ->GetValueAsUnsigned(0);
170  addr_t description_ptr =
171  return_value_sp->GetValueForExpressionPath(".description")
172  ->GetValueAsUnsigned(0);
173  std::string description;
174  Status error;
175  process_sp->ReadCStringFromMemory(description_ptr, description, error);
176 
178  dict->AddStringItem("instrumentation_class", "AddressSanitizer");
179  dict->AddStringItem("stop_type", "fatal_error");
180  dict->AddIntegerItem("pc", pc);
181  /* commented out because rdar://problem/18533301
182  dict->AddIntegerItem("bp", bp);
183  dict->AddIntegerItem("sp", sp);
184  */
185  dict->AddIntegerItem("address", address);
186  dict->AddIntegerItem("access_type", access_type);
187  dict->AddIntegerItem("access_size", access_size);
188  dict->AddStringItem("description", description);
189 
190  return StructuredData::ObjectSP(dict);
191 }
192 
194 InstrumentationRuntimeASan::FormatDescription(StructuredData::ObjectSP report) {
195  std::string description = std::string(report->GetAsDictionary()
196  ->GetValueForKey("description")
197  ->GetAsString()
198  ->GetValue());
199  return llvm::StringSwitch<std::string>(description)
200  .Case("heap-use-after-free", "Use of deallocated memory")
201  .Case("heap-buffer-overflow", "Heap buffer overflow")
202  .Case("stack-buffer-underflow", "Stack buffer underflow")
203  .Case("initialization-order-fiasco", "Initialization order problem")
204  .Case("stack-buffer-overflow", "Stack buffer overflow")
205  .Case("stack-use-after-return", "Use of stack memory after return")
206  .Case("use-after-poison", "Use of poisoned memory")
207  .Case("container-overflow", "Container overflow")
208  .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
209  .Case("global-buffer-overflow", "Global buffer overflow")
210  .Case("unknown-crash", "Invalid memory access")
211  .Case("stack-overflow", "Stack space exhausted")
212  .Case("null-deref", "Dereference of null pointer")
213  .Case("wild-jump", "Jump to non-executable address")
214  .Case("wild-addr-write", "Write through wild pointer")
215  .Case("wild-addr-read", "Read from wild pointer")
216  .Case("wild-addr", "Access through wild pointer")
217  .Case("signal", "Deadly signal")
218  .Case("double-free", "Deallocation of freed memory")
219  .Case("new-delete-type-mismatch",
220  "Deallocation size different from allocation size")
221  .Case("bad-free", "Deallocation of non-allocated memory")
222  .Case("alloc-dealloc-mismatch",
223  "Mismatch between allocation and deallocation APIs")
224  .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
225  .Case("bad-__sanitizer_get_allocated_size",
226  "Invalid argument to __sanitizer_get_allocated_size")
227  .Case("param-overlap",
228  "Call to function disallowing overlapping memory ranges")
229  .Case("negative-size-param", "Negative size used when accessing memory")
230  .Case("bad-__sanitizer_annotate_contiguous_container",
231  "Invalid argument to __sanitizer_annotate_contiguous_container")
232  .Case("odr-violation", "Symbol defined in multiple translation units")
233  .Case(
234  "invalid-pointer-pair",
235  "Comparison or arithmetic on pointers from different memory regions")
236  // for unknown report codes just show the code
237  .Default("AddressSanitizer detected: " + description);
238 }
239 
240 bool InstrumentationRuntimeASan::NotifyBreakpointHit(
241  void *baton, StoppointCallbackContext *context, user_id_t break_id,
242  user_id_t break_loc_id) {
243  assert(baton && "null baton");
244  if (!baton)
245  return false;
246 
247  InstrumentationRuntimeASan *const instance =
248  static_cast<InstrumentationRuntimeASan *>(baton);
249 
250  ProcessSP process_sp = instance->GetProcessSP();
251 
252  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
253  return false;
254 
255  StructuredData::ObjectSP report = instance->RetrieveReportData();
256  std::string description;
257  if (report) {
258  description = instance->FormatDescription(report);
259  }
260  // Make sure this is the right process
261  if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
262  ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
263  if (thread_sp)
264  thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo::
265  CreateStopReasonWithInstrumentationData(
266  *thread_sp, description, report));
267 
268  StreamFileSP stream_sp(
269  process_sp->GetTarget().GetDebugger().GetOutputStreamSP());
270  if (stream_sp) {
271  stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
272  "info -s' to get extended information about the "
273  "report.\n");
274  }
275  return true; // Return true to stop the target
276  } else
277  return false; // Let target run
278 }
279 
280 void InstrumentationRuntimeASan::Activate() {
281  if (IsActive())
282  return;
283 
284  ProcessSP process_sp = GetProcessSP();
285  if (!process_sp)
286  return;
287 
288  ConstString symbol_name("__asan::AsanDie()");
289  const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType(
290  symbol_name, eSymbolTypeCode);
291 
292  if (symbol == nullptr)
293  return;
294 
295  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
296  return;
297 
298  Target &target = process_sp->GetTarget();
299  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
300 
301  if (symbol_address == LLDB_INVALID_ADDRESS)
302  return;
303 
304  bool internal = true;
305  bool hardware = false;
306  Breakpoint *breakpoint =
307  process_sp->GetTarget()
308  .CreateBreakpoint(symbol_address, internal, hardware)
309  .get();
310  breakpoint->SetCallback(InstrumentationRuntimeASan::NotifyBreakpointHit, this,
311  true);
312  breakpoint->SetBreakpointKind("address-sanitizer-report");
313  SetBreakpointID(breakpoint->GetID());
314 
315  SetActive(true);
316 }
317 
318 void InstrumentationRuntimeASan::Deactivate() {
319  if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
320  ProcessSP process_sp = GetProcessSP();
321  if (process_sp) {
322  process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
323  SetBreakpointID(LLDB_INVALID_BREAK_ID);
324  }
325  }
326  SetActive(false);
327 }
RegularExpression.h
lldb_private::ExecutionContext
Definition: ExecutionContext.h:291
lldb_private::StructuredData::Dictionary
Definition: StructuredData.h:352
lldb_private::RegularExpression
Definition: RegularExpression.h:18
lldb_private::InstrumentationRuntimeStopInfo
Definition: InstrumentationRuntimeStopInfo.h:19
lldb_private::StoppointCallbackContext
General Outline: When we hit a breakpoint we need to package up whatever information is needed to eva...
Definition: StoppointCallbackContext.h:26
lldb_private::Stoppoint::GetID
lldb::break_id_t GetID() const
Definition: Stoppoint.cpp:22
lldb_private::Address::IsValid
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:332
lldb_private::InstrumentationRuntimeASan
Definition: InstrumentationRuntimeASan.h:19
lldb::eSymbolTypeCode
@ eSymbolTypeCode
Definition: lldb-enumerations.h:615
lldb_private::EvaluateExpressionOptions::SetTimeout
void SetTimeout(const Timeout< std::micro > &timeout)
Definition: Target.h:323
lldb_private::EvaluateExpressionOptions::SetLanguage
void SetLanguage(lldb::LanguageType language)
Definition: Target.h:283
lldb_private::Symbol
Definition: Symbol.h:20
lldb_private::Symbol::ValueIsAddress
bool ValueIsAddress() const
Definition: Symbol.cpp:118
lldb_private::ExecutionContextRef::GetThreadSP
lldb::ThreadSP GetThreadSP() const
Get accessor that creates a strong reference from the weak thread reference contained in this object.
Definition: ExecutionContext.cpp:581
lldb_private::Breakpoint::SetBreakpointKind
void SetBreakpointKind(const char *kind)
Set the "kind" description for a breakpoint.
Definition: Breakpoint.h:442
lldb::ExpressionResults
ExpressionResults
The results of expression evaluation.
Definition: lldb-enumerations.h:270
Module.h
lldb_private::StoppointCallbackContext::exe_ctx_ref
ExecutionContextRef exe_ctx_ref
Definition: StoppointCallbackContext.h:43
lldb_private::EvaluateExpressionOptions
Definition: Target.h:255
StoppointCallbackContext.h
lldb_private::InstrumentationRuntimeASan::FormatDescription
std::string FormatDescription(StructuredData::ObjectSP report)
Definition: InstrumentationRuntimeASan.cpp:194
UserExpression.h
lldb_private::Target::CreateBreakpoint
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool request_hardware, LazyBool move_to_nearest_code)
Definition: Target.cpp:329
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
pc
@ pc
Definition: CompactUnwindInfo.cpp:1250
CommandReturnObject.h
Debugger.h
lldb_private::Target
Definition: Target.h:447
lldb_private::Address::GetOpcodeLoadAddress
lldb::addr_t GetOpcodeLoadAddress(Target *target, AddressClass addr_class=AddressClass::eInvalid) const
Get the load address as an opcode load address.
Definition: Address.cpp:367
address_sanitizer_retrieve_report_data_command
const char * address_sanitizer_retrieve_report_data_command
Definition: InstrumentationRuntimeASan.cpp:90
Target.h
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb::eSymbolTypeAny
@ eSymbolTypeAny
Definition: lldb-enumerations.h:612
InstrumentationRuntimeStopInfo.h
lldb_private::StructuredData::ObjectSP
std::shared_ptr< Object > ObjectSP
Definition: StructuredData.h:59
lldb::eExpressionCompleted
@ eExpressionCompleted
Definition: lldb-enumerations.h:271
lldb_private::Symbol::GetAddressRef
Address & GetAddressRef()
Definition: Symbol.h:57
lldb_private::ConstString
Definition: ConstString.h:40
lldb_private::EvaluateExpressionOptions::SetTryAllThreads
void SetTryAllThreads(bool try_others=true)
Definition: Target.h:335
PluginInterface.h
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:38
lldb_private::EvaluateExpressionOptions::SetUnwindOnError
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:302
Thread.h
lldb::eLanguageTypeObjC_plus_plus
@ eLanguageTypeObjC_plus_plus
Objective-C++.
Definition: lldb-enumerations.h:454
ValueObject.h
LLDB_INVALID_BREAK_ID
#define LLDB_INVALID_BREAK_ID
Definition: lldb-defines.h:49
lldb_private::EvaluateExpressionOptions::SetIgnoreBreakpoints
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:306
Symbol.h
StreamFile.h
lldb_private::Status
Definition: Status.h:44
address_sanitizer_retrieve_report_data_prefix
const char * address_sanitizer_retrieve_report_data_prefix
Definition: InstrumentationRuntimeASan.cpp:76
lldb_private::Breakpoint::SetCallback
void SetCallback(BreakpointHitCallback callback, void *baton, bool is_synchronous=false)
Set the callback action invoked when the breakpoint is hit.
Definition: Breakpoint.cpp:429
StopInfo.h
PluginManager.h
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
lldb_private::StructuredData::Dictionary::AddStringItem
void AddStringItem(llvm::StringRef key, llvm::StringRef value)
Definition: StructuredData.h:507
lldb::eInstrumentationRuntimeTypeAddressSanitizer
@ eInstrumentationRuntimeTypeAddressSanitizer
Definition: lldb-enumerations.h:486
lldb::user_id_t
uint64_t user_id_t
Definition: lldb-types.h:84
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::StructuredData::Dictionary::AddIntegerItem
void AddIntegerItem(llvm::StringRef key, uint64_t value)
Definition: StructuredData.h:499
lldb_private::Breakpoint::GetTarget
Target & GetTarget()
Accessor for the breakpoint Target.
Definition: Breakpoint.h:453
lldb_private::InstrumentationRuntime::GetProcessSP
lldb::ProcessSP GetProcessSP()
Definition: InstrumentationRuntime.h:51
Stream.h
LLDB_PLUGIN_DEFINE
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
lldb_private::EvaluateExpressionOptions::SetStopOthers
void SetStopOthers(bool stop_others=true)
Definition: Target.h:339
lldb_private::ExecutionContextRef::GetProcessSP
lldb::ProcessSP GetProcessSP() const
Get accessor that creates a strong reference from the weak process reference contained in this object...
Definition: ExecutionContext.cpp:574
lldb_private::EvaluateExpressionOptions::SetPrefix
void SetPrefix(const char *prefix)
Definition: Target.h:291
lldb
Definition: SBAddress.h:15
InstrumentationRuntimeASan.h
lldb_private::Breakpoint
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
Definition: Breakpoint.h:79
lldb_private::InstrumentationRuntimeASan::RetrieveReportData
StructuredData::ObjectSP RetrieveReportData()
Definition: InstrumentationRuntimeASan.cpp:113
lldb::InstrumentationRuntimeType
InstrumentationRuntimeType
Definition: lldb-enumerations.h:485
lldb_private::Status::AsCString
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:131
lldb_private::EvaluateExpressionOptions::SetAutoApplyFixIts
void SetAutoApplyFixIts(bool b)
Definition: Target.h:398