1dda28197Spatrick //===-- InstrumentationRuntimeASan.cpp ------------------------------------===//
2dda28197Spatrick //
3dda28197Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4dda28197Spatrick // See https://llvm.org/LICENSE.txt for license information.
5dda28197Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dda28197Spatrick //
7dda28197Spatrick //===----------------------------------------------------------------------===//
8dda28197Spatrick
9dda28197Spatrick #include "InstrumentationRuntimeASan.h"
10dda28197Spatrick
11dda28197Spatrick #include "lldb/Breakpoint/StoppointCallbackContext.h"
12dda28197Spatrick #include "lldb/Core/Debugger.h"
13dda28197Spatrick #include "lldb/Core/Module.h"
14dda28197Spatrick #include "lldb/Core/PluginInterface.h"
15dda28197Spatrick #include "lldb/Core/PluginManager.h"
16dda28197Spatrick #include "lldb/Core/StreamFile.h"
17dda28197Spatrick #include "lldb/Core/ValueObject.h"
18dda28197Spatrick #include "lldb/Expression/UserExpression.h"
19dda28197Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
20dda28197Spatrick #include "lldb/Symbol/Symbol.h"
21dda28197Spatrick #include "lldb/Target/InstrumentationRuntimeStopInfo.h"
22dda28197Spatrick #include "lldb/Target/StopInfo.h"
23dda28197Spatrick #include "lldb/Target/Target.h"
24dda28197Spatrick #include "lldb/Target/Thread.h"
25dda28197Spatrick #include "lldb/Utility/RegularExpression.h"
26dda28197Spatrick #include "lldb/Utility/Stream.h"
27dda28197Spatrick
28dda28197Spatrick #include "llvm/ADT/StringSwitch.h"
29dda28197Spatrick
30dda28197Spatrick using namespace lldb;
31dda28197Spatrick using namespace lldb_private;
32dda28197Spatrick
LLDB_PLUGIN_DEFINE(InstrumentationRuntimeASan)33dda28197Spatrick LLDB_PLUGIN_DEFINE(InstrumentationRuntimeASan)
34dda28197Spatrick
35dda28197Spatrick lldb::InstrumentationRuntimeSP
36dda28197Spatrick InstrumentationRuntimeASan::CreateInstance(const lldb::ProcessSP &process_sp) {
37dda28197Spatrick return InstrumentationRuntimeSP(new InstrumentationRuntimeASan(process_sp));
38dda28197Spatrick }
39dda28197Spatrick
Initialize()40dda28197Spatrick void InstrumentationRuntimeASan::Initialize() {
41dda28197Spatrick PluginManager::RegisterPlugin(
42dda28197Spatrick GetPluginNameStatic(), "AddressSanitizer instrumentation runtime plugin.",
43dda28197Spatrick CreateInstance, GetTypeStatic);
44dda28197Spatrick }
45dda28197Spatrick
Terminate()46dda28197Spatrick void InstrumentationRuntimeASan::Terminate() {
47dda28197Spatrick PluginManager::UnregisterPlugin(CreateInstance);
48dda28197Spatrick }
49dda28197Spatrick
GetTypeStatic()50dda28197Spatrick lldb::InstrumentationRuntimeType InstrumentationRuntimeASan::GetTypeStatic() {
51dda28197Spatrick return eInstrumentationRuntimeTypeAddressSanitizer;
52dda28197Spatrick }
53dda28197Spatrick
~InstrumentationRuntimeASan()54dda28197Spatrick InstrumentationRuntimeASan::~InstrumentationRuntimeASan() { Deactivate(); }
55dda28197Spatrick
56dda28197Spatrick const RegularExpression &
GetPatternForRuntimeLibrary()57dda28197Spatrick InstrumentationRuntimeASan::GetPatternForRuntimeLibrary() {
58dda28197Spatrick // FIXME: This shouldn't include the "dylib" suffix.
59dda28197Spatrick static RegularExpression regex(
60dda28197Spatrick llvm::StringRef("libclang_rt.asan_(.*)_dynamic\\.dylib"));
61dda28197Spatrick return regex;
62dda28197Spatrick }
63dda28197Spatrick
CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp)64dda28197Spatrick bool InstrumentationRuntimeASan::CheckIfRuntimeIsValid(
65dda28197Spatrick const lldb::ModuleSP module_sp) {
66dda28197Spatrick const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
67dda28197Spatrick ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny);
68dda28197Spatrick
69dda28197Spatrick return symbol != nullptr;
70dda28197Spatrick }
71dda28197Spatrick
72dda28197Spatrick const char *address_sanitizer_retrieve_report_data_prefix = R"(
73dda28197Spatrick extern "C"
74dda28197Spatrick {
75dda28197Spatrick int __asan_report_present();
76dda28197Spatrick void *__asan_get_report_pc();
77dda28197Spatrick void *__asan_get_report_bp();
78dda28197Spatrick void *__asan_get_report_sp();
79dda28197Spatrick void *__asan_get_report_address();
80dda28197Spatrick const char *__asan_get_report_description();
81dda28197Spatrick int __asan_get_report_access_type();
82dda28197Spatrick size_t __asan_get_report_access_size();
83dda28197Spatrick }
84dda28197Spatrick )";
85dda28197Spatrick
86dda28197Spatrick const char *address_sanitizer_retrieve_report_data_command = R"(
87dda28197Spatrick struct {
88dda28197Spatrick int present;
89dda28197Spatrick int access_type;
90dda28197Spatrick void *pc;
91dda28197Spatrick void *bp;
92dda28197Spatrick void *sp;
93dda28197Spatrick void *address;
94dda28197Spatrick size_t access_size;
95dda28197Spatrick const char *description;
96dda28197Spatrick } t;
97dda28197Spatrick
98dda28197Spatrick t.present = __asan_report_present();
99dda28197Spatrick t.access_type = __asan_get_report_access_type();
100dda28197Spatrick t.pc = __asan_get_report_pc();
101dda28197Spatrick t.bp = __asan_get_report_bp();
102dda28197Spatrick t.sp = __asan_get_report_sp();
103dda28197Spatrick t.address = __asan_get_report_address();
104dda28197Spatrick t.access_size = __asan_get_report_access_size();
105dda28197Spatrick t.description = __asan_get_report_description();
106dda28197Spatrick t
107dda28197Spatrick )";
108dda28197Spatrick
RetrieveReportData()109dda28197Spatrick StructuredData::ObjectSP InstrumentationRuntimeASan::RetrieveReportData() {
110dda28197Spatrick ProcessSP process_sp = GetProcessSP();
111dda28197Spatrick if (!process_sp)
112dda28197Spatrick return StructuredData::ObjectSP();
113dda28197Spatrick
114dda28197Spatrick ThreadSP thread_sp =
115dda28197Spatrick process_sp->GetThreadList().GetExpressionExecutionThread();
116dda28197Spatrick StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
117dda28197Spatrick
118dda28197Spatrick if (!frame_sp)
119dda28197Spatrick return StructuredData::ObjectSP();
120dda28197Spatrick
121dda28197Spatrick EvaluateExpressionOptions options;
122dda28197Spatrick options.SetUnwindOnError(true);
123dda28197Spatrick options.SetTryAllThreads(true);
124dda28197Spatrick options.SetStopOthers(true);
125dda28197Spatrick options.SetIgnoreBreakpoints(true);
126dda28197Spatrick options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
127dda28197Spatrick options.SetPrefix(address_sanitizer_retrieve_report_data_prefix);
128dda28197Spatrick options.SetAutoApplyFixIts(false);
129dda28197Spatrick options.SetLanguage(eLanguageTypeObjC_plus_plus);
130dda28197Spatrick
131dda28197Spatrick ValueObjectSP return_value_sp;
132dda28197Spatrick ExecutionContext exe_ctx;
133dda28197Spatrick Status eval_error;
134dda28197Spatrick frame_sp->CalculateExecutionContext(exe_ctx);
135dda28197Spatrick ExpressionResults result = UserExpression::Evaluate(
136dda28197Spatrick exe_ctx, options, address_sanitizer_retrieve_report_data_command, "",
137dda28197Spatrick return_value_sp, eval_error);
138dda28197Spatrick if (result != eExpressionCompleted) {
139*f6aab3d8Srobert StreamString ss;
140*f6aab3d8Srobert ss << "cannot evaluate AddressSanitizer expression:\n";
141*f6aab3d8Srobert ss << eval_error.AsCString();
142*f6aab3d8Srobert Debugger::ReportWarning(ss.GetString().str(),
143*f6aab3d8Srobert process_sp->GetTarget().GetDebugger().GetID());
144dda28197Spatrick return StructuredData::ObjectSP();
145dda28197Spatrick }
146dda28197Spatrick
147dda28197Spatrick int present = return_value_sp->GetValueForExpressionPath(".present")
148dda28197Spatrick ->GetValueAsUnsigned(0);
149dda28197Spatrick if (present != 1)
150dda28197Spatrick return StructuredData::ObjectSP();
151dda28197Spatrick
152dda28197Spatrick addr_t pc =
153dda28197Spatrick return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
154dda28197Spatrick /* commented out because rdar://problem/18533301
155dda28197Spatrick addr_t bp =
156dda28197Spatrick return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
157dda28197Spatrick addr_t sp =
158dda28197Spatrick return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
159dda28197Spatrick */
160dda28197Spatrick addr_t address = return_value_sp->GetValueForExpressionPath(".address")
161dda28197Spatrick ->GetValueAsUnsigned(0);
162dda28197Spatrick addr_t access_type =
163dda28197Spatrick return_value_sp->GetValueForExpressionPath(".access_type")
164dda28197Spatrick ->GetValueAsUnsigned(0);
165dda28197Spatrick addr_t access_size =
166dda28197Spatrick return_value_sp->GetValueForExpressionPath(".access_size")
167dda28197Spatrick ->GetValueAsUnsigned(0);
168dda28197Spatrick addr_t description_ptr =
169dda28197Spatrick return_value_sp->GetValueForExpressionPath(".description")
170dda28197Spatrick ->GetValueAsUnsigned(0);
171dda28197Spatrick std::string description;
172dda28197Spatrick Status error;
173dda28197Spatrick process_sp->ReadCStringFromMemory(description_ptr, description, error);
174dda28197Spatrick
175dda28197Spatrick StructuredData::Dictionary *dict = new StructuredData::Dictionary();
176dda28197Spatrick dict->AddStringItem("instrumentation_class", "AddressSanitizer");
177dda28197Spatrick dict->AddStringItem("stop_type", "fatal_error");
178dda28197Spatrick dict->AddIntegerItem("pc", pc);
179dda28197Spatrick /* commented out because rdar://problem/18533301
180dda28197Spatrick dict->AddIntegerItem("bp", bp);
181dda28197Spatrick dict->AddIntegerItem("sp", sp);
182dda28197Spatrick */
183dda28197Spatrick dict->AddIntegerItem("address", address);
184dda28197Spatrick dict->AddIntegerItem("access_type", access_type);
185dda28197Spatrick dict->AddIntegerItem("access_size", access_size);
186dda28197Spatrick dict->AddStringItem("description", description);
187dda28197Spatrick
188dda28197Spatrick return StructuredData::ObjectSP(dict);
189dda28197Spatrick }
190dda28197Spatrick
191dda28197Spatrick std::string
FormatDescription(StructuredData::ObjectSP report)192dda28197Spatrick InstrumentationRuntimeASan::FormatDescription(StructuredData::ObjectSP report) {
193dda28197Spatrick std::string description = std::string(report->GetAsDictionary()
194dda28197Spatrick ->GetValueForKey("description")
195dda28197Spatrick ->GetAsString()
196dda28197Spatrick ->GetValue());
197dda28197Spatrick return llvm::StringSwitch<std::string>(description)
198dda28197Spatrick .Case("heap-use-after-free", "Use of deallocated memory")
199dda28197Spatrick .Case("heap-buffer-overflow", "Heap buffer overflow")
200dda28197Spatrick .Case("stack-buffer-underflow", "Stack buffer underflow")
201dda28197Spatrick .Case("initialization-order-fiasco", "Initialization order problem")
202dda28197Spatrick .Case("stack-buffer-overflow", "Stack buffer overflow")
203dda28197Spatrick .Case("stack-use-after-return", "Use of stack memory after return")
204dda28197Spatrick .Case("use-after-poison", "Use of poisoned memory")
205dda28197Spatrick .Case("container-overflow", "Container overflow")
206dda28197Spatrick .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
207dda28197Spatrick .Case("global-buffer-overflow", "Global buffer overflow")
208dda28197Spatrick .Case("unknown-crash", "Invalid memory access")
209dda28197Spatrick .Case("stack-overflow", "Stack space exhausted")
210dda28197Spatrick .Case("null-deref", "Dereference of null pointer")
211dda28197Spatrick .Case("wild-jump", "Jump to non-executable address")
212dda28197Spatrick .Case("wild-addr-write", "Write through wild pointer")
213dda28197Spatrick .Case("wild-addr-read", "Read from wild pointer")
214dda28197Spatrick .Case("wild-addr", "Access through wild pointer")
215dda28197Spatrick .Case("signal", "Deadly signal")
216dda28197Spatrick .Case("double-free", "Deallocation of freed memory")
217dda28197Spatrick .Case("new-delete-type-mismatch",
218dda28197Spatrick "Deallocation size different from allocation size")
219dda28197Spatrick .Case("bad-free", "Deallocation of non-allocated memory")
220dda28197Spatrick .Case("alloc-dealloc-mismatch",
221dda28197Spatrick "Mismatch between allocation and deallocation APIs")
222dda28197Spatrick .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
223dda28197Spatrick .Case("bad-__sanitizer_get_allocated_size",
224dda28197Spatrick "Invalid argument to __sanitizer_get_allocated_size")
225dda28197Spatrick .Case("param-overlap",
226dda28197Spatrick "Call to function disallowing overlapping memory ranges")
227dda28197Spatrick .Case("negative-size-param", "Negative size used when accessing memory")
228dda28197Spatrick .Case("bad-__sanitizer_annotate_contiguous_container",
229dda28197Spatrick "Invalid argument to __sanitizer_annotate_contiguous_container")
230dda28197Spatrick .Case("odr-violation", "Symbol defined in multiple translation units")
231dda28197Spatrick .Case(
232dda28197Spatrick "invalid-pointer-pair",
233dda28197Spatrick "Comparison or arithmetic on pointers from different memory regions")
234dda28197Spatrick // for unknown report codes just show the code
235dda28197Spatrick .Default("AddressSanitizer detected: " + description);
236dda28197Spatrick }
237dda28197Spatrick
NotifyBreakpointHit(void * baton,StoppointCallbackContext * context,user_id_t break_id,user_id_t break_loc_id)238dda28197Spatrick bool InstrumentationRuntimeASan::NotifyBreakpointHit(
239dda28197Spatrick void *baton, StoppointCallbackContext *context, user_id_t break_id,
240dda28197Spatrick user_id_t break_loc_id) {
241dda28197Spatrick assert(baton && "null baton");
242dda28197Spatrick if (!baton)
243dda28197Spatrick return false;
244dda28197Spatrick
245dda28197Spatrick InstrumentationRuntimeASan *const instance =
246dda28197Spatrick static_cast<InstrumentationRuntimeASan *>(baton);
247dda28197Spatrick
248dda28197Spatrick ProcessSP process_sp = instance->GetProcessSP();
249dda28197Spatrick
250dda28197Spatrick if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
251dda28197Spatrick return false;
252dda28197Spatrick
253dda28197Spatrick StructuredData::ObjectSP report = instance->RetrieveReportData();
254dda28197Spatrick std::string description;
255dda28197Spatrick if (report) {
256dda28197Spatrick description = instance->FormatDescription(report);
257dda28197Spatrick }
258dda28197Spatrick // Make sure this is the right process
259dda28197Spatrick if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
260dda28197Spatrick ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
261dda28197Spatrick if (thread_sp)
262dda28197Spatrick thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo::
263dda28197Spatrick CreateStopReasonWithInstrumentationData(
264dda28197Spatrick *thread_sp, description, report));
265dda28197Spatrick
266dda28197Spatrick StreamFileSP stream_sp(
267dda28197Spatrick process_sp->GetTarget().GetDebugger().GetOutputStreamSP());
268dda28197Spatrick if (stream_sp) {
269dda28197Spatrick stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
270dda28197Spatrick "info -s' to get extended information about the "
271dda28197Spatrick "report.\n");
272dda28197Spatrick }
273dda28197Spatrick return true; // Return true to stop the target
274dda28197Spatrick } else
275dda28197Spatrick return false; // Let target run
276dda28197Spatrick }
277dda28197Spatrick
Activate()278dda28197Spatrick void InstrumentationRuntimeASan::Activate() {
279dda28197Spatrick if (IsActive())
280dda28197Spatrick return;
281dda28197Spatrick
282dda28197Spatrick ProcessSP process_sp = GetProcessSP();
283dda28197Spatrick if (!process_sp)
284dda28197Spatrick return;
285dda28197Spatrick
286*f6aab3d8Srobert ConstString symbol_name("_ZN6__asanL7AsanDieEv");
287dda28197Spatrick const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType(
288dda28197Spatrick symbol_name, eSymbolTypeCode);
289dda28197Spatrick
290dda28197Spatrick if (symbol == nullptr)
291dda28197Spatrick return;
292dda28197Spatrick
293dda28197Spatrick if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
294dda28197Spatrick return;
295dda28197Spatrick
296dda28197Spatrick Target &target = process_sp->GetTarget();
297dda28197Spatrick addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
298dda28197Spatrick
299dda28197Spatrick if (symbol_address == LLDB_INVALID_ADDRESS)
300dda28197Spatrick return;
301dda28197Spatrick
302*f6aab3d8Srobert const bool internal = true;
303*f6aab3d8Srobert const bool hardware = false;
304*f6aab3d8Srobert const bool sync = false;
305dda28197Spatrick Breakpoint *breakpoint =
306dda28197Spatrick process_sp->GetTarget()
307dda28197Spatrick .CreateBreakpoint(symbol_address, internal, hardware)
308dda28197Spatrick .get();
309dda28197Spatrick breakpoint->SetCallback(InstrumentationRuntimeASan::NotifyBreakpointHit, this,
310*f6aab3d8Srobert sync);
311dda28197Spatrick breakpoint->SetBreakpointKind("address-sanitizer-report");
312dda28197Spatrick SetBreakpointID(breakpoint->GetID());
313dda28197Spatrick
314dda28197Spatrick SetActive(true);
315dda28197Spatrick }
316dda28197Spatrick
Deactivate()317dda28197Spatrick void InstrumentationRuntimeASan::Deactivate() {
318dda28197Spatrick if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
319dda28197Spatrick ProcessSP process_sp = GetProcessSP();
320dda28197Spatrick if (process_sp) {
321dda28197Spatrick process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
322dda28197Spatrick SetBreakpointID(LLDB_INVALID_BREAK_ID);
323dda28197Spatrick }
324dda28197Spatrick }
325dda28197Spatrick SetActive(false);
326dda28197Spatrick }
327