LLDB mainline
AbortWithPayloadFrameRecognizer.cpp
Go to the documentation of this file.
1//===-- AbortWithPayloadFrameRecognizer.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
11#include "lldb/Core/Value.h"
13#include "lldb/Target/ABI.h"
14#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
17#include "lldb/Target/Thread.h"
19#include "lldb/Utility/Log.h"
21
23
24using namespace lldb;
25using namespace lldb_private;
26
27namespace lldb_private {
29 // There are two user-level API's that this recognizer captures,
30 // abort_with_reason and abort_with_payload. But they both call the private
31 // __abort_with_payload, the abort_with_reason call fills in a null payload.
32 static ConstString module_name("libsystem_kernel.dylib");
33 static ConstString sym_name("__abort_with_payload");
34
35 if (!process)
36 return;
37
39 std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name,
40 sym_name, /*first_instruction_only*/ false);
41}
42
45 // We have two jobs:
46 // 1) to add the data passed to abort_with_payload to the
47 // ExtraCrashInformation dictionary.
48 // 2) To make up faux arguments for this frame.
49 static constexpr llvm::StringLiteral namespace_key("namespace");
50 static constexpr llvm::StringLiteral code_key("code");
51 static constexpr llvm::StringLiteral payload_addr_key("payload_addr");
52 static constexpr llvm::StringLiteral payload_size_key("payload_size");
53 static constexpr llvm::StringLiteral reason_key("reason");
54 static constexpr llvm::StringLiteral flags_key("flags");
55 static constexpr llvm::StringLiteral info_key("abort_with_payload");
56
58
59 if (!frame_sp) {
60 LLDB_LOG(log, "abort_with_payload recognizer: invalid frame.");
61 return {};
62 }
63
64 Thread *thread = frame_sp->GetThread().get();
65 if (!thread) {
66 LLDB_LOG(log, "abort_with_payload recognizer: invalid thread.");
67 return {};
68 }
69
70 Process *process = thread->GetProcess().get();
71 if (!thread) {
72 LLDB_LOG(log, "abort_with_payload recognizer: invalid process.");
73 }
74
75 TypeSystemClangSP scratch_ts_sp =
77 if (!scratch_ts_sp) {
78 LLDB_LOG(log, "abort_with_payload recognizer: invalid scratch typesystem.");
79 return {};
80 }
81
82 // The abort_with_payload signature is:
83 // abort_with_payload(uint32_t reason_namespace, uint64_t reason_code,
84 // void* payload, uint32_t payload_size,
85 // const char* reason_string, uint64_t reason_flags);
86
87 ValueList arg_values;
88 Value input_value_32;
89 Value input_value_64;
90 Value input_value_void_ptr;
91 Value input_value_char_ptr;
92
93 CompilerType clang_void_ptr_type =
94 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
95 CompilerType clang_char_ptr_type =
96 scratch_ts_sp->GetBasicType(eBasicTypeChar).GetPointerType();
97 CompilerType clang_uint64_type =
98 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
99 64);
100 CompilerType clang_uint32_type =
101 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
102 32);
103 CompilerType clang_char_star_type =
104 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
105 64);
106
108 input_value_32.SetCompilerType(clang_uint32_type);
110 input_value_64.SetCompilerType(clang_uint64_type);
111 input_value_void_ptr.SetValueType(Value::ValueType::Scalar);
112 input_value_void_ptr.SetCompilerType(clang_void_ptr_type);
113 input_value_char_ptr.SetValueType(Value::ValueType::Scalar);
114 input_value_char_ptr.SetCompilerType(clang_char_ptr_type);
115
116 arg_values.PushValue(input_value_32);
117 arg_values.PushValue(input_value_64);
118 arg_values.PushValue(input_value_void_ptr);
119 arg_values.PushValue(input_value_32);
120 arg_values.PushValue(input_value_char_ptr);
121 arg_values.PushValue(input_value_64);
122
123 lldb::ABISP abi_sp = process->GetABI();
124 bool success = abi_sp->GetArgumentValues(*thread, arg_values);
125 if (!success)
126 return {};
127
128 Value *cur_value;
129 StackFrame *frame = frame_sp.get();
131
132 auto add_to_arguments = [&](llvm::StringRef name, Value *value,
133 bool dynamic) {
134 ValueObjectSP cur_valobj_sp =
135 ValueObjectConstResult::Create(frame, *value, ConstString(name));
137 *cur_valobj_sp, eValueTypeVariableArgument);
138 ValueObjectSP dyn_valobj_sp;
139 if (dynamic) {
140 dyn_valobj_sp = cur_valobj_sp->GetDynamicValue(eDynamicDontRunTarget);
141 if (dyn_valobj_sp)
142 cur_valobj_sp = dyn_valobj_sp;
143 }
144 arguments_sp->Append(cur_valobj_sp);
145 };
146
147 // Decode the arg_values:
148
149 uint32_t namespace_val = 0;
150 cur_value = arg_values.GetValueAtIndex(0);
151 add_to_arguments(namespace_key, cur_value, false);
152 namespace_val = cur_value->GetScalar().UInt(namespace_val);
153
154 uint32_t code_val = 0;
155 cur_value = arg_values.GetValueAtIndex(1);
156 add_to_arguments(code_key, cur_value, false);
157 code_val = cur_value->GetScalar().UInt(code_val);
158
159 lldb::addr_t payload_addr = LLDB_INVALID_ADDRESS;
160 cur_value = arg_values.GetValueAtIndex(2);
161 add_to_arguments(payload_addr_key, cur_value, true);
162 payload_addr = cur_value->GetScalar().ULongLong(payload_addr);
163
164 uint32_t payload_size = 0;
165 cur_value = arg_values.GetValueAtIndex(3);
166 add_to_arguments(payload_size_key, cur_value, false);
167 payload_size = cur_value->GetScalar().UInt(payload_size);
168
170 cur_value = arg_values.GetValueAtIndex(4);
171 add_to_arguments(reason_key, cur_value, false);
172 reason_addr = cur_value->GetScalar().ULongLong(payload_addr);
173
174 // For the reason string, we want the string not the address, so fetch that.
175 std::string reason_string;
177 process->ReadCStringFromMemory(reason_addr, reason_string, error);
178 if (error.Fail()) {
179 // Even if we couldn't read the string, return the other data.
180 LLDB_LOG(log, "Couldn't fetch reason string: {0}.", error);
181 reason_string = "<error fetching reason string>";
182 }
183
184 uint32_t flags_val = 0;
185 cur_value = arg_values.GetValueAtIndex(5);
186 add_to_arguments(flags_key, cur_value, false);
187 flags_val = cur_value->GetScalar().UInt(flags_val);
188
189 // Okay, we've gotten all the argument values, now put them in a
190 // StructuredData, and add that to the Process ExtraCrashInformation:
192 abort_dict_sp->AddIntegerItem(namespace_key, namespace_val);
193 abort_dict_sp->AddIntegerItem(code_key, code_val);
194 abort_dict_sp->AddIntegerItem(payload_addr_key, payload_addr);
195 abort_dict_sp->AddIntegerItem(payload_size_key, payload_size);
196 abort_dict_sp->AddStringItem(reason_key, reason_string);
197 abort_dict_sp->AddIntegerItem(flags_key, flags_val);
198
199 // This will overwrite the abort_with_payload information in the dictionary
200 // already. But we can only crash on abort_with_payload once, so that
201 // shouldn't matter.
202 process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp);
203
205 new AbortWithPayloadRecognizedStackFrame(frame_sp, arguments_sp));
206}
207
209 lldb::StackFrameSP &frame_sp, ValueObjectListSP &args_sp)
211 m_arguments = args_sp;
212 m_stop_desc = "abort with payload or reason";
213}
214
215} // namespace lldb_private
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:359
lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame_sp) override
AbortWithPayloadRecognizedStackFrame(lldb::StackFrameSP &frame_sp, lldb::ValueObjectListSP &args_sp)
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
CompilerType GetPointerType() const
Return a new CompilerType that is a pointer to this type.
A uniqued constant string class.
Definition: ConstString.h:40
A plug-in interface definition class for debugging a process.
Definition: Process.h:341
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr, size_t cstr_max_len, Status &error)
Read a NULL terminated C string from memory.
Definition: Process.cpp:2162
StructuredData::DictionarySP GetExtendedCrashInfoDict()
Fetch extended crash information held by the process.
Definition: Process.h:2588
const lldb::ABISP & GetABI()
Definition: Process.cpp:1531
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1285
This class provides extra information about a stack frame that was provided by a specific stack frame...
unsigned int UInt(unsigned int fail_value=0) const
Definition: Scalar.cpp:321
unsigned long long ULongLong(unsigned long long fail_value=0) const
Definition: Scalar.cpp:335
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef< ConstString > symbols, bool first_instruction_only=true)
This base class provides an interface to stack frames.
Definition: StackFrame.h:43
An error handling class.
Definition: Status.h:44
std::shared_ptr< Dictionary > DictionarySP
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition: Target.h:1473
lldb::ProcessSP GetProcess() const
Definition: Thread.h:157
void PushValue(const Value &value)
Definition: Value.cpp:682
Value * GetValueAtIndex(size_t idx)
Definition: Value.cpp:686
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address=LLDB_INVALID_ADDRESS)
A collection of ValueObject values that.
static lldb::ValueObjectSP Create(ValueObject &parent, lldb::ValueType type)
const Scalar & GetScalar() const
Definition: Value.h:112
@ Scalar
A raw scalar value.
void SetCompilerType(const CompilerType &compiler_type)
Definition: Value.cpp:268
void SetValueType(ValueType value_type)
Definition: Value.h:89
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:331
void RegisterAbortWithPayloadFrameRecognizer(Process *process)
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::ABI > ABISP
Definition: lldb-forward.h:315
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:420
std::shared_ptr< lldb_private::RecognizedStackFrame > RecognizedStackFrameSP
Definition: lldb-forward.h:401
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:480
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
Definition: lldb-forward.h:484
@ eEncodingUint
unsigned integer
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
Definition: lldb-forward.h:466
uint64_t addr_t
Definition: lldb-types.h:80
@ eDynamicDontRunTarget
@ eValueTypeVariableArgument
function argument variables