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

Usama Hameed via lldb-commits lldb-commits at lists.llvm.org
Thu Oct 19 11:25:46 PDT 2023


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

>From bafeea33e1aea4a9e947220a78801ef241106eac Mon Sep 17 00:00:00 2001
From: usama <u_hameed at apple.com>
Date: Wed, 18 Oct 2023 17:16:50 -0700
Subject: [PATCH 1/2] [lldb] Refactor InstrumentationRuntimeAsan

This commit refactors InstrumentationRuntimeASan by pulling out reusable
code into a separate ReportRetriever class. The purpose of the
refactoring is to allow reuse of the ReportRetriever class in another
plugin.

rdar://112491689
---
 lldb/include/lldb/lldb-enumerations.h         |   1 +
 .../ASan/CMakeLists.txt                       |   5 +-
 .../ASan/InstrumentationRuntimeASan.cpp       | 242 ++---------------
 .../ASan/InstrumentationRuntimeASan.h         |   7 -
 .../InstrumentationRuntime/CMakeLists.txt     |   1 +
 .../Utility/CMakeLists.txt                    |  10 +
 .../Utility/ReportRetriever.cpp               | 252 ++++++++++++++++++
 .../Utility/ReportRetriever.h                 |  34 +++
 8 files changed, 315 insertions(+), 237 deletions(-)
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/Utility/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..b746a16b31f7789 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
@@ -4,10 +4,7 @@ add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN
   LINK_LIBS
     lldbBreakpoint
     lldbCore
-    lldbExpression
-    lldbInterpreter
     lldbSymbol
     lldbTarget
-  LINK_COMPONENTS
-    Support
+    lldbPluginInstrumentationRuntimeUtility
   )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
index 5fcdc808bbb154c..a09c89103b0e3dd 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp
@@ -9,23 +9,14 @@
 #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"
+#include "Plugins/InstrumentationRuntime/Utility/ReportRetriever.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -69,169 +60,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 +72,8 @@ 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 +84,14 @@ void InstrumentationRuntimeASan::Activate() {
   if (!process_sp)
     return;
 
-  ConstString symbol_name("_ZN6__asanL7AsanDieEv");
-  const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType(
-      symbol_name, eSymbolTypeCode);
-
-  if (symbol == nullptr)
-    return;
+  Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint(
+      GetRuntimeModuleSP(), process_sp, ConstString("_ZN6__asanL7AsanDieEv"));
 
-  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+  if (!breakpoint)
     return;
 
-  Target &target = process_sp->GetTarget();
-  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
-
-  if (symbol_address == LLDB_INVALID_ADDRESS)
-    return;
-
-  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");
@@ -312,12 +101,13 @@ void InstrumentationRuntimeASan::Activate() {
 }
 
 void InstrumentationRuntimeASan::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);
+
+  if (GetBreakpointID() == LLDB_INVALID_BREAK_ID)
+    return;
+
+  if (ProcessSP process_sp = GetProcessSP()) {
+    process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
+    SetBreakpointID(LLDB_INVALID_BREAK_ID);
+  }
 }
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
index 83a88cf7f89fadf..177959d7126be9e 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h
@@ -10,9 +10,6 @@
 #define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H
 
 #include "lldb/Target/InstrumentationRuntime.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Utility/StructuredData.h"
