1 //===-- ReportRetriever.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ReportRetriever.h"
11 #include "lldb/Breakpoint/StoppointCallbackContext.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Expression/UserExpression.h"
15 #include "lldb/Target/InstrumentationRuntimeStopInfo.h"
16 #include "lldb/ValueObject/ValueObject.h"
19 using namespace lldb_private
;
21 const char *address_sanitizer_retrieve_report_data_prefix
= R
"(
24 int __asan_report_present();
25 void *__asan_get_report_pc();
26 void *__asan_get_report_bp();
27 void *__asan_get_report_sp();
28 void *__asan_get_report_address();
29 const char *__asan_get_report_description();
30 int __asan_get_report_access_type();
31 size_t __asan_get_report_access_size();
35 const char *address_sanitizer_retrieve_report_data_command
= R
"(
44 const char *description;
47 t.present = __asan_report_present();
48 t.access_type = __asan_get_report_access_type();
49 t.pc = __asan_get_report_pc();
50 t.bp = __asan_get_report_bp();
51 t.sp = __asan_get_report_sp();
52 t.address = __asan_get_report_address();
53 t.access_size = __asan_get_report_access_size();
54 t.description = __asan_get_report_description();
58 StructuredData::ObjectSP
59 ReportRetriever::RetrieveReportData(const ProcessSP process_sp
) {
61 return StructuredData::ObjectSP();
64 process_sp
->GetThreadList().GetExpressionExecutionThread();
67 return StructuredData::ObjectSP();
69 StackFrameSP frame_sp
=
70 thread_sp
->GetSelectedFrame(DoNoSelectMostRelevantFrame
);
73 return StructuredData::ObjectSP();
75 EvaluateExpressionOptions options
;
76 options
.SetUnwindOnError(true);
77 options
.SetTryAllThreads(true);
78 options
.SetStopOthers(true);
79 options
.SetIgnoreBreakpoints(true);
80 options
.SetTimeout(process_sp
->GetUtilityExpressionTimeout());
81 options
.SetPrefix(address_sanitizer_retrieve_report_data_prefix
);
82 options
.SetAutoApplyFixIts(false);
83 options
.SetLanguage(eLanguageTypeObjC_plus_plus
);
85 ValueObjectSP return_value_sp
;
86 ExecutionContext exe_ctx
;
87 frame_sp
->CalculateExecutionContext(exe_ctx
);
88 ExpressionResults result
= UserExpression::Evaluate(
89 exe_ctx
, options
, address_sanitizer_retrieve_report_data_command
, "",
91 if (result
!= eExpressionCompleted
) {
93 ss
<< "cannot evaluate AddressSanitizer expression:\n";
95 ss
<< return_value_sp
->GetError().AsCString();
96 Debugger::ReportWarning(ss
.GetString().str(),
97 process_sp
->GetTarget().GetDebugger().GetID());
98 return StructuredData::ObjectSP();
101 int present
= return_value_sp
->GetValueForExpressionPath(".present")
102 ->GetValueAsUnsigned(0);
104 return StructuredData::ObjectSP();
107 return_value_sp
->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
109 return_value_sp
->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
111 return_value_sp
->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
112 addr_t address
= return_value_sp
->GetValueForExpressionPath(".address")
113 ->GetValueAsUnsigned(0);
115 return_value_sp
->GetValueForExpressionPath(".access_type")
116 ->GetValueAsUnsigned(0);
118 return_value_sp
->GetValueForExpressionPath(".access_size")
119 ->GetValueAsUnsigned(0);
120 addr_t description_ptr
=
121 return_value_sp
->GetValueForExpressionPath(".description")
122 ->GetValueAsUnsigned(0);
123 std::string description
;
125 process_sp
->ReadCStringFromMemory(description_ptr
, description
, error
);
127 auto dict
= std::make_shared
<StructuredData::Dictionary
>();
129 return StructuredData::ObjectSP();
131 dict
->AddStringItem("instrumentation_class", "AddressSanitizer");
132 dict
->AddStringItem("stop_type", "fatal_error");
133 dict
->AddIntegerItem("pc", pc
);
134 dict
->AddIntegerItem("bp", bp
);
135 dict
->AddIntegerItem("sp", sp
);
136 dict
->AddIntegerItem("address", address
);
137 dict
->AddIntegerItem("access_type", access_type
);
138 dict
->AddIntegerItem("access_size", access_size
);
139 dict
->AddStringItem("description", description
);
141 return StructuredData::ObjectSP(dict
);
145 ReportRetriever::FormatDescription(StructuredData::ObjectSP report
) {
146 std::string description
= std::string(report
->GetAsDictionary()
147 ->GetValueForKey("description")
150 return llvm::StringSwitch
<std::string
>(description
)
151 .Case("heap-use-after-free", "Use of deallocated memory")
152 .Case("heap-buffer-overflow", "Heap buffer overflow")
153 .Case("stack-buffer-underflow", "Stack buffer underflow")
154 .Case("initialization-order-fiasco", "Initialization order problem")
155 .Case("stack-buffer-overflow", "Stack buffer overflow")
156 .Case("stack-use-after-return", "Use of stack memory after return")
157 .Case("use-after-poison", "Use of poisoned memory")
158 .Case("container-overflow", "Container overflow")
159 .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
160 .Case("global-buffer-overflow", "Global buffer overflow")
161 .Case("unknown-crash", "Invalid memory access")
162 .Case("stack-overflow", "Stack space exhausted")
163 .Case("null-deref", "Dereference of null pointer")
164 .Case("wild-jump", "Jump to non-executable address")
165 .Case("wild-addr-write", "Write through wild pointer")
166 .Case("wild-addr-read", "Read from wild pointer")
167 .Case("wild-addr", "Access through wild pointer")
168 .Case("signal", "Deadly signal")
169 .Case("double-free", "Deallocation of freed memory")
170 .Case("new-delete-type-mismatch",
171 "Deallocation size different from allocation size")
172 .Case("bad-free", "Deallocation of non-allocated memory")
173 .Case("alloc-dealloc-mismatch",
174 "Mismatch between allocation and deallocation APIs")
175 .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
176 .Case("bad-__sanitizer_get_allocated_size",
177 "Invalid argument to __sanitizer_get_allocated_size")
178 .Case("param-overlap",
179 "Call to function disallowing overlapping memory ranges")
180 .Case("negative-size-param", "Negative size used when accessing memory")
181 .Case("bad-__sanitizer_annotate_contiguous_container",
182 "Invalid argument to __sanitizer_annotate_contiguous_container")
183 .Case("odr-violation", "Symbol defined in multiple translation units")
185 "invalid-pointer-pair",
186 "Comparison or arithmetic on pointers from different memory regions")
187 // for unknown report codes just show the code
188 .Default("AddressSanitizer detected: " + description
);
191 bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp
,
192 StoppointCallbackContext
*context
,
194 user_id_t break_loc_id
) {
195 // Make sure this is the right process
196 if (!process_sp
|| process_sp
!= context
->exe_ctx_ref
.GetProcessSP())
199 if (process_sp
->GetModIDRef().IsLastResumeForUserExpression())
202 StructuredData::ObjectSP report
= RetrieveReportData(process_sp
);
203 if (!report
|| report
->GetType() != lldb::eStructuredDataTypeDictionary
)
206 std::string description
= FormatDescription(report
);
208 if (ThreadSP thread_sp
= context
->exe_ctx_ref
.GetThreadSP())
209 thread_sp
->SetStopInfo(
210 InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
211 *thread_sp
, description
, report
));
213 if (StreamFileSP stream_sp
= StreamFileSP(
214 process_sp
->GetTarget().GetDebugger().GetOutputStreamSP()))
215 stream_sp
->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
216 "info -s' to get extended information about the "
219 return true; // Return true to stop the target
222 Breakpoint
*ReportRetriever::SetupBreakpoint(ModuleSP module_sp
,
223 ProcessSP process_sp
,
224 ConstString symbol_name
) {
225 if (!module_sp
|| !process_sp
)
228 const Symbol
*symbol
=
229 module_sp
->FindFirstSymbolWithNameAndType(symbol_name
, eSymbolTypeCode
);
231 if (symbol
== nullptr)
234 if (!symbol
->ValueIsAddress() || !symbol
->GetAddressRef().IsValid())
237 const Address
&address
= symbol
->GetAddressRef();
238 const bool internal
= true;
239 const bool hardware
= false;
241 Breakpoint
*breakpoint
= process_sp
->GetTarget()
242 .CreateBreakpoint(address
, internal
, hardware
)