https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/101365
>From 5b2cf0ab7e382e41ff3dfe88e4d7e35ddc99afd5 Mon Sep 17 00:00:00 2001 From: Jim Ingham <jing...@apple.com> Date: Tue, 30 Jul 2024 09:32:24 -0700 Subject: [PATCH 1/3] Add a StackFrameRecognizer for the Darwin specific abort_with_payload API. --- lldb/include/lldb/Target/Process.h | 16 ++ .../Platform/MacOSX/PlatformDarwin.cpp | 45 ++-- .../AbortWithPayloadFrameRecognizer.cpp | 201 ++++++++++++++++++ .../MacOSX/AbortWithPayloadFrameRecognizer.h | 38 ++++ .../SystemRuntime/MacOSX/CMakeLists.txt | 1 + .../MacOSX/SystemRuntimeMacOSX.cpp | 6 +- lldb/source/Target/Process.cpp | 7 +- .../API/macosx/abort_with_payload/Makefile | 4 + .../TestAbortWithPayload.py | 146 +++++++++++++ .../test/API/macosx/abort_with_payload/main.c | 30 +++ 10 files changed, 478 insertions(+), 16 deletions(-) create mode 100644 lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp create mode 100644 lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h create mode 100644 lldb/test/API/macosx/abort_with_payload/Makefile create mode 100644 lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py create mode 100644 lldb/test/API/macosx/abort_with_payload/main.c diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index c8475db8ae160..ffff84bbd8a52 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2569,6 +2569,18 @@ void PruneThreadPlans(); /// A StructuredDataSP object which, if non-empty, will contain the /// information related to the process. virtual StructuredData::DictionarySP GetMetadata() { return nullptr; } + + /// Fetch extended crash information held by the process. This will never be + /// an empty shared pointer, it will always have a dict, though it may be + /// empty. + StructuredData::DictionarySP GetExtendedCrashInfoDict() { + return m_crash_info_dict_sp; + } + + void ResetExtendedCrashInfoDict() { + // StructuredData::Dictionary is add only, so we have to make a new one: + m_crash_info_dict_sp.reset(new StructuredData::Dictionary()); + } size_t AddImageToken(lldb::addr_t image_ptr); @@ -3185,6 +3197,10 @@ void PruneThreadPlans(); /// Per process source file cache. SourceManager::SourceFileCache m_source_file_cache; + + /// A repository for extra crash information, consulted in + /// GetExtendedCrashInformation. + StructuredData::DictionarySP m_crash_info_dict_sp; size_t RemoveBreakpointOpcodesFromBuffer(lldb::addr_t addr, size_t size, uint8_t *buf) const; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 6fb5bbfbe417b..398b44c293614 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -856,21 +856,38 @@ PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) { } llvm::Expected<StructuredData::DictionarySP> -PlatformDarwin::FetchExtendedCrashInformation(Process &process) { - StructuredData::DictionarySP extended_crash_info = - std::make_shared<StructuredData::Dictionary>(); - - StructuredData::ArraySP annotations = ExtractCrashInfoAnnotations(process); - if (annotations && annotations->GetSize()) - extended_crash_info->AddItem("Crash-Info Annotations", annotations); - - StructuredData::DictionarySP app_specific_info = - ExtractAppSpecificInfo(process); - if (app_specific_info && app_specific_info->GetSize()) - extended_crash_info->AddItem("Application Specific Information", - app_specific_info); +PlatformDarwin:: +FetchExtendedCrashInformation(Process &process) { + static constexpr llvm::StringLiteral crash_info_key("Crash-Info Annotations"); + static constexpr llvm::StringLiteral asi_info_key("Application Specific Information"); + + // We cache the information we find in the process extended info dict: + StructuredData::DictionarySP process_dict_sp + = process.GetExtendedCrashInfoDict(); + StructuredData::Array *annotations = nullptr; + StructuredData::ArraySP new_annotations_sp; + if (!process_dict_sp->GetValueForKeyAsArray(crash_info_key, annotations)) { + new_annotations_sp = ExtractCrashInfoAnnotations(process); + if (new_annotations_sp && new_annotations_sp->GetSize()) { + process_dict_sp->AddItem(crash_info_key, new_annotations_sp); + annotations = new_annotations_sp.get(); + } + } - return extended_crash_info->GetSize() ? extended_crash_info : nullptr; + StructuredData::Dictionary *app_specific_info; + StructuredData::DictionarySP new_app_specific_info_sp; + if (!process_dict_sp->GetValueForKeyAsDictionary(asi_info_key, app_specific_info)) + { + new_app_specific_info_sp = ExtractAppSpecificInfo(process); + if (new_app_specific_info_sp && new_app_specific_info_sp->GetSize()) { + process_dict_sp->AddItem(asi_info_key, new_app_specific_info_sp); + app_specific_info = new_app_specific_info_sp.get(); + } + } + + // Now get anything else that was in the process info dict, and add it to the + // return here: + return process_dict_sp->GetSize() ? process_dict_sp : nullptr; } StructuredData::ArraySP diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp new file mode 100644 index 0000000000000..7f2aecd148379 --- /dev/null +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp @@ -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. + // But we can only crash on abort_with_payload once, so that shouldn't matter. + process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp); + + return RecognizedStackFrameSP(new AbortWithPayloadRecognizedStackFrame(frame_sp, arguments_sp)); +} + +AbortWithPayloadRecognizedStackFrame::AbortWithPayloadRecognizedStackFrame( + lldb::StackFrameSP &frame_sp, ValueObjectListSP &args_sp) : + RecognizedStackFrame() { + m_arguments = args_sp; + m_stop_desc = "abort with payload or reason"; +} + +} // namespace lldb_private + diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h new file mode 100644 index 0000000000000..25053a4322e7d --- /dev/null +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h @@ -0,0 +1,38 @@ +//===-- AbortWithPayloadFrameRecognizer.h -----------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LLDB_MACOSX_ABORTWITHPAYLOADFRAMERECOGNIZER_H +#define LLDB_MACOSX_ABORTWITHPAYLOADFRAMERECOGNIZER_H + +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrameRecognizer.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include <tuple> + +namespace lldb_private { + +void RegisterAbortWithPayloadFrameRecognizer(Process *process); + +class AbortWithPayloadRecognizedStackFrame : public RecognizedStackFrame { +public: + AbortWithPayloadRecognizedStackFrame(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectListSP &args_sp); +}; + +class AbortWithPayloadFrameRecognizer: public StackFrameRecognizer { + public: + std::string GetName() override { + return "abort_with_payload StackFrame Recognizer"; } + lldb::RecognizedStackFrameSP + RecognizeFrame(lldb::StackFrameSP frame_sp) override; + +}; +} // namespace lldb_private + +#endif // LLDB_MACOSX_ABORTWITHPAYLOADFRAMERECOGNIZER_H diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt index 04d30652ba4b4..17fccdf43c828 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt @@ -4,6 +4,7 @@ add_lldb_library(lldbPluginSystemRuntimeMacOSX PLUGIN AppleGetQueuesHandler.cpp AppleGetThreadItemInfoHandler.cpp SystemRuntimeMacOSX.cpp + AbortWithPayloadFrameRecognizer.cpp LINK_LIBS lldbBreakpoint diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 34ce175920d1e..999b81b49e6e0 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -29,6 +29,7 @@ #include "lldb/Utility/StreamString.h" #include "SystemRuntimeMacOSX.h" +#include "AbortWithPayloadFrameRecognizer.h" #include <memory> @@ -90,7 +91,10 @@ SystemRuntimeMacOSX::SystemRuntimeMacOSX(Process *process) m_libpthread_offsets(), m_dispatch_tsd_indexes_addr(LLDB_INVALID_ADDRESS), m_libdispatch_tsd_indexes(), m_dispatch_voucher_offsets_addr(LLDB_INVALID_ADDRESS), - m_libdispatch_voucher_offsets() {} + m_libdispatch_voucher_offsets() { + + RegisterAbortWithPayloadFrameRecognizer(process); +} // Destructor SystemRuntimeMacOSX::~SystemRuntimeMacOSX() { Clear(true); } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index d5a639d9beacd..c72852d2afffa 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -477,7 +477,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), m_can_interpret_function_calls(false), m_run_thread_plan_lock(), - m_can_jit(eCanJITDontKnow) { + m_can_jit(eCanJITDontKnow), + m_crash_info_dict_sp(new StructuredData::Dictionary()) { CheckInWithManager(); Log *log = GetLog(LLDBLog::Object); @@ -3263,6 +3264,10 @@ Status Process::PrivateResume() { // If signals handing status changed we might want to update our signal // filters before resuming. UpdateAutomaticSignalFiltering(); + // Clear any crash info we accumulated for this stop, but don't do so if we + // are running functions; we don't want to wipe out the real stop's info. + if (!GetModID().IsLastResumeForUserExpression()) + ResetExtendedCrashInfoDict(); Status error(WillResume()); // Tell the process it is about to resume before the thread list diff --git a/lldb/test/API/macosx/abort_with_payload/Makefile b/lldb/test/API/macosx/abort_with_payload/Makefile new file mode 100644 index 0000000000000..695335e068c0c --- /dev/null +++ b/lldb/test/API/macosx/abort_with_payload/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py new file mode 100644 index 0000000000000..764f8441382a5 --- /dev/null +++ b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py @@ -0,0 +1,146 @@ +""" +Test that the FrameRecognizer for __abort_with_payload +works properly +""" + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestAbortWithPayload(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_abort_with_payload(self): + """There can be many tests in a test case - describe this test here.""" + self.build() + self.abort_with_test(True) + + def test_abort_with_reason(self): + """There can be many tests in a test case - describe this test here.""" + self.build() + self.abort_with_test(False) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + self.main_source_file = lldb.SBFileSpec("main.c") + + def abort_with_test(self, with_payload): + """If with_payload is True, we test the abort_with_payload call, + if false, we test abort_with_reason.""" + launch_info = lldb.SBLaunchInfo([]) + if not with_payload: + launch_info.SetArguments(["use_reason"], True) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Stop here before abort", self.main_source_file, + launch_info=launch_info + ) + + frame = thread.GetFrameAtIndex(0) + payload_str_var = frame.FindVariable("payload_string") + self.assertSuccess(payload_str_var.GetError(), "Got payload string var") + payload_var_addr = payload_str_var.unsigned + + payload_size_var = frame.FindVariable("payload_string_len") + self.assertSuccess(payload_size_var.GetError(), "Got payload string len var") + payload_size_val = payload_size_var.unsigned + + # Not let it run to crash: + process.Continue() + + # At this point we should have stopped at the internal function. + # Make sure we selected the right thread: + sel_thread = process.GetSelectedThread() + self.assertEqual(thread, sel_thread, "Selected the original thread") + # Make sure the stop reason is right: + self.assertEqual(thread.GetStopDescription(100), "abort with payload or reason", "Description was right") + frame_0 = thread.frames[0] + self.assertEqual(frame_0.name, "__abort_with_payload", "Frame 0 was right") + + # Now check the recognized argument values and the ExtendedCrashInformation version: + options = lldb.SBVariablesOptions() + options.SetIncludeRecognizedArguments(True) + options.SetIncludeArguments(False) + options.SetIncludeLocals(False) + options.SetIncludeStatics(False) + options.SetIncludeRuntimeSupportValues(False) + + arguments = frame_0.GetVariables(options) + + correct_values = { "namespace" : 5, + "code" : 100, + "payload_addr" : payload_var_addr, + "payload_size" : payload_size_val, + "payload_string" : '"This is a payload that happens to be a string"', + "reason_string" : '"This is the reason string"', + "reason_no_quote" : "This is the reason string", + "flags": 0x85 } + + # First check the recognized argument values: + self.assertEqual(len(arguments), 6, "Got all six values") + self.runCmd("frame variable") + self.assertEqual(arguments[0].name, "namespace") + self.assertEqual(arguments[0].unsigned, correct_values["namespace"], "Namespace value correct") + + self.assertEqual(arguments[1].name, "code") + self.assertEqual(arguments[1].unsigned, correct_values["code"], "code value correct") + + # FIXME: I'm always adding these recognized arguments, but that looks wrong. Should only + # add the payload ones if it is the payload not the reason function. + self.assertEqual(arguments[2].name, "payload_addr") + self.assertEqual(arguments[3].name, "payload_size") + if with_payload: + self.assertEqual(arguments[2].unsigned, correct_values["payload_addr"], "Payload matched variable address") + # We've made a payload that is a string, try to fetch that: + char_ptr_type = target.FindFirstType("char").GetPointerType() + self.assertTrue(char_ptr_type.IsValid(), "Got char ptr type") + + str_val = arguments[2].Cast(char_ptr_type) + self.assertEqual(str_val.summary, correct_values["payload_string"], "Got payload string") + + self.assertEqual(arguments[3].unsigned, correct_values["payload_size"], "payload size value correct") + else: + self.assertEqual(arguments[2].unsigned, 0, "Got 0 payload addr for reason call") + self.assertEqual(arguments[3].unsigned, 0, "Got 0 payload size for reason call") + + self.assertEqual(arguments[4].name, "reason") + self.assertEqual(arguments[4].summary, correct_values["reason_string"], "Reason value correct") + + self.assertEqual(arguments[5].name, "flags") + self.assertEqual(arguments[5].unsigned, correct_values["flags"], "Flags value correct") + + # Also check that the same info was stored in the ExtendedCrashInformation dict: + dict = process.GetExtendedCrashInformation() + self.assertTrue(dict.IsValid(), "Got extended crash information dict") + self.assertEqual(dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary") + + abort_dict = dict.GetValueForKey("abort_with_payload") + self.assertTrue(abort_dict.IsValid(), "Got an abort_with_payload dict") + self.assertEqual(abort_dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary") + + namespace_val = abort_dict.GetValueForKey("namespace") + self.assertTrue(namespace_val.IsValid(), "Got a valid namespace") + self.assertEqual(namespace_val.GetIntegerValue(0), correct_values["namespace"], "Namespace value correct") + + code_val = abort_dict.GetValueForKey("code") + self.assertTrue(code_val.IsValid(), "Got a valid code") + self.assertEqual(code_val.GetIntegerValue(0), correct_values["code"], "Code value correct") + + if with_payload: + addr_val = abort_dict.GetValueForKey("payload_addr") + self.assertTrue(addr_val.IsValid(), "Got a payload_addr") + self.assertEqual(addr_val.GetIntegerValue(0), correct_values["payload_addr"], "payload_addr right in dictionary") + + size_val = abort_dict.GetValueForKey("payload_size") + self.assertTrue(size_val.IsValid(), "Got a payload size value") + self.assertEqual(size_val.GetIntegerValue(0), correct_values["payload_size"], "payload size right in dictionary") + + reason_val = abort_dict.GetValueForKey("reason") + self.assertTrue(reason_val.IsValid(), "Got a reason key") + self.assertEqual(reason_val.GetStringValue(100), correct_values["reason_no_quote"], "reason right in dictionary") + + flags_val = abort_dict.GetValueForKey("flags") + self.assertTrue(flags_val.IsValid(), "Got a flags value") + self.assertEqual(flags_val.GetIntegerValue(0), correct_values["flags"], "flags right in dictionary") diff --git a/lldb/test/API/macosx/abort_with_payload/main.c b/lldb/test/API/macosx/abort_with_payload/main.c new file mode 100644 index 0000000000000..aabe21b9cbbdf --- /dev/null +++ b/lldb/test/API/macosx/abort_with_payload/main.c @@ -0,0 +1,30 @@ +// These defines are from bsd/sys/reason.h: +#include <stdint.h> +#include <string.h> + +extern void 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); + +extern void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char* reason_string, uint64_t reason_flags); + +#define OS_REASON_FLAG_FROM_USERSPACE 0x4 +#define OS_REASON_FLAG_NO_CRASH_REPORT 0x1 +#define OS_REASON_FLAG_ONE_TIME_FAILURE 0x80 + +#define MY_REASON_FLAGS OS_REASON_FLAG_FROM_USERSPACE|OS_REASON_FLAG_NO_CRASH_REPORT|OS_REASON_FLAG_ONE_TIME_FAILURE +#define OS_REASON_TEST 5 + +int +main(int argc, char **argv) +{ + const char *reason_string = "This is the reason string"; + const char *payload_string = "This is a payload that happens to be a string"; + size_t payload_string_len = strlen(payload_string) + 1; + if (argc == 1) // Stop here before abort + abort_with_payload(OS_REASON_TEST, 100, (void *) payload_string , payload_string_len, + reason_string, MY_REASON_FLAGS); + else + abort_with_reason(OS_REASON_TEST, 100, reason_string, MY_REASON_FLAGS); + + return 0; + +} >From 408882d0fec2f604418bf78dddb89962ffc27522 Mon Sep 17 00:00:00 2001 From: Jim Ingham <jing...@apple.com> Date: Wed, 31 Jul 2024 10:38:42 -0700 Subject: [PATCH 2/3] Mark the tests Darwin only. --- .../test/API/macosx/abort_with_payload/TestAbortWithPayload.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py index 764f8441382a5..b6bafc9e171ae 100644 --- a/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py +++ b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py @@ -5,6 +5,7 @@ import lldb +from lldbsuite.test.decorators import * import lldbsuite.test.lldbutil as lldbutil from lldbsuite.test.lldbtest import * @@ -12,11 +13,13 @@ class TestAbortWithPayload(TestBase): NO_DEBUG_INFO_TESTCASE = True + @skipUnlessDarwin def test_abort_with_payload(self): """There can be many tests in a test case - describe this test here.""" self.build() self.abort_with_test(True) + @skipUnlessDarwin def test_abort_with_reason(self): """There can be many tests in a test case - describe this test here.""" self.build() >From 9c5b9160a600d40e26830e8a9111f90ffc64052c Mon Sep 17 00:00:00 2001 From: Jim Ingham <jing...@apple.com> Date: Wed, 31 Jul 2024 10:41:24 -0700 Subject: [PATCH 3/3] formatting --- lldb/include/lldb/Target/Process.h | 10 +- .../Platform/MacOSX/PlatformDarwin.cpp | 18 +-- .../AbortWithPayloadFrameRecognizer.cpp | 70 ++++----- .../MacOSX/AbortWithPayloadFrameRecognizer.h | 14 +- .../MacOSX/SystemRuntimeMacOSX.cpp | 4 +- lldb/source/Target/Process.cpp | 2 +- .../TestAbortWithPayload.py | 134 +++++++++++++----- .../test/API/macosx/abort_with_payload/main.c | 33 +++-- 8 files changed, 175 insertions(+), 110 deletions(-) diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index ffff84bbd8a52..e1be76d494b1f 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2569,14 +2569,14 @@ void PruneThreadPlans(); /// A StructuredDataSP object which, if non-empty, will contain the /// information related to the process. virtual StructuredData::DictionarySP GetMetadata() { return nullptr; } - + /// Fetch extended crash information held by the process. This will never be /// an empty shared pointer, it will always have a dict, though it may be /// empty. StructuredData::DictionarySP GetExtendedCrashInfoDict() { - return m_crash_info_dict_sp; + return m_crash_info_dict_sp; } - + void ResetExtendedCrashInfoDict() { // StructuredData::Dictionary is add only, so we have to make a new one: m_crash_info_dict_sp.reset(new StructuredData::Dictionary()); @@ -3197,8 +3197,8 @@ void PruneThreadPlans(); /// Per process source file cache. SourceManager::SourceFileCache m_source_file_cache; - - /// A repository for extra crash information, consulted in + + /// A repository for extra crash information, consulted in /// GetExtendedCrashInformation. StructuredData::DictionarySP m_crash_info_dict_sp; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 398b44c293614..3d22e7122d472 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -856,15 +856,15 @@ PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) { } llvm::Expected<StructuredData::DictionarySP> -PlatformDarwin:: -FetchExtendedCrashInformation(Process &process) { +PlatformDarwin::FetchExtendedCrashInformation(Process &process) { static constexpr llvm::StringLiteral crash_info_key("Crash-Info Annotations"); - static constexpr llvm::StringLiteral asi_info_key("Application Specific Information"); + static constexpr llvm::StringLiteral asi_info_key( + "Application Specific Information"); // We cache the information we find in the process extended info dict: - StructuredData::DictionarySP process_dict_sp - = process.GetExtendedCrashInfoDict(); - StructuredData::Array *annotations = nullptr; + StructuredData::DictionarySP process_dict_sp = + process.GetExtendedCrashInfoDict(); + StructuredData::Array *annotations = nullptr; StructuredData::ArraySP new_annotations_sp; if (!process_dict_sp->GetValueForKeyAsArray(crash_info_key, annotations)) { new_annotations_sp = ExtractCrashInfoAnnotations(process); @@ -876,15 +876,15 @@ FetchExtendedCrashInformation(Process &process) { StructuredData::Dictionary *app_specific_info; StructuredData::DictionarySP new_app_specific_info_sp; - if (!process_dict_sp->GetValueForKeyAsDictionary(asi_info_key, app_specific_info)) - { + if (!process_dict_sp->GetValueForKeyAsDictionary(asi_info_key, + app_specific_info)) { new_app_specific_info_sp = ExtractAppSpecificInfo(process); if (new_app_specific_info_sp && new_app_specific_info_sp->GetSize()) { process_dict_sp->AddItem(asi_info_key, new_app_specific_info_sp); app_specific_info = new_app_specific_info_sp.get(); } } - + // Now get anything else that was in the process info dict, and add it to the // return here: return process_dict_sp->GetSize() ? process_dict_sp : nullptr; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp index 7f2aecd148379..5434601f54401 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp @@ -1,4 +1,4 @@ - //===-- AbortWithPayloadFrameRecognizer.cpp -------------------------------===// +//===-- 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. @@ -26,26 +26,25 @@ using namespace lldb_private; namespace lldb_private { void RegisterAbortWithPayloadFrameRecognizer(Process *process) { - // There are two user-level API's that this recognizer captures, + // 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}; - + ConstString sym_arr[1] = {sym_name}; + process->GetTarget().GetFrameRecognizerManager().AddRecognizer( - std::make_shared<AbortWithPayloadFrameRecognizer>(), - module_name, sym_arr, - /*first_instruction_only*/ false); + 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 + // 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"); @@ -55,7 +54,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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(); @@ -69,10 +68,10 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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); + // 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; @@ -93,7 +92,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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); @@ -102,7 +101,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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); @@ -119,10 +118,10 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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)); + 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; @@ -133,19 +132,19 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_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); @@ -155,16 +154,17 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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); + size_t str_len = + process->ReadCStringFromMemory(reason_addr, reason_string, error); if (error.Fail()) return {}; @@ -183,19 +183,19 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 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. + // This will overwrite any information in the dictionary already. // But we can only crash on abort_with_payload once, so that shouldn't matter. process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp); - - return RecognizedStackFrameSP(new AbortWithPayloadRecognizedStackFrame(frame_sp, arguments_sp)); + + return RecognizedStackFrameSP( + new AbortWithPayloadRecognizedStackFrame(frame_sp, arguments_sp)); } AbortWithPayloadRecognizedStackFrame::AbortWithPayloadRecognizedStackFrame( - lldb::StackFrameSP &frame_sp, ValueObjectListSP &args_sp) : - RecognizedStackFrame() { - m_arguments = args_sp; - m_stop_desc = "abort with payload or reason"; + lldb::StackFrameSP &frame_sp, ValueObjectListSP &args_sp) + : RecognizedStackFrame() { + m_arguments = args_sp; + m_stop_desc = "abort with payload or reason"; } } // namespace lldb_private - diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h index 25053a4322e7d..6f3538647aadf 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.h @@ -21,17 +21,17 @@ void RegisterAbortWithPayloadFrameRecognizer(Process *process); class AbortWithPayloadRecognizedStackFrame : public RecognizedStackFrame { public: - AbortWithPayloadRecognizedStackFrame(lldb::StackFrameSP &frame_sp, + AbortWithPayloadRecognizedStackFrame(lldb::StackFrameSP &frame_sp, lldb::ValueObjectListSP &args_sp); }; -class AbortWithPayloadFrameRecognizer: public StackFrameRecognizer { - public: - std::string GetName() override { - return "abort_with_payload StackFrame Recognizer"; } +class AbortWithPayloadFrameRecognizer : public StackFrameRecognizer { +public: + std::string GetName() override { + return "abort_with_payload StackFrame Recognizer"; + } lldb::RecognizedStackFrameSP - RecognizeFrame(lldb::StackFrameSP frame_sp) override; - + RecognizeFrame(lldb::StackFrameSP frame_sp) override; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 999b81b49e6e0..0556b87777884 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -28,8 +28,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" -#include "SystemRuntimeMacOSX.h" #include "AbortWithPayloadFrameRecognizer.h" +#include "SystemRuntimeMacOSX.h" #include <memory> @@ -92,7 +92,7 @@ SystemRuntimeMacOSX::SystemRuntimeMacOSX(Process *process) m_libdispatch_tsd_indexes(), m_dispatch_voucher_offsets_addr(LLDB_INVALID_ADDRESS), m_libdispatch_voucher_offsets() { - + RegisterAbortWithPayloadFrameRecognizer(process); } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index c72852d2afffa..728f9aadef779 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -477,7 +477,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), m_can_interpret_function_calls(false), m_run_thread_plan_lock(), - m_can_jit(eCanJITDontKnow), + m_can_jit(eCanJITDontKnow), m_crash_info_dict_sp(new StructuredData::Dictionary()) { CheckInWithManager(); diff --git a/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py index b6bafc9e171ae..5934e23237053 100644 --- a/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py +++ b/lldb/test/API/macosx/abort_with_payload/TestAbortWithPayload.py @@ -32,33 +32,39 @@ def setUp(self): def abort_with_test(self, with_payload): """If with_payload is True, we test the abort_with_payload call, - if false, we test abort_with_reason.""" + if false, we test abort_with_reason.""" launch_info = lldb.SBLaunchInfo([]) if not with_payload: launch_info.SetArguments(["use_reason"], True) (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( - self, "Stop here before abort", self.main_source_file, - launch_info=launch_info + self, + "Stop here before abort", + self.main_source_file, + launch_info=launch_info, ) frame = thread.GetFrameAtIndex(0) payload_str_var = frame.FindVariable("payload_string") self.assertSuccess(payload_str_var.GetError(), "Got payload string var") payload_var_addr = payload_str_var.unsigned - + payload_size_var = frame.FindVariable("payload_string_len") self.assertSuccess(payload_size_var.GetError(), "Got payload string len var") payload_size_val = payload_size_var.unsigned # Not let it run to crash: process.Continue() - + # At this point we should have stopped at the internal function. # Make sure we selected the right thread: sel_thread = process.GetSelectedThread() self.assertEqual(thread, sel_thread, "Selected the original thread") # Make sure the stop reason is right: - self.assertEqual(thread.GetStopDescription(100), "abort with payload or reason", "Description was right") + self.assertEqual( + thread.GetStopDescription(100), + "abort with payload or reason", + "Description was right", + ) frame_0 = thread.frames[0] self.assertEqual(frame_0.name, "__abort_with_payload", "Frame 0 was right") @@ -72,78 +78,134 @@ def abort_with_test(self, with_payload): arguments = frame_0.GetVariables(options) - correct_values = { "namespace" : 5, - "code" : 100, - "payload_addr" : payload_var_addr, - "payload_size" : payload_size_val, - "payload_string" : '"This is a payload that happens to be a string"', - "reason_string" : '"This is the reason string"', - "reason_no_quote" : "This is the reason string", - "flags": 0x85 } - - # First check the recognized argument values: + correct_values = { + "namespace": 5, + "code": 100, + "payload_addr": payload_var_addr, + "payload_size": payload_size_val, + "payload_string": '"This is a payload that happens to be a string"', + "reason_string": '"This is the reason string"', + "reason_no_quote": "This is the reason string", + "flags": 0x85, + } + + # First check the recognized argument values: self.assertEqual(len(arguments), 6, "Got all six values") self.runCmd("frame variable") self.assertEqual(arguments[0].name, "namespace") - self.assertEqual(arguments[0].unsigned, correct_values["namespace"], "Namespace value correct") + self.assertEqual( + arguments[0].unsigned, + correct_values["namespace"], + "Namespace value correct", + ) self.assertEqual(arguments[1].name, "code") - self.assertEqual(arguments[1].unsigned, correct_values["code"], "code value correct") + self.assertEqual( + arguments[1].unsigned, correct_values["code"], "code value correct" + ) # FIXME: I'm always adding these recognized arguments, but that looks wrong. Should only # add the payload ones if it is the payload not the reason function. self.assertEqual(arguments[2].name, "payload_addr") self.assertEqual(arguments[3].name, "payload_size") if with_payload: - self.assertEqual(arguments[2].unsigned, correct_values["payload_addr"], "Payload matched variable address") + self.assertEqual( + arguments[2].unsigned, + correct_values["payload_addr"], + "Payload matched variable address", + ) # We've made a payload that is a string, try to fetch that: char_ptr_type = target.FindFirstType("char").GetPointerType() self.assertTrue(char_ptr_type.IsValid(), "Got char ptr type") - + str_val = arguments[2].Cast(char_ptr_type) - self.assertEqual(str_val.summary, correct_values["payload_string"], "Got payload string") - - self.assertEqual(arguments[3].unsigned, correct_values["payload_size"], "payload size value correct") + self.assertEqual( + str_val.summary, correct_values["payload_string"], "Got payload string" + ) + + self.assertEqual( + arguments[3].unsigned, + correct_values["payload_size"], + "payload size value correct", + ) else: - self.assertEqual(arguments[2].unsigned, 0, "Got 0 payload addr for reason call") - self.assertEqual(arguments[3].unsigned, 0, "Got 0 payload size for reason call") - + self.assertEqual( + arguments[2].unsigned, 0, "Got 0 payload addr for reason call" + ) + self.assertEqual( + arguments[3].unsigned, 0, "Got 0 payload size for reason call" + ) + self.assertEqual(arguments[4].name, "reason") - self.assertEqual(arguments[4].summary, correct_values["reason_string"], "Reason value correct") + self.assertEqual( + arguments[4].summary, + correct_values["reason_string"], + "Reason value correct", + ) self.assertEqual(arguments[5].name, "flags") - self.assertEqual(arguments[5].unsigned, correct_values["flags"], "Flags value correct") + self.assertEqual( + arguments[5].unsigned, correct_values["flags"], "Flags value correct" + ) # Also check that the same info was stored in the ExtendedCrashInformation dict: dict = process.GetExtendedCrashInformation() self.assertTrue(dict.IsValid(), "Got extended crash information dict") - self.assertEqual(dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary") + self.assertEqual( + dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary" + ) abort_dict = dict.GetValueForKey("abort_with_payload") self.assertTrue(abort_dict.IsValid(), "Got an abort_with_payload dict") - self.assertEqual(abort_dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary") + self.assertEqual( + abort_dict.GetType(), + lldb.eStructuredDataTypeDictionary, + "It is a dictionary", + ) namespace_val = abort_dict.GetValueForKey("namespace") self.assertTrue(namespace_val.IsValid(), "Got a valid namespace") - self.assertEqual(namespace_val.GetIntegerValue(0), correct_values["namespace"], "Namespace value correct") + self.assertEqual( + namespace_val.GetIntegerValue(0), + correct_values["namespace"], + "Namespace value correct", + ) code_val = abort_dict.GetValueForKey("code") self.assertTrue(code_val.IsValid(), "Got a valid code") - self.assertEqual(code_val.GetIntegerValue(0), correct_values["code"], "Code value correct") + self.assertEqual( + code_val.GetIntegerValue(0), correct_values["code"], "Code value correct" + ) if with_payload: addr_val = abort_dict.GetValueForKey("payload_addr") self.assertTrue(addr_val.IsValid(), "Got a payload_addr") - self.assertEqual(addr_val.GetIntegerValue(0), correct_values["payload_addr"], "payload_addr right in dictionary") + self.assertEqual( + addr_val.GetIntegerValue(0), + correct_values["payload_addr"], + "payload_addr right in dictionary", + ) size_val = abort_dict.GetValueForKey("payload_size") self.assertTrue(size_val.IsValid(), "Got a payload size value") - self.assertEqual(size_val.GetIntegerValue(0), correct_values["payload_size"], "payload size right in dictionary") + self.assertEqual( + size_val.GetIntegerValue(0), + correct_values["payload_size"], + "payload size right in dictionary", + ) reason_val = abort_dict.GetValueForKey("reason") self.assertTrue(reason_val.IsValid(), "Got a reason key") - self.assertEqual(reason_val.GetStringValue(100), correct_values["reason_no_quote"], "reason right in dictionary") + self.assertEqual( + reason_val.GetStringValue(100), + correct_values["reason_no_quote"], + "reason right in dictionary", + ) flags_val = abort_dict.GetValueForKey("flags") self.assertTrue(flags_val.IsValid(), "Got a flags value") - self.assertEqual(flags_val.GetIntegerValue(0), correct_values["flags"], "flags right in dictionary") + self.assertEqual( + flags_val.GetIntegerValue(0), + correct_values["flags"], + "flags right in dictionary", + ) diff --git a/lldb/test/API/macosx/abort_with_payload/main.c b/lldb/test/API/macosx/abort_with_payload/main.c index aabe21b9cbbdf..a10a6cf65fe69 100644 --- a/lldb/test/API/macosx/abort_with_payload/main.c +++ b/lldb/test/API/macosx/abort_with_payload/main.c @@ -2,29 +2,32 @@ #include <stdint.h> #include <string.h> -extern void 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); +extern void 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); -extern void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char* reason_string, uint64_t reason_flags); +extern void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, + const char *reason_string, uint64_t reason_flags); -#define OS_REASON_FLAG_FROM_USERSPACE 0x4 -#define OS_REASON_FLAG_NO_CRASH_REPORT 0x1 -#define OS_REASON_FLAG_ONE_TIME_FAILURE 0x80 +#define OS_REASON_FLAG_FROM_USERSPACE 0x4 +#define OS_REASON_FLAG_NO_CRASH_REPORT 0x1 +#define OS_REASON_FLAG_ONE_TIME_FAILURE 0x80 -#define MY_REASON_FLAGS OS_REASON_FLAG_FROM_USERSPACE|OS_REASON_FLAG_NO_CRASH_REPORT|OS_REASON_FLAG_ONE_TIME_FAILURE -#define OS_REASON_TEST 5 +#define MY_REASON_FLAGS \ + OS_REASON_FLAG_FROM_USERSPACE | OS_REASON_FLAG_NO_CRASH_REPORT | \ + OS_REASON_FLAG_ONE_TIME_FAILURE +#define OS_REASON_TEST 5 -int -main(int argc, char **argv) -{ +int main(int argc, char **argv) { const char *reason_string = "This is the reason string"; - const char *payload_string = "This is a payload that happens to be a string"; + const char *payload_string = "This is a payload that happens to be a string"; size_t payload_string_len = strlen(payload_string) + 1; if (argc == 1) // Stop here before abort - abort_with_payload(OS_REASON_TEST, 100, (void *) payload_string , payload_string_len, - reason_string, MY_REASON_FLAGS); - else + abort_with_payload(OS_REASON_TEST, 100, (void *)payload_string, + payload_string_len, reason_string, MY_REASON_FLAGS); + else abort_with_reason(OS_REASON_TEST, 100, reason_string, MY_REASON_FLAGS); return 0; - } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits