brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · aaa4ccd Raw
217 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "AbortWithPayloadFrameRecognizer.h"10 11#include "lldb/Core/Value.h"12#include "lldb/Target/ABI.h"13#include "lldb/Target/Process.h"14#include "lldb/Target/StackFrame.h"15#include "lldb/Target/Target.h"16#include "lldb/Target/Thread.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19#include "lldb/Utility/StructuredData.h"20#include "lldb/ValueObject/ValueObjectConstResult.h"21 22#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"23 24using namespace lldb;25using namespace lldb_private;26 27namespace lldb_private {28void RegisterAbortWithPayloadFrameRecognizer(Process *process) {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 private31  // __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 38  process->GetTarget().GetFrameRecognizerManager().AddRecognizer(39      std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name,40      sym_name, Mangled::NamePreference::ePreferDemangled,41      /*first_instruction_only*/ false);42}43 44RecognizedStackFrameSP45AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {46  // We have two jobs:47  // 1) to add the data passed to abort_with_payload to the48  //    ExtraCrashInformation dictionary.49  // 2) To make up faux arguments for this frame.50  static constexpr llvm::StringLiteral namespace_key("namespace");51  static constexpr llvm::StringLiteral code_key("code");52  static constexpr llvm::StringLiteral payload_addr_key("payload_addr");53  static constexpr llvm::StringLiteral payload_size_key("payload_size");54  static constexpr llvm::StringLiteral reason_key("reason");55  static constexpr llvm::StringLiteral flags_key("flags");56  static constexpr llvm::StringLiteral info_key("abort_with_payload");57 58  Log *log = GetLog(LLDBLog::SystemRuntime);59  60  if (!frame_sp) {61    LLDB_LOG(log, "abort_with_payload recognizer: invalid frame.");62    return {};63  }64 65  Thread *thread = frame_sp->GetThread().get();66  if (!thread) {67    LLDB_LOG(log, "abort_with_payload recognizer: invalid thread.");68    return {};69  }70 71  Process *process = thread->GetProcess().get();72  if (!thread) {73    LLDB_LOG(log, "abort_with_payload recognizer: invalid process.");74  }75 76  TypeSystemClangSP scratch_ts_sp =77      ScratchTypeSystemClang::GetForTarget(process->GetTarget());78  if (!scratch_ts_sp) {79    LLDB_LOG(log, "abort_with_payload recognizer: invalid scratch typesystem.");80    return {};81  }82 83  // The abort_with_payload signature is:84  // abort_with_payload(uint32_t reason_namespace, uint64_t reason_code,85  //                      void* payload, uint32_t payload_size,86  //                      const char* reason_string, uint64_t reason_flags);87 88  ValueList arg_values;89  Value input_value_32;90  Value input_value_64;91  Value input_value_void_ptr;92  Value input_value_char_ptr;93 94  CompilerType clang_void_ptr_type =95      scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();96  CompilerType clang_char_ptr_type =97      scratch_ts_sp->GetBasicType(eBasicTypeChar).GetPointerType();98  CompilerType clang_uint64_type =99      scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,100                                                         64);101  CompilerType clang_uint32_type =102      scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,103                                                         32);104  CompilerType clang_char_star_type =105      scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,106                                                         64);107 108  input_value_32.SetValueType(Value::ValueType::Scalar);109  input_value_32.SetCompilerType(clang_uint32_type);110  input_value_64.SetValueType(Value::ValueType::Scalar);111  input_value_64.SetCompilerType(clang_uint64_type);112  input_value_void_ptr.SetValueType(Value::ValueType::Scalar);113  input_value_void_ptr.SetCompilerType(clang_void_ptr_type);114  input_value_char_ptr.SetValueType(Value::ValueType::Scalar);115  input_value_char_ptr.SetCompilerType(clang_char_ptr_type);116 117  arg_values.PushValue(input_value_32);118  arg_values.PushValue(input_value_64);119  arg_values.PushValue(input_value_void_ptr);120  arg_values.PushValue(input_value_32);121  arg_values.PushValue(input_value_char_ptr);122  arg_values.PushValue(input_value_64);123 124  lldb::ABISP abi_sp = process->GetABI();125  bool success = abi_sp->GetArgumentValues(*thread, arg_values);126  if (!success)127    return {};128 129  Value *cur_value;130  StackFrame *frame = frame_sp.get();131  ValueObjectListSP arguments_sp = std::make_shared<ValueObjectList>();132 133  auto add_to_arguments = [&](llvm::StringRef name, Value *value,134                              bool dynamic) {135    ValueObjectSP cur_valobj_sp =136        ValueObjectConstResult::Create(frame, *value, ConstString(name));137    cur_valobj_sp = ValueObjectRecognizerSynthesizedValue::Create(138        *cur_valobj_sp, eValueTypeVariableArgument);139    ValueObjectSP dyn_valobj_sp;140    if (dynamic) {141      dyn_valobj_sp = cur_valobj_sp->GetDynamicValue(eDynamicDontRunTarget);142      if (dyn_valobj_sp)143        cur_valobj_sp = dyn_valobj_sp;144    }145    arguments_sp->Append(cur_valobj_sp);146  };147 148  // Decode the arg_values:149 150  uint32_t namespace_val = 0;151  cur_value = arg_values.GetValueAtIndex(0);152  add_to_arguments(namespace_key, cur_value, false);153  namespace_val = cur_value->GetScalar().UInt(namespace_val);154 155  uint32_t code_val = 0;156  cur_value = arg_values.GetValueAtIndex(1);157  add_to_arguments(code_key, cur_value, false);158  code_val = cur_value->GetScalar().UInt(code_val);159 160  lldb::addr_t payload_addr = LLDB_INVALID_ADDRESS;161  cur_value = arg_values.GetValueAtIndex(2);162  add_to_arguments(payload_addr_key, cur_value, true);163  payload_addr = cur_value->GetScalar().ULongLong(payload_addr);164 165  uint32_t payload_size = 0;166  cur_value = arg_values.GetValueAtIndex(3);167  add_to_arguments(payload_size_key, cur_value, false);168  payload_size = cur_value->GetScalar().UInt(payload_size);169 170  lldb::addr_t reason_addr = LLDB_INVALID_ADDRESS;171  cur_value = arg_values.GetValueAtIndex(4);172  add_to_arguments(reason_key, cur_value, false);173  reason_addr = cur_value->GetScalar().ULongLong(payload_addr);174 175  // For the reason string, we want the string not the address, so fetch that.176  std::string reason_string;177  Status error;178  process->ReadCStringFromMemory(reason_addr, reason_string, error);179  if (error.Fail()) {180    // Even if we couldn't read the string, return the other data.181    LLDB_LOG(log, "Couldn't fetch reason string: {0}.", error);182    reason_string = "<error fetching reason string>";183  }184 185  uint32_t flags_val = 0;186  cur_value = arg_values.GetValueAtIndex(5);187  add_to_arguments(flags_key, cur_value, false);188  flags_val = cur_value->GetScalar().UInt(flags_val);189 190  // Okay, we've gotten all the argument values, now put them in a191  // StructuredData, and add that to the Process ExtraCrashInformation:192  StructuredData::DictionarySP abort_dict_sp(new StructuredData::Dictionary());193  abort_dict_sp->AddIntegerItem(namespace_key, namespace_val);194  abort_dict_sp->AddIntegerItem(code_key, code_val);195  abort_dict_sp->AddIntegerItem(payload_addr_key, payload_addr);196  abort_dict_sp->AddIntegerItem(payload_size_key, payload_size);197  abort_dict_sp->AddStringItem(reason_key, reason_string);198  abort_dict_sp->AddIntegerItem(flags_key, flags_val);199 200  // This will overwrite the abort_with_payload information in the dictionary  201  // already.  But we can only crash on abort_with_payload once, so that 202  // shouldn't matter.203  process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp);204 205  return RecognizedStackFrameSP(206      new AbortWithPayloadRecognizedStackFrame(frame_sp, arguments_sp));207}208 209AbortWithPayloadRecognizedStackFrame::AbortWithPayloadRecognizedStackFrame(210    lldb::StackFrameSP &frame_sp, ValueObjectListSP &args_sp)211    : RecognizedStackFrame() {212  m_arguments = args_sp;213  m_stop_desc = "abort with payload or reason";214}215 216} // namespace lldb_private217