================ @@ -0,0 +1,201 @@ +//===-- AbortWithPayloadFrameRecognizer.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AbortWithPayloadFrameRecognizer.h" + +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StructuredData.h" + +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +using namespace lldb; +using namespace lldb_private; + +namespace lldb_private { +void RegisterAbortWithPayloadFrameRecognizer(Process *process) { + // There are two user-level API's that this recognizer captures, + // abort_with_reason and abort_with_payload. But they both call the private + // __abort_with_payload, the abort_with_reason call fills in a null payload. + static ConstString module_name("libsystem_kernel.dylib"); + static ConstString sym_name("__abort_with_payload"); + + if (!process) + return; + ConstString sym_arr[1] = {sym_name}; + + process->GetTarget().GetFrameRecognizerManager().AddRecognizer( + std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name, sym_arr, + /*first_instruction_only*/ false); +} + +RecognizedStackFrameSP +AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { + // We have two jobs: + // 1) to add the data passed to abort_with_payload to the + // ExtraCrashInformation dictionary. + // 2) To make up faux arguments for this frame. + static constexpr llvm::StringLiteral namespace_key("namespace"); + static constexpr llvm::StringLiteral code_key("code"); + static constexpr llvm::StringLiteral payload_addr_key("payload_addr"); + static constexpr llvm::StringLiteral payload_size_key("payload_size"); + static constexpr llvm::StringLiteral reason_key("reason"); + static constexpr llvm::StringLiteral flags_key("flags"); + static constexpr llvm::StringLiteral info_key("abort_with_payload"); + + // We are fetching the data from registers. + Thread *thread = frame_sp->GetThread().get(); + Process *process = thread->GetProcess().get(); + + // FIXME: Add logging for these errors + if (!thread) + return {}; + + TypeSystemClangSP scratch_ts_sp = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); + if (!scratch_ts_sp) + return {}; + + // The abort_with_payload signature is: + // abort_with_payload(uint32_t reason_namespace, uint64_t reason_code, + // void* payload, uint32_t payload_size, + // const char* reason_string, uint64_t reason_flags); + + ValueList arg_values; + Value input_value_32; + Value input_value_64; + Value input_value_void_ptr; + Value input_value_char_ptr; + + CompilerType clang_void_ptr_type = + scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType(); + CompilerType clang_char_ptr_type = + scratch_ts_sp->GetBasicType(eBasicTypeChar).GetPointerType(); + CompilerType clang_uint64_type = + scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, + 64); + CompilerType clang_uint32_type = + scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, + 32); + CompilerType clang_char_star_type = + scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, + 64); + + input_value_32.SetValueType(Value::ValueType::Scalar); + input_value_32.SetCompilerType(clang_uint32_type); + input_value_64.SetValueType(Value::ValueType::Scalar); + input_value_64.SetCompilerType(clang_uint64_type); + input_value_void_ptr.SetValueType(Value::ValueType::Scalar); + input_value_void_ptr.SetCompilerType(clang_void_ptr_type); + input_value_char_ptr.SetValueType(Value::ValueType::Scalar); + input_value_char_ptr.SetCompilerType(clang_char_ptr_type); + + arg_values.PushValue(input_value_32); + arg_values.PushValue(input_value_64); + arg_values.PushValue(input_value_void_ptr); + arg_values.PushValue(input_value_32); + arg_values.PushValue(input_value_char_ptr); + arg_values.PushValue(input_value_64); + + lldb::ABISP abi_sp = process->GetABI(); + bool success = abi_sp->GetArgumentValues(*thread, arg_values); + if (!success) + return {}; + + Value *cur_value; + StackFrame *frame = frame_sp.get(); + ValueObjectListSP arguments_sp = ValueObjectListSP(new ValueObjectList()); + + auto add_to_arguments = [&](llvm::StringRef name, Value *value, + bool dynamic) { + ValueObjectSP cur_valobj_sp = + ValueObjectConstResult::Create(frame, *value, ConstString(name)); + cur_valobj_sp = ValueObjectRecognizerSynthesizedValue::Create( + *cur_valobj_sp, eValueTypeVariableArgument); + ValueObjectSP dyn_valobj_sp; + if (dynamic) { + dyn_valobj_sp = cur_valobj_sp->GetDynamicValue(eDynamicDontRunTarget); + if (dyn_valobj_sp) + cur_valobj_sp = dyn_valobj_sp; + } + arguments_sp->Append(cur_valobj_sp); + }; + + // Decode the arg_values: + + uint32_t namespace_val = 0; + cur_value = arg_values.GetValueAtIndex(0); + add_to_arguments(namespace_key, cur_value, false); + namespace_val = cur_value->GetScalar().UInt(namespace_val); + + uint32_t code_val = 0; + cur_value = arg_values.GetValueAtIndex(1); + add_to_arguments(code_key, cur_value, false); + code_val = cur_value->GetScalar().UInt(code_val); + + lldb::addr_t payload_addr = LLDB_INVALID_ADDRESS; + cur_value = arg_values.GetValueAtIndex(2); + add_to_arguments(payload_addr_key, cur_value, true); + payload_addr = cur_value->GetScalar().ULongLong(payload_addr); + + uint32_t payload_size = 0; + cur_value = arg_values.GetValueAtIndex(3); + add_to_arguments(payload_size_key, cur_value, false); + payload_size = cur_value->GetScalar().UInt(payload_size); + + lldb::addr_t reason_addr = LLDB_INVALID_ADDRESS; + cur_value = arg_values.GetValueAtIndex(4); + add_to_arguments(reason_key, cur_value, false); + reason_addr = cur_value->GetScalar().ULongLong(payload_addr); + + // For the reason string, we want the string not the address, so fetch that. + std::string reason_string; + Status error; + size_t str_len = + process->ReadCStringFromMemory(reason_addr, reason_string, error); + if (error.Fail()) + return {}; + + uint32_t flags_val = 0; + cur_value = arg_values.GetValueAtIndex(5); + add_to_arguments(flags_key, cur_value, false); + flags_val = cur_value->GetScalar().UInt(flags_val); + + // Okay, we've gotten all the argument values, now put then in a + // StructuredData, and add that to the Process ExtraCrashInformation: + StructuredData::DictionarySP abort_dict_sp(new StructuredData::Dictionary()); + abort_dict_sp->AddIntegerItem(namespace_key, namespace_val); + abort_dict_sp->AddIntegerItem(code_key, code_val); + abort_dict_sp->AddIntegerItem(payload_addr_key, payload_addr); + abort_dict_sp->AddIntegerItem(payload_size_key, payload_size); + abort_dict_sp->AddStringItem(reason_key, reason_string); + abort_dict_sp->AddIntegerItem(flags_key, flags_val); + + // This will overwrite any information in the dictionary already. ---------------- medismailben wrote:
Is this comment accurate ? If we call `AddItem` it will only overwrite existing `abort_with_payload` item in the dictionary but not the other entries. https://github.com/llvm/llvm-project/pull/101365 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits