[Lldb-commits] [lldb] [lldb] Refactor InstrumentationRuntimeAsan and add a new plugin (PR #69388)

Usama Hameed via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 17 14:52:39 PDT 2023


https://github.com/usama54321 updated https://github.com/llvm/llvm-project/pull/69388

>From 3ee63c7dfd8b92ac8738d19bd3cebffeccfd59ec Mon Sep 17 00:00:00 2001
From: usama <u_hameed at apple.com>
Date: Tue, 17 Oct 2023 14:35:04 -0700
Subject: [PATCH] [lldb] Refactor InstrumentationRuntimeAsan and add a new
 plugin InstrumentationRuntimeLibsanitizers.

This commit adds InstrumentationRuntimeLibsanitizers, a new runtime
plugin for ASan. The plugin provides the same
functionality as InstrumentationRuntimeASan, but provides a different
set of symbols/library names to search for while activating the plugin.

rdar://112491689
---
 lldb/include/lldb/lldb-enumerations.h         |   1 +
 .../ASan/CMakeLists.txt                       |   2 +
 .../ASan/InstrumentationRuntimeASan.cpp       | 225 +---------------
 .../ASan/InstrumentationRuntimeASan.h         |   6 +-
 .../ASan/Libsanitizers/CMakeLists.txt         |  14 +
 .../InstrumentationRuntimeLibsanitizers.cpp   | 108 ++++++++
 .../InstrumentationRuntimeLibsanitizers.h     |  56 ++++
 .../ASan/ReportRetriever.cpp                  | 241 ++++++++++++++++++
 .../ASan/ReportRetriever.h                    |  31 +++
 9 files changed, 460 insertions(+), 224 deletions(-)
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.cpp
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.h
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.cpp
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.h

diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 36f3030c5226d60..206ff4ed7e6ad05 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -527,6 +527,7 @@ enum InstrumentationRuntimeType {
   eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer = 0x0002,
   eInstrumentationRuntimeTypeMainThreadChecker = 0x0003,
   eInstrumentationRuntimeTypeSwiftRuntimeReporting = 0x0004,
+  eInstrumentationRuntimeTypeLibsanitizersAsan = 0x0005,
   eNumInstrumentationRuntimeTypes
 };
 
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
index 0b29027018463fe..361e78316f290c0 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
@@ -1,5 +1,7 @@
+add_subdirectory(Libsanitizers)
 add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN
   InstrumentationRuntimeASan.cpp
+  ReportRetriever.cpp
 
   LINK_LIBS
     lldbBreakpoint
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
index 5fcdc808bbb154c..3ca0f2d528fea1d 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
@@ -9,23 +9,12 @@
 #include "InstrumentationRuntimeASan.h"
 
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/Core/PluginManager.h"
-#include "lldb/Core/ValueObject.h"
-#include "lldb/Expression/UserExpression.h"
-#include "lldb/Host/StreamFile.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Symbol/Symbol.h"
-#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Utility/RegularExpression.h"
-#include "lldb/Utility/Stream.h"
-
-#include "llvm/ADT/StringSwitch.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -69,169 +58,6 @@ bool InstrumentationRuntimeASan::CheckIfRuntimeIsValid(
   return symbol != nullptr;
 }
 
