brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.1 KiB · 5f128a1 Raw
402 lines · cpp
1//===-- AppleGetThreadItemInfoHandler.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 "AppleGetThreadItemInfoHandler.h"10 11#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/Value.h"14#include "lldb/Expression/DiagnosticManager.h"15#include "lldb/Expression/Expression.h"16#include "lldb/Expression/FunctionCaller.h"17#include "lldb/Expression/UtilityFunction.h"18#include "lldb/Symbol/Symbol.h"19#include "lldb/Target/ExecutionContext.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/StackFrame.h"22#include "lldb/Target/Target.h"23#include "lldb/Target/Thread.h"24#include "lldb/Utility/ConstString.h"25#include "lldb/Utility/LLDBLog.h"26#include "lldb/Utility/Log.h"27#include "lldb/Utility/StreamString.h"28#include "lldb/lldb-private.h"29 30using namespace lldb;31using namespace lldb_private;32 33const char34    *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_name =35        "__lldb_backtrace_recording_get_thread_item_info";36const char37    *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_code =38        "                                  \n\39extern \"C\"                                                                                                    \n\40{                                                                                                               \n\41    /*                                                                                                          \n\42     * mach defines                                                                                             \n\43     */                                                                                                         \n\44                                                                                                                \n\45    typedef unsigned int uint32_t;                                                                              \n\46    typedef unsigned long long uint64_t;                                                                        \n\47    typedef uint32_t mach_port_t;                                                                               \n\48    typedef mach_port_t vm_map_t;                                                                               \n\49    typedef int kern_return_t;                                                                                  \n\50    typedef uint64_t mach_vm_address_t;                                                                         \n\51    typedef uint64_t mach_vm_size_t;                                                                            \n\52                                                                                                                \n\53    mach_port_t mach_task_self ();                                                                              \n\54    kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);         \n\55                                                                                                                \n\56    typedef void *pthread_t;                                                                                    \n\57    extern int printf(const char *format, ...);                                                                 \n\58    extern pthread_t pthread_self(void);                                                                        \n\59                                                                                                                \n\60    /*                                                                                                          \n\61     * libBacktraceRecording defines                                                                            \n\62     */                                                                                                         \n\63                                                                                                                \n\64    typedef uint32_t queue_list_scope_t;                                                                        \n\65    typedef void *dispatch_queue_t;                                                                             \n\66    typedef void *introspection_dispatch_queue_info_t;                                                          \n\67    typedef void *introspection_dispatch_item_info_ref;                                                         \n\68                                                                                                                \n\69    extern void __introspection_dispatch_thread_get_item_info (uint64_t  thread_id,                             \n\70                                                 introspection_dispatch_item_info_ref *returned_queues_buffer,  \n\71                                                 uint64_t *returned_queues_buffer_size);                        \n\72                                                                                                                \n\73    /*                                                                                                          \n\74     * return type define                                                                                       \n\75     */                                                                                                         \n\76                                                                                                                \n\77    struct get_thread_item_info_return_values                                                                      \n\78    {                                                                                                           \n\79        uint64_t item_info_buffer_ptr;    /* the address of the items buffer from libBacktraceRecording */  \n\80        uint64_t item_info_buffer_size;   /* the size of the items buffer from libBacktraceRecording */     \n\81    };                                                                                                          \n\82                                                                                                                \n\83    void  __lldb_backtrace_recording_get_thread_item_info                                                          \n\84                                               (struct get_thread_item_info_return_values *return_buffer,          \n\85                                                int debug,                                                      \n\86                                                uint64_t thread_id,                                             \n\87                                                void *page_to_free,                                             \n\88                                                uint64_t page_to_free_size)                                     \n\89{                                                                                                               \n\90    void *pthread_id = pthread_self ();                                                                         \n\91    if (debug)                                                                                                  \n\92      printf (\"entering get_thread_item_info with args return_buffer == %p, debug == %d, thread id == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, (uint64_t) thread_id, page_to_free, page_to_free_size); \n\93    if (page_to_free != 0)                                                                                      \n\94    {                                                                                                           \n\95        mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\96    }                                                                                                           \n\97                                                                                                                \n\98    __introspection_dispatch_thread_get_item_info (thread_id,                                                  \n\99                                                  (void**)&return_buffer->item_info_buffer_ptr,                 \n\100                                                  &return_buffer->item_info_buffer_size);                       \n\101}                                                                                                               \n\102}                                                                                                               \n\103";104 105AppleGetThreadItemInfoHandler::AppleGetThreadItemInfoHandler(Process *process)106    : m_process(process), m_get_thread_item_info_impl_code(),107      m_get_thread_item_info_function_mutex(),108      m_get_thread_item_info_return_buffer_addr(LLDB_INVALID_ADDRESS),109      m_get_thread_item_info_retbuffer_mutex() {}110 111AppleGetThreadItemInfoHandler::~AppleGetThreadItemInfoHandler() = default;112 113void AppleGetThreadItemInfoHandler::Detach() {114 115  if (m_process && m_process->IsAlive() &&116      m_get_thread_item_info_return_buffer_addr != LLDB_INVALID_ADDRESS) {117    std::unique_lock<std::mutex> lock(m_get_thread_item_info_retbuffer_mutex,118                                      std::defer_lock);119    (void)lock.try_lock(); // Even if we don't get the lock, deallocate the buffer120    m_process->DeallocateMemory(m_get_thread_item_info_return_buffer_addr);121  }122}123 124// Compile our __lldb_backtrace_recording_get_thread_item_info() function (from125// the source above in g_get_thread_item_info_function_code) if we don't find126// that function in the inferior already with USE_BUILTIN_FUNCTION defined.127// (e.g. this would be the case for testing.)128//129// Insert the __lldb_backtrace_recording_get_thread_item_info into the inferior130// process if needed.131//132// Write the get_thread_item_info_arglist into the inferior's memory space to133// prepare for the call.134//135// Returns the address of the arguments written down in the inferior process,136// which can be used to make the function call.137 138lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction(139    Thread &thread, ValueList &get_thread_item_info_arglist) {140  ThreadSP thread_sp(thread.shared_from_this());141  ExecutionContext exe_ctx(thread_sp);142  Address impl_code_address;143  DiagnosticManager diagnostics;144  Log *log = GetLog(LLDBLog::SystemRuntime);145  lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;146  FunctionCaller *get_thread_item_info_caller = nullptr;147 148  // Scope for mutex locker:149  {150    std::lock_guard<std::mutex> guard(m_get_thread_item_info_function_mutex);151 152    // First stage is to make the ClangUtility to hold our injected function:153 154    if (!m_get_thread_item_info_impl_code) {155      Status error;156      if (g_get_thread_item_info_function_code != nullptr) {157        auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(158            g_get_thread_item_info_function_code,159            g_get_thread_item_info_function_name, eLanguageTypeC, exe_ctx);160        if (!utility_fn_or_error) {161          LLDB_LOG_ERROR(log, utility_fn_or_error.takeError(),162                         "Failed to get UtilityFunction for "163                         "get-thread-item-info introspection: {0}.");164          return args_addr;165        }166        m_get_thread_item_info_impl_code = std::move(*utility_fn_or_error);167      } else {168        LLDB_LOGF(log, "No get-thread-item-info introspection code found.");169        return LLDB_INVALID_ADDRESS;170      }171 172      // Also make the FunctionCaller for this UtilityFunction:173 174      TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(175          thread.GetProcess()->GetTarget());176      CompilerType get_thread_item_info_return_type =177          scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();178 179      get_thread_item_info_caller =180          m_get_thread_item_info_impl_code->MakeFunctionCaller(181              get_thread_item_info_return_type, get_thread_item_info_arglist,182              thread_sp, error);183      if (error.Fail() || get_thread_item_info_caller == nullptr) {184        LLDB_LOGF(log,185                  "Failed to install get-thread-item-info introspection "186                  "caller: %s.",187                  error.AsCString());188        m_get_thread_item_info_impl_code.reset();189        return args_addr;190      }191 192    } else {193      get_thread_item_info_caller =194          m_get_thread_item_info_impl_code->GetFunctionCaller();195    }196  }197 198  diagnostics.Clear();199 200  // Now write down the argument values for this particular call.  This looks201  // like it might be a race condition if other threads were calling into here,202  // but actually it isn't because we allocate a new args structure for this203  // call by passing args_addr = LLDB_INVALID_ADDRESS...204 205  if (!get_thread_item_info_caller->WriteFunctionArguments(206          exe_ctx, args_addr, get_thread_item_info_arglist, diagnostics)) {207    if (log) {208      LLDB_LOGF(log, "Error writing get-thread-item-info function arguments");209      diagnostics.Dump(log);210    }211    return args_addr;212  }213 214  return args_addr;215}216 217AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo218AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread,219                                                 lldb::tid_t thread_id,220                                                 addr_t page_to_free,221                                                 uint64_t page_to_free_size,222                                                 Status &error) {223  lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);224  ProcessSP process_sp(thread.CalculateProcess());225  TargetSP target_sp(thread.CalculateTarget());226  TypeSystemClangSP scratch_ts_sp =227      ScratchTypeSystemClang::GetForTarget(*target_sp);228  Log *log = GetLog(LLDBLog::SystemRuntime);229 230  GetThreadItemInfoReturnInfo return_value;231  return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;232  return_value.item_buffer_size = 0;233 234  error.Clear();235 236  if (!thread.SafeToCallFunctions()) {237    LLDB_LOGF(log, "Not safe to call functions on thread 0x%" PRIx64,238              thread.GetID());239    error =240        Status::FromErrorString("Not safe to call functions on this thread.");241    return return_value;242  }243 244  // Set up the arguments for a call to245 246  // struct get_thread_item_info_return_values {247  //     uint64_t item_info_buffer_ptr;    /* the address of the items buffer248  //     from libBacktraceRecording */249  //     uint64_t item_info_buffer_size;   /* the size of the items buffer from250  //     libBacktraceRecording */251  // };252  //253  // void  __lldb_backtrace_recording_get_thread_item_info254  //                                            (struct255  //                                            get_thread_item_info_return_values256  //                                            *return_buffer,257  //                                             int debug,258  //                                             void *page_to_free,259  //                                             uint64_t page_to_free_size)260 261  // Where the return_buffer argument points to a 24 byte region of memory262  // already allocated by lldb in the inferior process.263 264  CompilerType clang_void_ptr_type =265      scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();266  Value return_buffer_ptr_value;267  return_buffer_ptr_value.SetValueType(Value::ValueType::Scalar);268  return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type);269 270  CompilerType clang_int_type = scratch_ts_sp->GetBasicType(eBasicTypeInt);271  Value debug_value;272  debug_value.SetValueType(Value::ValueType::Scalar);273  debug_value.SetCompilerType(clang_int_type);274 275  CompilerType clang_uint64_type =276      scratch_ts_sp->GetBasicType(eBasicTypeUnsignedLongLong);277  Value thread_id_value;278  thread_id_value.SetValueType(Value::ValueType::Scalar);279  thread_id_value.SetCompilerType(clang_uint64_type);280 281  Value page_to_free_value;282  page_to_free_value.SetValueType(Value::ValueType::Scalar);283  page_to_free_value.SetCompilerType(clang_void_ptr_type);284 285  Value page_to_free_size_value;286  page_to_free_size_value.SetValueType(Value::ValueType::Scalar);287  page_to_free_size_value.SetCompilerType(clang_uint64_type);288 289  std::lock_guard<std::mutex> guard(m_get_thread_item_info_retbuffer_mutex);290  if (m_get_thread_item_info_return_buffer_addr == LLDB_INVALID_ADDRESS) {291    addr_t bufaddr = process_sp->AllocateMemory(292        32, ePermissionsReadable | ePermissionsWritable, error);293    if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS) {294      LLDB_LOGF(log, "Failed to allocate memory for return buffer for get "295                     "current queues func call");296      return return_value;297    }298    m_get_thread_item_info_return_buffer_addr = bufaddr;299  }300 301  ValueList argument_values;302 303  return_buffer_ptr_value.GetScalar() =304      m_get_thread_item_info_return_buffer_addr;305  argument_values.PushValue(return_buffer_ptr_value);306 307  debug_value.GetScalar() = 0;308  argument_values.PushValue(debug_value);309 310  thread_id_value.GetScalar() = thread_id;311  argument_values.PushValue(thread_id_value);312 313  if (page_to_free != LLDB_INVALID_ADDRESS)314    page_to_free_value.GetScalar() = page_to_free;315  else316    page_to_free_value.GetScalar() = 0;317  argument_values.PushValue(page_to_free_value);318 319  page_to_free_size_value.GetScalar() = page_to_free_size;320  argument_values.PushValue(page_to_free_size_value);321 322  addr_t args_addr = SetupGetThreadItemInfoFunction(thread, argument_values);323 324  DiagnosticManager diagnostics;325  ExecutionContext exe_ctx;326  EvaluateExpressionOptions options;327  FunctionCaller *get_thread_item_info_caller = nullptr;328 329  options.SetUnwindOnError(true);330  options.SetIgnoreBreakpoints(true);331  options.SetStopOthers(true);332#if __has_feature(address_sanitizer)333  options.SetTimeout(process_sp->GetUtilityExpressionTimeout());334#else335  options.SetTimeout(std::chrono::milliseconds(500));336#endif337  options.SetTryAllThreads(false);338  options.SetIsForUtilityExpr(true);339  thread.CalculateExecutionContext(exe_ctx);340 341  if (!m_get_thread_item_info_impl_code) {342    error = Status::FromErrorString(343        "Unable to compile function to call "344        "__introspection_dispatch_thread_get_item_info");345    return return_value;346  }347 348  get_thread_item_info_caller =349      m_get_thread_item_info_impl_code->GetFunctionCaller();350 351  if (!get_thread_item_info_caller) {352    error = Status::FromErrorString(353        "Unable to compile function caller for "354        "__introspection_dispatch_thread_get_item_info");355    return return_value;356  }357 358  ExpressionResults func_call_ret;359  Value results;360  func_call_ret = get_thread_item_info_caller->ExecuteFunction(361      exe_ctx, &args_addr, options, diagnostics, results);362  if (func_call_ret != eExpressionCompleted || !error.Success()) {363    LLDB_LOGF(log,364              "Unable to call "365              "__introspection_dispatch_thread_get_item_info(), got "366              "ExpressionResults %d, error contains %s",367              func_call_ret, error.AsCString(""));368    error = Status::FromErrorString(369        "Unable to call "370        "__introspection_dispatch_thread_get_item_info() for "371        "list of queues");372    return return_value;373  }374 375  return_value.item_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory(376      m_get_thread_item_info_return_buffer_addr, 8, LLDB_INVALID_ADDRESS,377      error);378  if (!error.Success() ||379      return_value.item_buffer_ptr == LLDB_INVALID_ADDRESS) {380    return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;381    return return_value;382  }383 384  return_value.item_buffer_size = m_process->ReadUnsignedIntegerFromMemory(385      m_get_thread_item_info_return_buffer_addr + 8, 8, 0, error);386 387  if (!error.Success()) {388    return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;389    return return_value;390  }391 392  LLDB_LOGF(log,393            "AppleGetThreadItemInfoHandler called "394            "__introspection_dispatch_thread_get_item_info (page_to_free "395            "== 0x%" PRIx64 ", size = %" PRId64396            "), returned page is at 0x%" PRIx64 ", size %" PRId64,397            page_to_free, page_to_free_size, return_value.item_buffer_ptr,398            return_value.item_buffer_size);399 400  return return_value;401}402