-#include "lldb/lldb-private.h"
 
 namespace lldb_private {
 
@@ -51,10 +48,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/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
index 55e8752e74242ae..72ccce2dca45a94 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(ASan)
 add_subdirectory(MainThreadChecker)
 add_subdirectory(TSan)
 add_subdirectory(UBSan)
+add_subdirectory(Utility)
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt
new file mode 100644
index 000000000000000..05f05c81392276c
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeUtility
+  ReportRetriever.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbExpression
+    lldbSymbol
+    lldbTarget
+  )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
new file mode 100644
index 000000000000000..ff58c4cababae32
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
@@ -0,0 +1,252 @@
+//===-- ReportRetriever.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 "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();
+
+  if (!thread_sp)
+    return StructuredData::ObjectSP();
+
+  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);
+
+  auto dict = std::make_shared<StructuredData::Dictionary>();
+  if (!dict)
+    return StructuredData::ObjectSP();
+
+  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) {
+  // Make sure this is the right process
+  if (!process_sp || process_sp != context->exe_ctx_ref.GetProcessSP())
+    return false;
+
+  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+    return false;
+
+  StructuredData::ObjectSP report = RetrieveReportData(process_sp);
+  if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary)
+    return false;
+
+  std::string description = FormatDescription(report);
+
+  if (ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP())
+    thread_sp->SetStopInfo(
+        InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
+            *thread_sp, description, report));
+
+  if (StreamFileSP stream_sp = StreamFileSP(
+          process_sp->GetTarget().GetDebugger().GetOutputStreamSP()))
+    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
+}
+
+Breakpoint *ReportRetriever::SetupBreakpoint(ModuleSP module_sp,
+                                             ProcessSP process_sp,
+                                             ConstString symbol_name) {
+  if (!module_sp || !process_sp)
+    return nullptr;
+
+  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/Utility/ReportRetriever.h b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.h
new file mode 100644
index 000000000000000..a45339a5809c01c
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.h
@@ -0,0 +1,34 @@
+//===-- 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_UTILITY_REPORTRETRIEVER_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_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_UTILITY_REPORTRETRIEVER_H

>From 56793d6091e8001e04e18b741a2fec3bb6359abe Mon Sep 17 00:00:00 2001
From: usama <u_hameed at apple.com>
Date: Thu, 19 Oct 2023 11:20:43 -0700
Subject: [PATCH 2/2] [lldb] Add a new plugin ASanLibsanitizers

This commit adds ASanLibsanitizers, 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
---
 .../ASanLibsanitizers/CMakeLists.txt          |  10 ++
 .../InstrumentationRuntimeASan.cpp            | 119 ++++++++++++++++++
 .../InstrumentationRuntimeASan.h              |  52 ++++++++
 .../InstrumentationRuntime/CMakeLists.txt     |   1 +
 4 files changed, 182 insertions(+)
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.cpp
 create mode 100644 lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.h

diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/CMakeLists.txt
new file mode 100644
index 000000000000000..fe96fdcc83fa28f
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeASanLibsanitizers PLUGIN
+  InstrumentationRuntimeASan.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbSymbol
+    lldbTarget
+    lldbPluginInstrumentationRuntimeUtility
+  )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.cpp
new file mode 100644
index 000000000000000..7383f988c60d283
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.cpp
@@ -0,0 +1,119 @@
+//===-- InstrumentationRuntimeASan.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 "InstrumentationRuntimeASan.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"
+
+#include "Plugins/InstrumentationRuntime/Utility/ReportRetriever.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() {
+  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;
+
+  const bool sync = false;
+
+  breakpoint->SetCallback(
+      InstrumentationRuntimeLibsanitizers::NotifyBreakpointHit, this, sync);
+  breakpoint->SetBreakpointKind("address-sanitizer-report");
+  SetBreakpointID(breakpoint->GetID());
+
+  SetActive(true);
+}
+
+void InstrumentationRuntimeLibsanitizers::Deactivate() {
+  SetActive(false);
+
+  if (GetBreakpointID() == LLDB_INVALID_BREAK_ID)
+    return;
+
+  if (ProcessSP process_sp = GetProcessSP()) {
+    process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
+    SetBreakpointID(LLDB_INVALID_BREAK_ID);
+  }
+}
diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.h b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.h
new file mode 100644
index 000000000000000..ed95d93e0aeb9ea
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASan.h
@@ -0,0 +1,52 @@
+//===-- InstrumentationRuntimeASan.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_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASAN_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASAN_H
+
+#include "lldb/Target/InstrumentationRuntime.h"
+
+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 lldb_private::RegularExpression &GetPatternForRuntimeLibrary() override;
+
+  bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+  void Activate() override;
+
+  void Deactivate();
+
+  static bool
+  NotifyBreakpointHit(void *baton,
+                      lldb_private::StoppointCallbackContext *context,
+                      lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASAN_H
diff --git a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
index 72ccce2dca45a94..7f301bca14a8375 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory(ASan)
+add_subdirectory(ASanLibsanitizers)
 add_subdirectory(MainThreadChecker)
 add_subdirectory(TSan)
 add_subdirectory(UBSan)



More information about the lldb-commits mailing list