xref: /llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp (revision 01e980e792651391dfc3b399dbe300eddbbd0997)
177edd9b7SUsama Hameed //===-- ReportRetriever.cpp -----------------------------------------------===//
277edd9b7SUsama Hameed //
377edd9b7SUsama Hameed // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
477edd9b7SUsama Hameed // See https://llvm.org/LICENSE.txt for license information.
577edd9b7SUsama Hameed // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
677edd9b7SUsama Hameed //
777edd9b7SUsama Hameed //===----------------------------------------------------------------------===//
877edd9b7SUsama Hameed 
977edd9b7SUsama Hameed #include "ReportRetriever.h"
1077edd9b7SUsama Hameed 
1177edd9b7SUsama Hameed #include "lldb/Breakpoint/StoppointCallbackContext.h"
1277edd9b7SUsama Hameed #include "lldb/Core/Debugger.h"
1377edd9b7SUsama Hameed #include "lldb/Core/Module.h"
1477edd9b7SUsama Hameed #include "lldb/Expression/UserExpression.h"
1577edd9b7SUsama Hameed #include "lldb/Target/InstrumentationRuntimeStopInfo.h"
16b852fb1eSJonas Devlieghere #include "lldb/ValueObject/ValueObject.h"
1777edd9b7SUsama Hameed 
1877edd9b7SUsama Hameed using namespace lldb;
1977edd9b7SUsama Hameed using namespace lldb_private;
2077edd9b7SUsama Hameed 
2177edd9b7SUsama Hameed const char *address_sanitizer_retrieve_report_data_prefix = R"(
2277edd9b7SUsama Hameed extern "C"
2377edd9b7SUsama Hameed {
2477edd9b7SUsama Hameed int __asan_report_present();
2577edd9b7SUsama Hameed void *__asan_get_report_pc();
2677edd9b7SUsama Hameed void *__asan_get_report_bp();
2777edd9b7SUsama Hameed void *__asan_get_report_sp();
2877edd9b7SUsama Hameed void *__asan_get_report_address();
2977edd9b7SUsama Hameed const char *__asan_get_report_description();
3077edd9b7SUsama Hameed int __asan_get_report_access_type();
3177edd9b7SUsama Hameed size_t __asan_get_report_access_size();
3277edd9b7SUsama Hameed }
3377edd9b7SUsama Hameed )";
3477edd9b7SUsama Hameed 
3577edd9b7SUsama Hameed const char *address_sanitizer_retrieve_report_data_command = R"(
3677edd9b7SUsama Hameed struct {
3777edd9b7SUsama Hameed     int present;
3877edd9b7SUsama Hameed     int access_type;
3977edd9b7SUsama Hameed     void *pc;
4077edd9b7SUsama Hameed     void *bp;
4177edd9b7SUsama Hameed     void *sp;
4277edd9b7SUsama Hameed     void *address;
4377edd9b7SUsama Hameed     size_t access_size;
4477edd9b7SUsama Hameed     const char *description;
4577edd9b7SUsama Hameed } t;
4677edd9b7SUsama Hameed 
4777edd9b7SUsama Hameed t.present = __asan_report_present();
4877edd9b7SUsama Hameed t.access_type = __asan_get_report_access_type();
4977edd9b7SUsama Hameed t.pc = __asan_get_report_pc();
5077edd9b7SUsama Hameed t.bp = __asan_get_report_bp();
5177edd9b7SUsama Hameed t.sp = __asan_get_report_sp();
5277edd9b7SUsama Hameed t.address = __asan_get_report_address();
5377edd9b7SUsama Hameed t.access_size = __asan_get_report_access_size();
5477edd9b7SUsama Hameed t.description = __asan_get_report_description();
5577edd9b7SUsama Hameed t
5677edd9b7SUsama Hameed )";
5777edd9b7SUsama Hameed 
5877edd9b7SUsama Hameed StructuredData::ObjectSP
5977edd9b7SUsama Hameed ReportRetriever::RetrieveReportData(const ProcessSP process_sp) {
6077edd9b7SUsama Hameed   if (!process_sp)
6177edd9b7SUsama Hameed     return StructuredData::ObjectSP();
6277edd9b7SUsama Hameed 
6377edd9b7SUsama Hameed   ThreadSP thread_sp =
6477edd9b7SUsama Hameed       process_sp->GetThreadList().GetExpressionExecutionThread();
6577edd9b7SUsama Hameed 
6677edd9b7SUsama Hameed   if (!thread_sp)
6777edd9b7SUsama Hameed     return StructuredData::ObjectSP();
6877edd9b7SUsama Hameed 
6977edd9b7SUsama Hameed   StackFrameSP frame_sp =
7077edd9b7SUsama Hameed       thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
7177edd9b7SUsama Hameed 
7277edd9b7SUsama Hameed   if (!frame_sp)
7377edd9b7SUsama Hameed     return StructuredData::ObjectSP();
7477edd9b7SUsama Hameed 
7577edd9b7SUsama Hameed   EvaluateExpressionOptions options;
7677edd9b7SUsama Hameed   options.SetUnwindOnError(true);
7777edd9b7SUsama Hameed   options.SetTryAllThreads(true);
7877edd9b7SUsama Hameed   options.SetStopOthers(true);
7977edd9b7SUsama Hameed   options.SetIgnoreBreakpoints(true);
8077edd9b7SUsama Hameed   options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
8177edd9b7SUsama Hameed   options.SetPrefix(address_sanitizer_retrieve_report_data_prefix);
8277edd9b7SUsama Hameed   options.SetAutoApplyFixIts(false);
8377edd9b7SUsama Hameed   options.SetLanguage(eLanguageTypeObjC_plus_plus);
8477edd9b7SUsama Hameed 
8577edd9b7SUsama Hameed   ValueObjectSP return_value_sp;
8677edd9b7SUsama Hameed   ExecutionContext exe_ctx;
8777edd9b7SUsama Hameed   frame_sp->CalculateExecutionContext(exe_ctx);
8877edd9b7SUsama Hameed   ExpressionResults result = UserExpression::Evaluate(
8977edd9b7SUsama Hameed       exe_ctx, options, address_sanitizer_retrieve_report_data_command, "",
906a8a4d51SAdrian Prantl       return_value_sp);
9177edd9b7SUsama Hameed   if (result != eExpressionCompleted) {
9277edd9b7SUsama Hameed     StreamString ss;
9377edd9b7SUsama Hameed     ss << "cannot evaluate AddressSanitizer expression:\n";
946a8a4d51SAdrian Prantl     if (return_value_sp)
956a8a4d51SAdrian Prantl       ss << return_value_sp->GetError().AsCString();
9677edd9b7SUsama Hameed     Debugger::ReportWarning(ss.GetString().str(),
9777edd9b7SUsama Hameed                             process_sp->GetTarget().GetDebugger().GetID());
9877edd9b7SUsama Hameed     return StructuredData::ObjectSP();
9977edd9b7SUsama Hameed   }
10077edd9b7SUsama Hameed 
10177edd9b7SUsama Hameed   int present = return_value_sp->GetValueForExpressionPath(".present")
10277edd9b7SUsama Hameed                     ->GetValueAsUnsigned(0);
10377edd9b7SUsama Hameed   if (present != 1)
10477edd9b7SUsama Hameed     return StructuredData::ObjectSP();
10577edd9b7SUsama Hameed 
10677edd9b7SUsama Hameed   addr_t pc =
10777edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
10877edd9b7SUsama Hameed   addr_t bp =
10977edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
11077edd9b7SUsama Hameed   addr_t sp =
11177edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
11277edd9b7SUsama Hameed   addr_t address = return_value_sp->GetValueForExpressionPath(".address")
11377edd9b7SUsama Hameed                        ->GetValueAsUnsigned(0);
11477edd9b7SUsama Hameed   addr_t access_type =
11577edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".access_type")
11677edd9b7SUsama Hameed           ->GetValueAsUnsigned(0);
11777edd9b7SUsama Hameed   addr_t access_size =
11877edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".access_size")
11977edd9b7SUsama Hameed           ->GetValueAsUnsigned(0);
12077edd9b7SUsama Hameed   addr_t description_ptr =
12177edd9b7SUsama Hameed       return_value_sp->GetValueForExpressionPath(".description")
12277edd9b7SUsama Hameed           ->GetValueAsUnsigned(0);
12377edd9b7SUsama Hameed   std::string description;
12477edd9b7SUsama Hameed   Status error;
12577edd9b7SUsama Hameed   process_sp->ReadCStringFromMemory(description_ptr, description, error);
12677edd9b7SUsama Hameed 
12777edd9b7SUsama Hameed   auto dict = std::make_shared<StructuredData::Dictionary>();
12877edd9b7SUsama Hameed   if (!dict)
12977edd9b7SUsama Hameed     return StructuredData::ObjectSP();
13077edd9b7SUsama Hameed 
13177edd9b7SUsama Hameed   dict->AddStringItem("instrumentation_class", "AddressSanitizer");
13277edd9b7SUsama Hameed   dict->AddStringItem("stop_type", "fatal_error");
13377edd9b7SUsama Hameed   dict->AddIntegerItem("pc", pc);
13477edd9b7SUsama Hameed   dict->AddIntegerItem("bp", bp);
13577edd9b7SUsama Hameed   dict->AddIntegerItem("sp", sp);
13677edd9b7SUsama Hameed   dict->AddIntegerItem("address", address);
13777edd9b7SUsama Hameed   dict->AddIntegerItem("access_type", access_type);
13877edd9b7SUsama Hameed   dict->AddIntegerItem("access_size", access_size);
13977edd9b7SUsama Hameed   dict->AddStringItem("description", description);
14077edd9b7SUsama Hameed 
14177edd9b7SUsama Hameed   return StructuredData::ObjectSP(dict);
14277edd9b7SUsama Hameed }
14377edd9b7SUsama Hameed 
14477edd9b7SUsama Hameed std::string
14577edd9b7SUsama Hameed ReportRetriever::FormatDescription(StructuredData::ObjectSP report) {
14677edd9b7SUsama Hameed   std::string description = std::string(report->GetAsDictionary()
14777edd9b7SUsama Hameed                                             ->GetValueForKey("description")
14877edd9b7SUsama Hameed                                             ->GetAsString()
14977edd9b7SUsama Hameed                                             ->GetValue());
15077edd9b7SUsama Hameed   return llvm::StringSwitch<std::string>(description)
15177edd9b7SUsama Hameed       .Case("heap-use-after-free", "Use of deallocated memory")
15277edd9b7SUsama Hameed       .Case("heap-buffer-overflow", "Heap buffer overflow")
15377edd9b7SUsama Hameed       .Case("stack-buffer-underflow", "Stack buffer underflow")
15477edd9b7SUsama Hameed       .Case("initialization-order-fiasco", "Initialization order problem")
15577edd9b7SUsama Hameed       .Case("stack-buffer-overflow", "Stack buffer overflow")
15677edd9b7SUsama Hameed       .Case("stack-use-after-return", "Use of stack memory after return")
15777edd9b7SUsama Hameed       .Case("use-after-poison", "Use of poisoned memory")
15877edd9b7SUsama Hameed       .Case("container-overflow", "Container overflow")
15977edd9b7SUsama Hameed       .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
16077edd9b7SUsama Hameed       .Case("global-buffer-overflow", "Global buffer overflow")
16177edd9b7SUsama Hameed       .Case("unknown-crash", "Invalid memory access")
16277edd9b7SUsama Hameed       .Case("stack-overflow", "Stack space exhausted")
16377edd9b7SUsama Hameed       .Case("null-deref", "Dereference of null pointer")
16477edd9b7SUsama Hameed       .Case("wild-jump", "Jump to non-executable address")
16577edd9b7SUsama Hameed       .Case("wild-addr-write", "Write through wild pointer")
16677edd9b7SUsama Hameed       .Case("wild-addr-read", "Read from wild pointer")
16777edd9b7SUsama Hameed       .Case("wild-addr", "Access through wild pointer")
16877edd9b7SUsama Hameed       .Case("signal", "Deadly signal")
16977edd9b7SUsama Hameed       .Case("double-free", "Deallocation of freed memory")
17077edd9b7SUsama Hameed       .Case("new-delete-type-mismatch",
17177edd9b7SUsama Hameed             "Deallocation size different from allocation size")
17277edd9b7SUsama Hameed       .Case("bad-free", "Deallocation of non-allocated memory")
17377edd9b7SUsama Hameed       .Case("alloc-dealloc-mismatch",
17477edd9b7SUsama Hameed             "Mismatch between allocation and deallocation APIs")
17577edd9b7SUsama Hameed       .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
17677edd9b7SUsama Hameed       .Case("bad-__sanitizer_get_allocated_size",
17777edd9b7SUsama Hameed             "Invalid argument to __sanitizer_get_allocated_size")
17877edd9b7SUsama Hameed       .Case("param-overlap",
17977edd9b7SUsama Hameed             "Call to function disallowing overlapping memory ranges")
18077edd9b7SUsama Hameed       .Case("negative-size-param", "Negative size used when accessing memory")
18177edd9b7SUsama Hameed       .Case("bad-__sanitizer_annotate_contiguous_container",
18277edd9b7SUsama Hameed             "Invalid argument to __sanitizer_annotate_contiguous_container")
18377edd9b7SUsama Hameed       .Case("odr-violation", "Symbol defined in multiple translation units")
18477edd9b7SUsama Hameed       .Case(
18577edd9b7SUsama Hameed           "invalid-pointer-pair",
18677edd9b7SUsama Hameed           "Comparison or arithmetic on pointers from different memory regions")
18777edd9b7SUsama Hameed       // for unknown report codes just show the code
18877edd9b7SUsama Hameed       .Default("AddressSanitizer detected: " + description);
18977edd9b7SUsama Hameed }
19077edd9b7SUsama Hameed 
19177edd9b7SUsama Hameed bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp,
19277edd9b7SUsama Hameed                                           StoppointCallbackContext *context,
19377edd9b7SUsama Hameed                                           user_id_t break_id,
19477edd9b7SUsama Hameed                                           user_id_t break_loc_id) {
19577edd9b7SUsama Hameed   // Make sure this is the right process
19677edd9b7SUsama Hameed   if (!process_sp || process_sp != context->exe_ctx_ref.GetProcessSP())
19777edd9b7SUsama Hameed     return false;
19877edd9b7SUsama Hameed 
19977edd9b7SUsama Hameed   if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
20077edd9b7SUsama Hameed     return false;
20177edd9b7SUsama Hameed 
20277edd9b7SUsama Hameed   StructuredData::ObjectSP report = RetrieveReportData(process_sp);
20377edd9b7SUsama Hameed   if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary)
20477edd9b7SUsama Hameed     return false;
20577edd9b7SUsama Hameed 
20677edd9b7SUsama Hameed   std::string description = FormatDescription(report);
20777edd9b7SUsama Hameed 
20877edd9b7SUsama Hameed   if (ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP())
20977edd9b7SUsama Hameed     thread_sp->SetStopInfo(
21077edd9b7SUsama Hameed         InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
21177edd9b7SUsama Hameed             *thread_sp, description, report));
21277edd9b7SUsama Hameed 
21377edd9b7SUsama Hameed   if (StreamFileSP stream_sp = StreamFileSP(
21477edd9b7SUsama Hameed           process_sp->GetTarget().GetDebugger().GetOutputStreamSP()))
21577edd9b7SUsama Hameed     stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
21677edd9b7SUsama Hameed                       "info -s' to get extended information about the "
21777edd9b7SUsama Hameed                       "report.\n");
21877edd9b7SUsama Hameed 
21977edd9b7SUsama Hameed   return true; // Return true to stop the target
22077edd9b7SUsama Hameed }
22177edd9b7SUsama Hameed 
22277edd9b7SUsama Hameed Breakpoint *ReportRetriever::SetupBreakpoint(ModuleSP module_sp,
22377edd9b7SUsama Hameed                                              ProcessSP process_sp,
22477edd9b7SUsama Hameed                                              ConstString symbol_name) {
22577edd9b7SUsama Hameed   if (!module_sp || !process_sp)
22677edd9b7SUsama Hameed     return nullptr;
22777edd9b7SUsama Hameed 
22877edd9b7SUsama Hameed   const Symbol *symbol =
22977edd9b7SUsama Hameed       module_sp->FindFirstSymbolWithNameAndType(symbol_name, eSymbolTypeCode);
23077edd9b7SUsama Hameed 
23177edd9b7SUsama Hameed   if (symbol == nullptr)
23277edd9b7SUsama Hameed     return nullptr;
23377edd9b7SUsama Hameed 
23477edd9b7SUsama Hameed   if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
23577edd9b7SUsama Hameed     return nullptr;
23677edd9b7SUsama Hameed 
237*01e980e7SJulian Lettner   const Address &address = symbol->GetAddressRef();
23877edd9b7SUsama Hameed   const bool internal = true;
23977edd9b7SUsama Hameed   const bool hardware = false;
24077edd9b7SUsama Hameed 
241*01e980e7SJulian Lettner   Breakpoint *breakpoint = process_sp->GetTarget()
242*01e980e7SJulian Lettner                                .CreateBreakpoint(address, internal, hardware)
24377edd9b7SUsama Hameed                                .get();
24477edd9b7SUsama Hameed 
24577edd9b7SUsama Hameed   return breakpoint;
24677edd9b7SUsama Hameed }
247