-const char *address_sanitizer_retrieve_report_data_prefix = R"(
-extern "C"
-{
-int __asan_report_present();
-void *__asan_get_report_pc();
-void *__asan_get_report_bp();
-void *__asan_get_report_sp();
-void *__asan_get_report_address();
-const char *__asan_get_report_description();
-int __asan_get_report_access_type();
-size_t __asan_get_report_access_size();
-}
-)";
-
-const char *address_sanitizer_retrieve_report_data_command = R"(
-struct {
-    int present;
-    int access_type;
-    void *pc;
-    void *bp;
-    void *sp;
-    void *address;
-    size_t access_size;
-    const char *description;
-} t;
-
-t.present = __asan_report_present();
-t.access_type = __asan_get_report_access_type();
-t.pc = __asan_get_report_pc();
-t.bp = __asan_get_report_bp();
-t.sp = __asan_get_report_sp();
-t.address = __asan_get_report_address();
-t.access_size = __asan_get_report_access_size();
-t.description = __asan_get_report_description();
-t
-)";
-
-StructuredData::ObjectSP InstrumentationRuntimeASan::RetrieveReportData() {
-  ProcessSP process_sp = GetProcessSP();
-  if (!process_sp)
-    return StructuredData::ObjectSP();
-
-  ThreadSP thread_sp =
-      process_sp->GetThreadList().GetExpressionExecutionThread();
-  StackFrameSP frame_sp =
-      thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
-
-  if (!frame_sp)
-    return StructuredData::ObjectSP();
-
-  EvaluateExpressionOptions options;
-  options.SetUnwindOnError(true);
-  options.SetTryAllThreads(true);
-  options.SetStopOthers(true);
-  options.SetIgnoreBreakpoints(true);
-  options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
-  options.SetPrefix(address_sanitizer_retrieve_report_data_prefix);
-  options.SetAutoApplyFixIts(false);
-  options.SetLanguage(eLanguageTypeObjC_plus_plus);
-
-  ValueObjectSP return_value_sp;
-  ExecutionContext exe_ctx;
-  Status eval_error;
-  frame_sp->CalculateExecutionContext(exe_ctx);
-  ExpressionResults result = UserExpression::Evaluate(
-      exe_ctx, options, address_sanitizer_retrieve_report_data_command, "",
-      return_value_sp, eval_error);
-  if (result != eExpressionCompleted) {
-    StreamString ss;
-    ss << "cannot evaluate AddressSanitizer expression:\n";
-    ss << eval_error.AsCString();
-    Debugger::ReportWarning(ss.GetString().str(),
-                            process_sp->GetTarget().GetDebugger().GetID());
-    return StructuredData::ObjectSP();
-  }
-
-  int present = return_value_sp->GetValueForExpressionPath(".present")
-                    ->GetValueAsUnsigned(0);
-  if (present != 1)
-    return StructuredData::ObjectSP();
-
-  addr_t pc =
-      return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
-  addr_t bp =
-  return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
-  addr_t sp =
-      return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
-  addr_t address = return_value_sp->GetValueForExpressionPath(".address")
-                       ->GetValueAsUnsigned(0);
-  addr_t access_type =
-      return_value_sp->GetValueForExpressionPath(".access_type")
-          ->GetValueAsUnsigned(0);
-  addr_t access_size =
-      return_value_sp->GetValueForExpressionPath(".access_size")
-          ->GetValueAsUnsigned(0);
-  addr_t description_ptr =
-      return_value_sp->GetValueForExpressionPath(".description")
-          ->GetValueAsUnsigned(0);
-  std::string description;
-  Status error;
-  process_sp->ReadCStringFromMemory(description_ptr, description, error);
-
-  StructuredData::Dictionary *dict = new StructuredData::Dictionary();
-  dict->AddStringItem("instrumentation_class", "AddressSanitizer");
-  dict->AddStringItem("stop_type", "fatal_error");
-  dict->AddIntegerItem("pc", pc);
-  dict->AddIntegerItem("bp", bp);
-  dict->AddIntegerItem("sp", sp);
-  dict->AddIntegerItem("address", address);
-  dict->AddIntegerItem("access_type", access_type);
-  dict->AddIntegerItem("access_size", access_size);
-  dict->AddStringItem("description", description);
-
-  return StructuredData::ObjectSP(dict);
-}
-
-std::string
-InstrumentationRuntimeASan::FormatDescription(StructuredData::ObjectSP report) {
-  std::string description = std::string(report->GetAsDictionary()
-                                            ->GetValueForKey("description")
-                                            ->GetAsString()
-                                            ->GetValue());
-  return llvm::StringSwitch<std::string>(description)
-      .Case("heap-use-after-free", "Use of deallocated memory")
-      .Case("heap-buffer-overflow", "Heap buffer overflow")
-      .Case("stack-buffer-underflow", "Stack buffer underflow")
-      .Case("initialization-order-fiasco", "Initialization order problem")
-      .Case("stack-buffer-overflow", "Stack buffer overflow")
-      .Case("stack-use-after-return", "Use of stack memory after return")
-      .Case("use-after-poison", "Use of poisoned memory")
-      .Case("container-overflow", "Container overflow")
-      .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
-      .Case("global-buffer-overflow", "Global buffer overflow")
-      .Case("unknown-crash", "Invalid memory access")
-      .Case("stack-overflow", "Stack space exhausted")
-      .Case("null-deref", "Dereference of null pointer")
-      .Case("wild-jump", "Jump to non-executable address")
-      .Case("wild-addr-write", "Write through wild pointer")
-      .Case("wild-addr-read", "Read from wild pointer")
-      .Case("wild-addr", "Access through wild pointer")
-      .Case("signal", "Deadly signal")
-      .Case("double-free", "Deallocation of freed memory")
-      .Case("new-delete-type-mismatch",
-            "Deallocation size different from allocation size")
-      .Case("bad-free", "Deallocation of non-allocated memory")
-      .Case("alloc-dealloc-mismatch",
-            "Mismatch between allocation and deallocation APIs")
-      .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
-      .Case("bad-__sanitizer_get_allocated_size",
-            "Invalid argument to __sanitizer_get_allocated_size")
-      .Case("param-overlap",
-            "Call to function disallowing overlapping memory ranges")
-      .Case("negative-size-param", "Negative size used when accessing memory")
-      .Case("bad-__sanitizer_annotate_contiguous_container",
-            "Invalid argument to __sanitizer_annotate_contiguous_container")
-      .Case("odr-violation", "Symbol defined in multiple translation units")
-      .Case(
-          "invalid-pointer-pair",
-          "Comparison or arithmetic on pointers from different memory regions")
-      // for unknown report codes just show the code
-      .Default("AddressSanitizer detected: " + description);
-}
-
 bool InstrumentationRuntimeASan::NotifyBreakpointHit(
     void *baton, StoppointCallbackContext *context, user_id_t break_id,
     user_id_t break_loc_id) {
@@ -244,32 +70,7 @@ bool InstrumentationRuntimeASan::NotifyBreakpointHit(
 
   ProcessSP process_sp = instance->GetProcessSP();
 
-  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
-    return false;
-
-  StructuredData::ObjectSP report = instance->RetrieveReportData();
-  std::string description;
-  if (report) {
-    description = instance->FormatDescription(report);
-  }
-  // Make sure this is the right process
-  if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
-    ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
-    if (thread_sp)
-      thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo::
-                                 CreateStopReasonWithInstrumentationData(
-                                     *thread_sp, description, report));
-
-    StreamFileSP stream_sp(
-        process_sp->GetTarget().GetDebugger().GetOutputStreamSP());
-    if (stream_sp) {
-      stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
-                        "info -s' to get extended information about the "
-                        "report.\n");
-    }
-    return true; // Return true to stop the target
-  } else
-    return false; // Let target run
+  return ReportRetriever::NotifyBreakpointHit(process_sp, context, break_id, break_loc_id);
 }
 
 void InstrumentationRuntimeASan::Activate() {
@@ -280,29 +81,13 @@ void InstrumentationRuntimeASan::Activate() {
   if (!process_sp)
     return;
 
-  ConstString symbol_name("_ZN6__asanL7AsanDieEv");
-  const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType(
-      symbol_name, eSymbolTypeCode);
+  Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint(GetRuntimeModuleSP(), process_sp, ConstString("_ZN6__asanL7AsanDieEv"));
 
-  if (symbol == nullptr)
+  if (!breakpoint)
     return;
 
-  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
-    return;
-
-  Target &target = process_sp->GetTarget();
-  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
-
-  if (symbol_address == LLDB_INVALID_ADDRESS)
-    return;
+  bool sync = false;
 
-  const bool internal = true;
-  const bool hardware = false;
-  const bool sync = false;
-  Breakpoint *breakpoint =
-      process_sp->GetTarget()
-          .CreateBreakpoint(symbol_address, internal, hardware)
-          .get();
   breakpoint->SetCallback(InstrumentationRuntimeASan::NotifyBreakpointHit, this,
                           sync);
   breakpoint->SetBreakpointKind("address-sanitizer-report");
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
index 83a88cf7f89fadf..b1395c31bbe7dae 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
@@ -9,6 +9,8 @@
 #ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H
 #define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H
 
+#include "ReportRetriever.h"
+
 #include "lldb/Target/InstrumentationRuntime.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/StructuredData.h"
@@ -51,10 +53,6 @@ class InstrumentationRuntimeASan : public lldb_private::InstrumentationRuntime {
                                   StoppointCallbackContext *context,
                                   lldb::user_id_t break_id,
                                   lldb::user_id_t break_loc_id);
-
-  StructuredData::ObjectSP RetrieveReportData();
-
-  std::string FormatDescription(StructuredData::ObjectSP report);
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/CMakeLists.txt
new file mode 100644
index 000000000000000..2ca6556f9c6b110
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeLibsanitizers PLUGIN
+  InstrumentationRuntimeLibsanitizers.cpp
+  ../ReportRetriever.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbExpression
+    lldbInterpreter
+    lldbSymbol
+    lldbTarget
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.cpp
new file mode 100644
index 000000000000000..6ab9f28010ae047
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.cpp
@@ -0,0 +1,108 @@
+//===-- InstrumentationRuntimeLibsanitizers.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 "InstrumentationRuntimeLibsanitizers.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/RegularExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(InstrumentationRuntimeLibsanitizers)
+
+lldb::InstrumentationRuntimeSP
+InstrumentationRuntimeLibsanitizers::CreateInstance(const lldb::ProcessSP &process_sp) {
+  return InstrumentationRuntimeSP(new InstrumentationRuntimeLibsanitizers(process_sp));
+}
+
+void InstrumentationRuntimeLibsanitizers::Initialize() {
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(), "AddressSanitizer instrumentation runtime plugin for Libsanitizers.",
+      CreateInstance, GetTypeStatic);
+}
+
+void InstrumentationRuntimeLibsanitizers::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb::InstrumentationRuntimeType InstrumentationRuntimeLibsanitizers::GetTypeStatic() {
+  return eInstrumentationRuntimeTypeLibsanitizersAsan;
+}
+
+InstrumentationRuntimeLibsanitizers::~InstrumentationRuntimeLibsanitizers() { Deactivate(); }
+
+const RegularExpression &
+InstrumentationRuntimeLibsanitizers::GetPatternForRuntimeLibrary() {
+  // FIXME: This shouldn't include the "dylib" suffix.
+  static RegularExpression regex(
+      llvm::StringRef("libsystem_sanitizers\\.dylib"));
+  return regex;
+}
+
+bool InstrumentationRuntimeLibsanitizers::CheckIfRuntimeIsValid(
+    const lldb::ModuleSP module_sp) {
+  const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("__asan_abi_init"), lldb::eSymbolTypeAny);
+
+  return symbol != nullptr;
+}
+
+bool InstrumentationRuntimeLibsanitizers::NotifyBreakpointHit(
+    void *baton, StoppointCallbackContext *context, user_id_t break_id,
+    user_id_t break_loc_id) {
+  assert(baton && "null baton");
+  if (!baton)
+    return false;
+
+  InstrumentationRuntimeLibsanitizers *const instance =
+      static_cast<InstrumentationRuntimeLibsanitizers *>(baton);
+
+  ProcessSP process_sp = instance->GetProcessSP();
+
+  return ReportRetriever::NotifyBreakpointHit(process_sp, context, break_id, break_loc_id);
+}
+
+void InstrumentationRuntimeLibsanitizers::Activate() {
+  if (IsActive())
+    return;
+
+  ProcessSP process_sp = GetProcessSP();
+  if (!process_sp)
+    return;
+
+  Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint(GetRuntimeModuleSP(), process_sp, ConstString("_Z22raise_sanitizers_error23sanitizer_error_context"));
+
+  if (!breakpoint)
+    return;
+
+  bool sync = false;
+
+  breakpoint->SetCallback(InstrumentationRuntimeLibsanitizers::NotifyBreakpointHit, this,
+                          sync);
+  breakpoint->SetBreakpointKind("address-sanitizer-report");
+  SetBreakpointID(breakpoint->GetID());
+
+  SetActive(true);
+}
+
+void InstrumentationRuntimeLibsanitizers::Deactivate() {
+  if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
+    ProcessSP process_sp = GetProcessSP();
+    if (process_sp) {
+      process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
+      SetBreakpointID(LLDB_INVALID_BREAK_ID);
+    }
+  }
+  SetActive(false);
+}
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.h b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.h
new file mode 100644
index 000000000000000..44eeb3669e9f0ec
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/Libsanitizers/InstrumentationRuntimeLibsanitizers.h
@@ -0,0 +1,56 @@
+//===-- InstrumentationRuntimeLibsanitizers.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_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMELIBSANITIZERS_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMELIBSANITIZERS_H
+
+#include "../ReportRetriever.h"
+
+
+namespace lldb_private {
+
+class InstrumentationRuntimeLibsanitizers : public lldb_private::InstrumentationRuntime {
+public:
+  ~InstrumentationRuntimeLibsanitizers() override;
+
+  static lldb::InstrumentationRuntimeSP
+  CreateInstance(const lldb::ProcessSP &process_sp);
+
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "Libsanitizers-ASan"; }
+
+  static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+private:
+  InstrumentationRuntimeLibsanitizers(const lldb::ProcessSP &process_sp)
+      : lldb_private::InstrumentationRuntime(process_sp) {}
+
+  const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+  bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+  void Activate() override;
+
+  void Deactivate();
+
+  static bool NotifyBreakpointHit(void *baton,
+                                  StoppointCallbackContext *context,
+                                  lldb::user_id_t break_id,
+                                  lldb::user_id_t break_loc_id);
+};
+
+} // namespace lldb_private
+
+#endif //LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMELIBSANITIZERS_H
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.cpp
new file mode 100644
index 000000000000000..78b5abcaf8292d5
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.cpp
@@ -0,0 +1,241 @@
+//===-- ReportRetriever.cpp ----------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReportRetriever.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *address_sanitizer_retrieve_report_data_prefix = R"(
+extern "C"
+{
+int __asan_report_present();
+void *__asan_get_report_pc();
+void *__asan_get_report_bp();
+void *__asan_get_report_sp();
+void *__asan_get_report_address();
+const char *__asan_get_report_description();
+int __asan_get_report_access_type();
+size_t __asan_get_report_access_size();
+}
+)";
+
+const char *address_sanitizer_retrieve_report_data_command = R"(
+struct {
+    int present;
+    int access_type;
+    void *pc;
+    void *bp;
+    void *sp;
+    void *address;
+    size_t access_size;
+    const char *description;
+} t;
+
+t.present = __asan_report_present();
+t.access_type = __asan_get_report_access_type();
+t.pc = __asan_get_report_pc();
+t.bp = __asan_get_report_bp();
+t.sp = __asan_get_report_sp();
+t.address = __asan_get_report_address();
+t.access_size = __asan_get_report_access_size();
+t.description = __asan_get_report_description();
+t
+)";
+
+StructuredData::ObjectSP ReportRetriever::RetrieveReportData(const ProcessSP process_sp) {
+  if (!process_sp)
+    return StructuredData::ObjectSP();
+
+  ThreadSP thread_sp =
+      process_sp->GetThreadList().GetExpressionExecutionThread();
+  StackFrameSP frame_sp =
+      thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
+
+  if (!frame_sp)
+    return StructuredData::ObjectSP();
+
+  EvaluateExpressionOptions options;
+  options.SetUnwindOnError(true);
+  options.SetTryAllThreads(true);
+  options.SetStopOthers(true);
+  options.SetIgnoreBreakpoints(true);
+  options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
+  options.SetPrefix(address_sanitizer_retrieve_report_data_prefix);
+  options.SetAutoApplyFixIts(false);
+  options.SetLanguage(eLanguageTypeObjC_plus_plus);
+
+  ValueObjectSP return_value_sp;
+  ExecutionContext exe_ctx;
+  Status eval_error;
+  frame_sp->CalculateExecutionContext(exe_ctx);
+  ExpressionResults result = UserExpression::Evaluate(
+      exe_ctx, options, address_sanitizer_retrieve_report_data_command, "",
+      return_value_sp, eval_error);
+  if (result != eExpressionCompleted) {
+    StreamString ss;
+    ss << "cannot evaluate AddressSanitizer expression:\n";
+    ss << eval_error.AsCString();
+    Debugger::ReportWarning(ss.GetString().str(),
+                            process_sp->GetTarget().GetDebugger().GetID());
+    return StructuredData::ObjectSP();
+  }
+
+  int present = return_value_sp->GetValueForExpressionPath(".present")
+                    ->GetValueAsUnsigned(0);
+  if (present != 1)
+    return StructuredData::ObjectSP();
+
+  addr_t pc =
+      return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
+  addr_t bp =
+  return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
+  addr_t sp =
+      return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
+  addr_t address = return_value_sp->GetValueForExpressionPath(".address")
+                       ->GetValueAsUnsigned(0);
+  addr_t access_type =
+      return_value_sp->GetValueForExpressionPath(".access_type")
+          ->GetValueAsUnsigned(0);
+  addr_t access_size =
+      return_value_sp->GetValueForExpressionPath(".access_size")
+          ->GetValueAsUnsigned(0);
+  addr_t description_ptr =
+      return_value_sp->GetValueForExpressionPath(".description")
+          ->GetValueAsUnsigned(0);
+  std::string description;
+  Status error;
+  process_sp->ReadCStringFromMemory(description_ptr, description, error);
+
+  StructuredData::Dictionary *dict = new StructuredData::Dictionary();
+  dict->AddStringItem("instrumentation_class", "AddressSanitizer");
+  dict->AddStringItem("stop_type", "fatal_error");
+  dict->AddIntegerItem("pc", pc);
+  dict->AddIntegerItem("bp", bp);
+  dict->AddIntegerItem("sp", sp);
+  dict->AddIntegerItem("address", address);
+  dict->AddIntegerItem("access_type", access_type);
+  dict->AddIntegerItem("access_size", access_size);
+  dict->AddStringItem("description", description);
+
+  return StructuredData::ObjectSP(dict);
+}
+
+std::string
+ReportRetriever::FormatDescription(StructuredData::ObjectSP report) {
+  std::string description = std::string(report->GetAsDictionary()
+                                            ->GetValueForKey("description")
+                                            ->GetAsString()
+                                            ->GetValue());
+  return llvm::StringSwitch<std::string>(description)
+      .Case("heap-use-after-free", "Use of deallocated memory")
+      .Case("heap-buffer-overflow", "Heap buffer overflow")
+      .Case("stack-buffer-underflow", "Stack buffer underflow")
+      .Case("initialization-order-fiasco", "Initialization order problem")
+      .Case("stack-buffer-overflow", "Stack buffer overflow")
+      .Case("stack-use-after-return", "Use of stack memory after return")
+      .Case("use-after-poison", "Use of poisoned memory")
+      .Case("container-overflow", "Container overflow")
+      .Case("stack-use-after-scope", "Use of out-of-scope stack memory")
+      .Case("global-buffer-overflow", "Global buffer overflow")
+      .Case("unknown-crash", "Invalid memory access")
+      .Case("stack-overflow", "Stack space exhausted")
+      .Case("null-deref", "Dereference of null pointer")
+      .Case("wild-jump", "Jump to non-executable address")
+      .Case("wild-addr-write", "Write through wild pointer")
+      .Case("wild-addr-read", "Read from wild pointer")
+      .Case("wild-addr", "Access through wild pointer")
+      .Case("signal", "Deadly signal")
+      .Case("double-free", "Deallocation of freed memory")
+      .Case("new-delete-type-mismatch",
+            "Deallocation size different from allocation size")
+      .Case("bad-free", "Deallocation of non-allocated memory")
+      .Case("alloc-dealloc-mismatch",
+            "Mismatch between allocation and deallocation APIs")
+      .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size")
+      .Case("bad-__sanitizer_get_allocated_size",
+            "Invalid argument to __sanitizer_get_allocated_size")
+      .Case("param-overlap",
+            "Call to function disallowing overlapping memory ranges")
+      .Case("negative-size-param", "Negative size used when accessing memory")
+      .Case("bad-__sanitizer_annotate_contiguous_container",
+            "Invalid argument to __sanitizer_annotate_contiguous_container")
+      .Case("odr-violation", "Symbol defined in multiple translation units")
+      .Case(
+          "invalid-pointer-pair",
+          "Comparison or arithmetic on pointers from different memory regions")
+      // for unknown report codes just show the code
+      .Default("AddressSanitizer detected: " + description);
+}
+
+bool ReportRetriever::NotifyBreakpointHit(
+    ProcessSP process_sp, StoppointCallbackContext *context,
+    user_id_t break_id, user_id_t break_loc_id) {
+
+  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+    return false;
+
+  StructuredData::ObjectSP report = RetrieveReportData(process_sp);
+  std::string description;
+  if (report) {
+    description = FormatDescription(report);
+  }
+  // Make sure this is the right process
+  if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
+    ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+    if (thread_sp)
+      thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo::
+                                 CreateStopReasonWithInstrumentationData(
+                                     *thread_sp, description, report));
+
+    StreamFileSP stream_sp(
+        process_sp->GetTarget().GetDebugger().GetOutputStreamSP());
+    if (stream_sp) {
+      stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
+                        "info -s' to get extended information about the "
+                        "report.\n");
+    }
+    return true; // Return true to stop the target
+  }
+
+  return false; // Let target run
+}
+
+Breakpoint* ReportRetriever::SetupBreakpoint(ModuleSP module_sp, ProcessSP process_sp, ConstString symbol_name) {
+  const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
+      symbol_name, eSymbolTypeCode);
+
+  if (symbol == nullptr)
+    return nullptr;
+
+  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+    return nullptr;
+
+  Target &target = process_sp->GetTarget();
+  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
+
+  if (symbol_address == LLDB_INVALID_ADDRESS)
+    return nullptr;
+
+  const bool internal = true;
+  const bool hardware = false;
+
+  Breakpoint *breakpoint =
+      process_sp->GetTarget()
+          .CreateBreakpoint(symbol_address, internal, hardware)
+          .get();
+
+  return breakpoint;
+}
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.h b/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.h
new file mode 100644
index 000000000000000..d66e548fb99ed59
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/ReportRetriever.h
@@ -0,0 +1,31 @@
+//===-- ReportRetriever.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Process.h"
+
+#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_REPORTRETRIEVER_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_REPORTRETRIEVER_H
+
+namespace lldb_private {
+
+class ReportRetriever {
+  private:
+  static StructuredData::ObjectSP RetrieveReportData(const lldb::ProcessSP process_sp);
+
+  static std::string FormatDescription(StructuredData::ObjectSP report);
+  public:
+
+  static bool NotifyBreakpointHit(lldb::ProcessSP process_sp,
+    StoppointCallbackContext *context, lldb::user_id_t break_id,
+    lldb::user_id_t break_loc_id);
+
+  static Breakpoint *SetupBreakpoint(lldb::ModuleSP, lldb::ProcessSP, ConstString);
+};
+} // namespace lldb_private
+
+#endif //LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_REPORTRETRIEVER_H



More information about the lldb-commits mailing list