[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread Ed Maste via lldb-commits

emaste wrote:

Needs to be adapted for f2d32ddcec82c20582c6aa32558b82ca7c3d3c50, 
`lldb/source/{Core => Host/common}/StreamFile.cpp`

(I've applied the change locally for testing, and will just fold it into the 
patch series if otherwise ready to go.)


https://github.com/llvm/llvm-project/pull/67106
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread via lldb-commits

https://github.com/aokblast updated 
https://github.com/llvm/llvm-project/pull/67106

>From f8ed3ed64be0a451542a4ec71f254dc9038b2d19 Mon Sep 17 00:00:00 2001
From: aokblast 
Date: Fri, 22 Sep 2023 18:11:07 +0800
Subject: [PATCH 1/5] feat: add DynamicLoaderFreeBSDKernel

---
 .../Plugins/DynamicLoader/CMakeLists.txt  |   1 +
 .../FreeBSD-Kernel/CMakeLists.txt |  13 +
 .../DynamicLoaderFreeBSDKernel.cpp| 770 ++
 .../DynamicLoaderFreeBSDKernel.h  | 165 
 .../FreeBSDKernel/ProcessFreeBSDKernel.cpp|   4 +-
 5 files changed, 951 insertions(+), 2 deletions(-)
 create mode 100644 
lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
 create mode 100644 
lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
 create mode 100644 
lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h

diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt 
b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
index f357fea02efbe68..30607159acdc088 100644
--- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory(Darwin-Kernel)
+add_subdirectory(FreeBSD-Kernel)
 add_subdirectory(MacOSX-DYLD)
 add_subdirectory(POSIX-DYLD)
 add_subdirectory(Static)
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt 
b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
new file mode 100644
index 000..76daf0a327cf97b
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginDynamicLoaderFreeBSDKernel PLUGIN
+  DynamicLoaderFreeBSDKernel.cpp
+
+  LINK_LIBS
+lldbBreakpoint
+lldbCore
+lldbHost
+lldbInterpreter
+lldbSymbol
+lldbTarget
+lldbUtility
+lldbPluginObjectFileELF
+  )
diff --git 
a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
 
b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
new file mode 100644
index 000..d5eb891f0060bea
--- /dev/null
+++ 
b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
@@ -0,0 +1,770 @@
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/LocateSymbolFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+
+#include "DynamicLoaderFreeBSDKernel.h"
+#include 
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderFreeBSDKernel)
+
+void DynamicLoaderFreeBSDKernel::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+GetPluginDescriptionStatic(), CreateInstance,
+DebuggerInit);
+}
+
+void DynamicLoaderFreeBSDKernel::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef DynamicLoaderFreeBSDKernel::GetPluginDescriptionStatic() {
+  return "The Dynamic Loader Plugin For FreeBSD Kernel";
+}
+
+static bool is_kernel(Module *module) {
+  if (!module)
+return false;
+
+  ObjectFile *objfile = module->GetObjectFile();
+  if (!objfile)
+return false;
+  if (objfile->GetType() != ObjectFile::eTypeExecutable)
+return false;
+  if (objfile->GetStrata() != ObjectFile::eStrataUnknown &&
+  objfile->GetStrata() != ObjectFile::eStrataUser)
+return false;
+
+  return true;
+}
+
+static bool is_kmod(Module *module) {
+  if (!module)
+return false;
+  if (!module->GetObjectFile())
+return false;
+  ObjectFile *objfile = module->GetObjectFile();
+  if (objfile->GetType() != ObjectFile::eTypeObjectFile &&
+  objfile->GetType() != ObjectFile::eTypeSharedLibrary)
+return false;
+
+  return true;
+}
+
+static bool is_reloc(Module *module) {
+  if (!module)
+return false;
+  if (!module->GetObjectFile())
+return false;
+  ObjectFile *objfile = module->GetObjectFile();
+  if (objfile->GetType() != ObjectFile::eTypeObjectFile)
+return false;
+
+  return true;
+}
+
+// Instantiate Function of the FreeBSD Kernel Dynamic Loader Plugin called when
+// Register the Plugin
+DynamicLoader *
+DynamicLoaderFreeBSDKernel::CreateInstance(lldb_private::Process *proce

[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread via lldb-commits

https://github.com/aokblast resolved 
https://github.com/llvm/llvm-project/pull/67106
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread via lldb-commits

aokblast wrote:

Excuse me. If the code works well now, I want to ask if I need to modify the 
commit message by myself so the message looks tidy, or let somebody landing 
this pull request modify the message?

https://github.com/llvm/llvm-project/pull/67106
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits

https://github.com/junior-jl updated 
https://github.com/llvm/llvm-project/pull/67019

From 11270775865a8415e00b4d899703f84717344967 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20L=2E=20Junior?= 
Date: Thu, 21 Sep 2023 11:12:58 -0300
Subject: [PATCH 1/7] [lldb] add command start

---
 lldb/source/Commands/CMakeLists.txt   |   1 +
 lldb/source/Commands/CommandObjectStart.cpp   | 102 ++
 lldb/source/Commands/CommandObjectStart.h |  32 ++
 .../source/Interpreter/CommandInterpreter.cpp |   2 +
 4 files changed, 137 insertions(+)
 create mode 100644 lldb/source/Commands/CommandObjectStart.cpp
 create mode 100644 lldb/source/Commands/CommandObjectStart.h

diff --git a/lldb/source/Commands/CMakeLists.txt 
b/lldb/source/Commands/CMakeLists.txt
index 6a36c5376d5c574..54c62e0f5284beb 100644
--- a/lldb/source/Commands/CMakeLists.txt
+++ b/lldb/source/Commands/CMakeLists.txt
@@ -30,6 +30,7 @@ add_lldb_library(lldbCommands NO_PLUGIN_DEPENDENCIES
   CommandObjectSession.cpp
   CommandObjectSettings.cpp
   CommandObjectSource.cpp
+  CommandObjectStart.cpp
   CommandObjectStats.cpp
   CommandObjectTarget.cpp
   CommandObjectThread.cpp
diff --git a/lldb/source/Commands/CommandObjectStart.cpp 
b/lldb/source/Commands/CommandObjectStart.cpp
new file mode 100644
index 000..7406143c50fec1b
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectStart.cpp
@@ -0,0 +1,102 @@
+//===-- CommandObjectStart.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 "CommandObjectStart.h"
+#include "lldb/Interpreter/CommandObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Constructor for CommandObjectStart
+CommandObjectStart::CommandObjectStart(CommandInterpreter &interpreter)
+: CommandObjectParsed(
+  interpreter, "start",
+  "Launches the process and pauses execution at main function",
+  "start args [optional args]") {
+  // Define command arguments
+  CommandArgumentData pause_location{eArgTypeName, eArgRepeatPlain};
+  m_arguments.push_back({pause_location});
+}
+
+CommandObjectStart::~CommandObjectStart() = default;
+
+// Execute the 'start' command
+bool CommandObjectStart::DoExecute(Args &command, CommandReturnObject &result) 
{
+  // Check if the 'first' subcommand is specified
+  bool pause_at_first_instruction = false;
+
+  if (command.GetArgumentCount() == 1 &&
+  strcmp(command.GetArgumentAtIndex(0), "first") == 0) {
+pause_at_first_instruction = true;
+  }
+
+  // Get the current selected target
+  TargetSP target_sp = GetDebugger().GetSelectedTarget();
+  if (!target_sp) {
+result.AppendError("No target selected.\n");
+return false;
+  }
+
+  // Create the breakpoint at main or the first instruction
+  BreakpointSP bp_sp;
+  if (pause_at_first_instruction) {
+ModuleSP exe_module_sp = target_sp->GetExecutableModule();
+ObjectFile *object = exe_module_sp->GetObjectFile();
+Address address = object->GetEntryPointAddress();
+
+if (!address.IsValid()) {
+  result.AppendError("Failed to get the entry point address");
+  result.SetStatus(eReturnStatusFailed);
+  return false;
+}
+
+bp_sp = target_sp->CreateBreakpoint(address, false, false);
+
+  } else {
+// Create a breakpoint at the main function
+bp_sp = target_sp->CreateBreakpoint(
+nullptr, nullptr, "main", eFunctionNameTypeAuto, eLanguageTypeUnknown,
+0, eLazyBoolNo, false, false);
+  }
+
+  if (!bp_sp) {
+result.AppendError("Breakpoint creation failed.\n");
+result.SetStatus(eReturnStatusFailed);
+return false;
+  } else {
+result.GetOutputStream().Printf("Breakpoint created%s.\n",
+pause_at_first_instruction
+? " at first instruction"
+: " in main function");
+result.SetStatus(eReturnStatusSuccessFinishResult);
+  }
+
+  // Construct the process launch info
+  ProcessLaunchInfo launch_info;
+  launch_info.SetShell(HostInfo::GetDefaultShell());
+  ModuleSP exe_module_sp = target_sp->GetExecutableModule();
+  if (!exe_module_sp) {
+result.AppendError("No executable module found.\n");
+return false;
+  }
+
+  launch_info.SetExecutableFile(exe_module_sp->GetPlatformFileSpec(), true);
+  // Launch the process
+  StreamString stream;
+  Status error = target_sp->Launch(launch_info, &stream);
+
+  if (error.Success()) {
+result.SetStatus(eReturnStatusSuccessFinishResult);
+result.GetOutputStream().Printf("Process launched successfully.\n");
+  } else {
+result.AppendErrorWithFormat("Process launch failed: %s\n",
+ error.AsC

[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits

https://github.com/junior-jl resolved 
https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits


@@ -38,7 +39,36 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
   case 's': // Stop at program entry point
 launch_info.GetFlags().Set(eLaunchFlagStopAtEntry);
 break;
-
+  case 'm': // Stop at user entry point
+  {
+TargetSP target_sp =
+execution_context ? execution_context->GetTargetSP() : TargetSP();
+ModuleSP main_module_sp = target_sp->GetExecutableModule();
+FileSpecList shared_lib_filter;
+shared_lib_filter.Append(main_module_sp->GetFileSpec());
+std::vector entryPointNames;
+for (LanguageType lang_type : Language::GetSupportedLanguages()) {
+  Language *lang = Language::FindPlugin(lang_type);
+  if (lang) {
+std::string entryPointName = lang->GetUserEntryPointName();
+if (!entryPointName.empty()) {
+  entryPointNames.push_back(entryPointName);
+}

junior-jl wrote:

Corrected! Thank you for the reminder.

https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits

https://github.com/junior-jl resolved 
https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits

https://github.com/junior-jl resolved 
https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread José Lira Junior via lldb-commits

junior-jl wrote:

What are your thoughts on creating an alias for `process launch 
--stop-at-user-entry` such as the intended `start` (or `begin`, or even `run 
-m`). 

Also, if I wanted to do that, the only change would be an `AddAlias` in 
`CommandInterpreter.cpp`? Or there's something else?

https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread Ed Maste via lldb-commits

emaste wrote:

> Excuse me. If the code works well now, I want to ask if I need to modify the 
> commit message by myself so the message looks tidy, or let somebody landing 
> this pull request modify the message?

This will be the first substantial change I'd land after LLVM moved to use pull 
requests, so I'm not completely certain on the process. I have the commits from 
this pull request on my local machine for testing and when we used Phabricator 
I'd just squash them, edit the commit message, and push.

That raises another point, the author is currently:
`Author: aokblast `
This is your desired author info?

https://github.com/llvm/llvm-project/pull/67106
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] e8ea476 - [lldb] Implement thread local storage for linux (#67470)

2023-09-27 Thread via lldb-commits

Author: jeffreytan81
Date: 2023-09-27T09:14:40-07:00
New Revision: e8ea47602bdb74a88c707d289fc241f7670e1483

URL: 
https://github.com/llvm/llvm-project/commit/e8ea47602bdb74a88c707d289fc241f7670e1483
DIFF: 
https://github.com/llvm/llvm-project/commit/e8ea47602bdb74a88c707d289fc241f7670e1483.diff

LOG: [lldb] Implement thread local storage for linux (#67470)

This patch implements the thread local storage support for linux
(https://github.com/llvm/llvm-project/issues/28766).

TLS feature is originally only implemented for Mac. With my previous
patch to enable `fs_base` register for Linux
(https://reviews.llvm.org/D155256), now it is feasible to implement this
feature for Linux.

The major changes are:
* Track the main module's link address during launch
* Fetch thread pointer from `fs_base` register
* Create register alias for thread pointer
* Read pthread metadata from target memory instead of process so that it
works for coredump

With the patch the failing test is passing now. Note: I am only enabling
this test for Mac and Linux because I do not have machine to test for
FreeBSD/NetBSD.

-

Co-authored-by: jeffreytan81 

Added: 


Modified: 
lldb/include/lldb/Target/RegisterContext.h
lldb/include/lldb/lldb-defines.h
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/source/Target/RegisterContext.cpp
lldb/source/Target/Thread.cpp
lldb/source/Utility/Args.cpp
lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py

Removed: 




diff  --git a/lldb/include/lldb/Target/RegisterContext.h 
b/lldb/include/lldb/Target/RegisterContext.h
index de0efd982daaa71..893569a98dbd8b3 100644
--- a/lldb/include/lldb/Target/RegisterContext.h
+++ b/lldb/include/lldb/Target/RegisterContext.h
@@ -144,6 +144,10 @@ class RegisterContext : public 
std::enable_shared_from_this,
 
   uint64_t GetPC(uint64_t fail_value = LLDB_INVALID_ADDRESS);
 
+  // Returns the register value containing thread specific data, like TLS data
+  // and other thread specific stuff.
+  uint64_t GetThreadPointer(uint64_t fail_value = LLDB_INVALID_ADDRESS);
+
   /// Get an address suitable for symbolication.
   /// When symbolicating -- computing line, block, function --
   /// for a function in the middle of the stack, using the return

diff  --git a/lldb/include/lldb/lldb-defines.h 
b/lldb/include/lldb/lldb-defines.h
index ce7fd6f3754516e..6950a4f3a496acf 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -71,6 +71,9 @@
   11 // The register that would contain pointer size or less argument 7 (if 
any)
 #define LLDB_REGNUM_GENERIC_ARG8   
\
   12 // The register that would contain pointer size or less argument 8 (if 
any)
+#define LLDB_REGNUM_GENERIC_TP 
\
+  13 // The register that would contain thread specific data, like TLS data and
+ // thread control block pointer
 /// Invalid value definitions
 #define LLDB_INVALID_STOP_ID 0
 #define LLDB_INVALID_ADDRESS UINT64_MAX

diff  --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp 
b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
index 68e4ac0cc4007c4..a0b6f44bed0e73b 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -710,16 +710,19 @@ bool DYLDRendezvous::FindMetadata(const char *name, 
PThreadField field,
   target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
 eSymbolTypeAny, list);
   if (list.IsEmpty())
-  return false;
+return false;
 
   Address address = list[0].symbol->GetAddress();
-  addr_t addr = address.GetLoadAddress(&target);
-  if (addr == LLDB_INVALID_ADDRESS)
-return false;
+  address.SetOffset(address.GetOffset() + field * sizeof(uint32_t));
 
+  // Read from target memory as this allows us to try process memory and
+  // fallback to reading from read only sections from the object files. Here we
+  // are reading read only data from libpthread.so to find data in the thread
+  // specific area for the data we want and this won't be saved into process
+  // memory due to it being read only.
   Status error;
-  value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
-  addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
+  value =
+  target.ReadUnsignedIntegerFromMemory(address, sizeof(uint32_t), 0, 
error);
   if (error.Fail())
 return false;
 

diff  --git 
a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp 
b/lldb/source/Plugins/DynamicLoader/POSIX-D

[Lldb-commits] [lldb] [lldb] Implement thread local storage for linux (PR #67470)

2023-09-27 Thread via lldb-commits

https://github.com/jeffreytan81 closed 
https://github.com/llvm/llvm-project/pull/67470
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)

2023-09-27 Thread via lldb-commits

aokblast wrote:

Thanks, maybe aokblast  is more suitable. XD

https://github.com/llvm/llvm-project/pull/67106
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][NFCI] Move functionality for getting unsupported DW_FORM values (PR #67579)

2023-09-27 Thread Alex Langford via lldb-commits

https://github.com/bulbazord created 
https://github.com/llvm/llvm-project/pull/67579

The LLVM implementation of DWARFDebugAbbrev does not have a way of listing all 
the DW_FORM values that have been parsed but are unsupported or otherwise 
unknown. AFAICT this functionality does not exist in LLVM at all. Since my 
primary goal is to unify the implementations and not judge the usefulness or 
completeness of this functionality, I decided to move it out of LLDB's 
implementation of DWARFDebugAbbrev for the time being.

>From 40507690a8f7ec584a580d6b2be1a8f90598d708 Mon Sep 17 00:00:00 2001
From: Alex Langford 
Date: Wed, 27 Sep 2023 10:29:41 -0700
Subject: [PATCH] [lldb][NFCI] Move functionality for getting unsupported
 DW_FORM values

The LLVM implementation of DWARFDebugAbbrev does not have a way of
listing all the DW_FORM values that have been parsed but are unsupported
or otherwise unknown. AFAICT this functionality does not exist in LLVM
at all. Since my primary goal is to unify the implementations and not
judge the usefulness or completeness of this functionality, I decided to
move it out of LLDB's implementation of DWARFDebugAbbrev for the time
being.
---
 .../SymbolFile/DWARF/DWARFDebugAbbrev.cpp | 10 --
 .../SymbolFile/DWARF/DWARFDebugAbbrev.h   | 10 +-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp  | 36 ---
 3 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
index bcebba6abd3ee5c..f3c2755c5a527cc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -61,13 +61,3 @@ DWARFDebugAbbrev::GetAbbreviationDeclarationSet(
 return &(pos->second);
   return nullptr;
 }
-
-// DWARFDebugAbbrev::GetUnsupportedForms()
-void DWARFDebugAbbrev::GetUnsupportedForms(
-std::set &invalid_forms) const {
-  for (const auto &pair : m_abbrevCollMap)
-for (const auto &decl : pair.second)
-  for (const auto &attr : decl.attributes())
-if (!DWARFFormValue::FormIsSupported(attr.Form))
-  invalid_forms.insert(attr.Form);
-}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
index 6d0616deeb91038..d2fade0934c8a88 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
@@ -36,7 +36,15 @@ class DWARFDebugAbbrev {
   /// llvm::ErrorSuccess() on success, and an appropriate llvm::Error object
   /// otherwise.
   llvm::Error parse();
-  void GetUnsupportedForms(std::set &invalid_forms) const;
+
+  DWARFAbbreviationDeclarationCollMapConstIter begin() const {
+assert(!m_data && "Must call parse before iterating over 
DWARFDebugAbbrev");
+return m_abbrevCollMap.begin();
+  }
+
+  DWARFAbbreviationDeclarationCollMapConstIter end() const {
+return m_abbrevCollMap.end();
+  }
 
 protected:
   DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 9832c324a2c0e55..aae481e2ae74177 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -511,6 +511,20 @@ bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
   return version >= 2 && version <= 5;
 }
 
+static std::set GetUnsupportedForms(DWARFDebugAbbrev *debug_abbrev) 
{
+  if (!debug_abbrev)
+return {};
+
+  std::set unsupported_forms;
+  for (const auto &[_, decl_set] : *debug_abbrev)
+for (const auto &decl : decl_set)
+  for (const auto &attr : decl.attributes())
+if (!DWARFFormValue::FormIsSupported(attr.Form))
+  unsupported_forms.insert(attr.Form);
+
+  return unsupported_forms;
+}
+
 uint32_t SymbolFileDWARF::CalculateAbilities() {
   uint32_t abilities = 0;
   if (m_objfile_sp != nullptr) {
@@ -540,19 +554,15 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
 debug_abbrev_file_size = section->GetFileSize();
 
   DWARFDebugAbbrev *abbrev = DebugAbbrev();
-  if (abbrev) {
-std::set invalid_forms;
-abbrev->GetUnsupportedForms(invalid_forms);
-if (!invalid_forms.empty()) {
-  StreamString error;
-  error.Printf("unsupported DW_FORM value%s:",
-   invalid_forms.size() > 1 ? "s" : "");
-  for (auto form : invalid_forms)
-error.Printf(" %#x", form);
-  m_objfile_sp->GetModule()->ReportWarning(
-  "{0}", error.GetString().str().c_str());
-  return 0;
-}
+  std::set unsupported_forms = GetUnsupportedForms(abbrev);
+  if (!unsupported_forms.empty()) {
+StreamString error;
+error.Printf("unsupported DW_FORM value%s:",
+ unsupported_forms.si

[Lldb-commits] [lldb] [lldb][NFCI] Move functionality for getting unsupported DW_FORM values (PR #67579)

2023-09-27 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb


Changes

The LLVM implementation of DWARFDebugAbbrev does not have a way of listing all 
the DW_FORM values that have been parsed but are unsupported or otherwise 
unknown. AFAICT this functionality does not exist in LLVM at all. Since my 
primary goal is to unify the implementations and not judge the usefulness or 
completeness of this functionality, I decided to move it out of LLDB's 
implementation of DWARFDebugAbbrev for the time being.

---
Full diff: https://github.com/llvm/llvm-project/pull/67579.diff


3 Files Affected:

- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp (-10) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h (+9-1) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+23-13) 


``diff
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
index bcebba6abd3ee5c..f3c2755c5a527cc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -61,13 +61,3 @@ DWARFDebugAbbrev::GetAbbreviationDeclarationSet(
 return &(pos->second);
   return nullptr;
 }
-
-// DWARFDebugAbbrev::GetUnsupportedForms()
-void DWARFDebugAbbrev::GetUnsupportedForms(
-std::set &invalid_forms) const {
-  for (const auto &pair : m_abbrevCollMap)
-for (const auto &decl : pair.second)
-  for (const auto &attr : decl.attributes())
-if (!DWARFFormValue::FormIsSupported(attr.Form))
-  invalid_forms.insert(attr.Form);
-}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
index 6d0616deeb91038..d2fade0934c8a88 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
@@ -36,7 +36,15 @@ class DWARFDebugAbbrev {
   /// llvm::ErrorSuccess() on success, and an appropriate llvm::Error object
   /// otherwise.
   llvm::Error parse();
-  void GetUnsupportedForms(std::set &invalid_forms) const;
+
+  DWARFAbbreviationDeclarationCollMapConstIter begin() const {
+assert(!m_data && "Must call parse before iterating over 
DWARFDebugAbbrev");
+return m_abbrevCollMap.begin();
+  }
+
+  DWARFAbbreviationDeclarationCollMapConstIter end() const {
+return m_abbrevCollMap.end();
+  }
 
 protected:
   DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 9832c324a2c0e55..aae481e2ae74177 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -511,6 +511,20 @@ bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
   return version >= 2 && version <= 5;
 }
 
+static std::set GetUnsupportedForms(DWARFDebugAbbrev *debug_abbrev) 
{
+  if (!debug_abbrev)
+return {};
+
+  std::set unsupported_forms;
+  for (const auto &[_, decl_set] : *debug_abbrev)
+for (const auto &decl : decl_set)
+  for (const auto &attr : decl.attributes())
+if (!DWARFFormValue::FormIsSupported(attr.Form))
+  unsupported_forms.insert(attr.Form);
+
+  return unsupported_forms;
+}
+
 uint32_t SymbolFileDWARF::CalculateAbilities() {
   uint32_t abilities = 0;
   if (m_objfile_sp != nullptr) {
@@ -540,19 +554,15 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
 debug_abbrev_file_size = section->GetFileSize();
 
   DWARFDebugAbbrev *abbrev = DebugAbbrev();
-  if (abbrev) {
-std::set invalid_forms;
-abbrev->GetUnsupportedForms(invalid_forms);
-if (!invalid_forms.empty()) {
-  StreamString error;
-  error.Printf("unsupported DW_FORM value%s:",
-   invalid_forms.size() > 1 ? "s" : "");
-  for (auto form : invalid_forms)
-error.Printf(" %#x", form);
-  m_objfile_sp->GetModule()->ReportWarning(
-  "{0}", error.GetString().str().c_str());
-  return 0;
-}
+  std::set unsupported_forms = GetUnsupportedForms(abbrev);
+  if (!unsupported_forms.empty()) {
+StreamString error;
+error.Printf("unsupported DW_FORM value%s:",
+ unsupported_forms.size() > 1 ? "s" : "");
+for (auto form : unsupported_forms)
+  error.Printf(" %#x", form);
+m_objfile_sp->GetModule()->ReportWarning("{0}", error.GetString());
+return 0;
   }
 
   section =

``




https://github.com/llvm/llvm-project/pull/67579
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][NFCI] Move functionality for getting unsupported DW_FORM values (PR #67579)

2023-09-27 Thread Greg Clayton via lldb-commits

https://github.com/clayborg approved this pull request.


https://github.com/llvm/llvm-project/pull/67579
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add SetValueFromCString API to SyntheticFronend (PR #67309)

2023-09-27 Thread via lldb-commits

jimingham wrote:

First off, note that the case of std::strings is slightly orthogonal to what 
you are doing here, because the thing that provides the "semantic" value for a 
std::string is the std::string Summary Formatter.  std::string doesn't actually 
have a synthetic front end provider.  So you would have to do parallel work on 
making "mutating summary providers" if you want to support the use case of 
changing std::string's.  You'd probably want to add a 
"SetValueFromSummaryString" to tell the summary provider to decode the incoming 
string value and figure out how to splat it onto the current object.

Secondly, lldb only supports changing scalars because it's hard to give meaning 
to "changing an aggregate object".  You have to change it in situ - which 
really means changing the values of its contents, i.e. its children - or you 
will end up invalidating code that relies on the location of the aggregate.  
You have to do some kind of "copy" or "move".  We don't try to give meaning to 
"change a whole structure's contents", because it's more natural to go to the 
children one by one and set them to the new values.

Synthetic child providers are all about making an object appear like an 
aggregate.  So again, I'm not sure what it would mean to change the whole 
synthetic value.  The natural operation here would be "change the value of one 
of the children the synthetic provider produces."  This will often still need 
the cooperation of the Synthetic value's FrontEndProvider to know how to do 
that.  For instance, the synthetic children for a std::vector could just 
point to the int in memory, and they can directly write to that memory.  In 
other cases the children don't exist in the program memory, but are either made 
up in lldb's address space, or allocated in the target.  In those cases you 
would have to get the Synthetic FrontEnd involved, to figure out what it would 
mean to change the underlying value for that child.  But in any case, it seems 
to me the request goes from the synthetic child up to the parent, so I would 
imagine that SetValueFromCString on a synthetic child would ask the 
ValueObjectSynthetic that is it's parent to do: "SetValueForChildFromCString".

Jim

  
> On Sep 26, 2023, at 11:44 PM, Pavel Kosov ***@***.***> wrote:
> 
> 
> Getting the SyntheticFrontEnd to try updating the synthetic value is a good 
> addition. But I'm not sure that ValueObject should be the one that should 
> provide access directly to the FrontEnd? Why isn't it enough to have the 
> ValueObjectSynthetic's SetValueFromCString do this? If you have decided to 
> pull the Non-synthetic value (and so are accessing the ValueObjectVariable 
> directly, would you expect to have the synthetic value do an update? When 
> would something that is a ValueObject but not a ValueObjectSynthetic really 
> want to update the value using the SyntheticFrontEnd?
> 
> @jimingham  In my understanding, the situation 
> is looks like this:
> 
> When somebody wants to update a value from lldb API, then SBValue's 
> SetValueFromCString method should be used, which in turn calls 
> ValueObjectVariable / ValueObjectRegister / etc.'s method SetValueFromCString 
> - all of them currently working only with Scalars, which represent addresses 
> for structured values (e.g., std::string in our case) in the process that we 
> debug.
> 
> I do not see a common way to update aggregate types in ValueObject* since it 
> can represent any type of data, but if we have defined synthetic children for 
> the concrete structure we want to update, then we can explicitly define there 
> how to update it.
> 
> So, in case of std::string we can't simply copy a new c-string value to a 
> location of an old c-string value; we have to destroy the old string (free 
> memory) and create a new one. It can be done in expression evaluation for 
> example.
> 
> I might misunderstand something in this problem, if so - please point me the 
> right way.
> 
> —
> Reply to this email directly, view it on GitHub 
> , or 
> unsubscribe 
> .
> You are receiving this because you were mentioned.
> 



https://github.com/llvm/llvm-project/pull/67309
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] add stop-at-user-entry option to process launch (PR #67019)

2023-09-27 Thread via lldb-commits
=?utf-8?q?José?= L. Junior ,
=?utf-8?q?José?= L. Junior ,
=?utf-8?q?José?= L. Junior ,
=?utf-8?q?José?= L. Junior ,
=?utf-8?q?José?= L. Junior ,
=?utf-8?q?José?= L. Junior 
Message-ID:
In-Reply-To: 


jimingham wrote:

We try to only add really frequently used aliases to the default lldb set.  In 
particular, the "unique first one and two character" space in the lldb command 
set is valuable, that's for your most common every-day commands, and we try to 
leave as much of it open as possible for users to customize lldb for their own 
purposes.

In the case of "start", that overlaps with "step" so it doesn't actually take 
up a new slot in that one or two character space, so it's not so bad.  However, 
we certainly don't want to make any of the partial spellings of "step" become 
ambiguous.  In the lldb command line exact matches to aliases always win.  
There's one for `s` but it doesn't look like there's one for `st`.  So if you 
are going to add `start` as an alias, you should also add an "st" alias to 
"thread step" since that's a much more common command.

I personally wouldn't use "start" enough to warrant having it in the default 
command set.  

One of the main reasons that "stopping at main" was handy in gdb was that gdb 
didn't originally do "future-break" so you always had to run to main to get 
everything loaded, then set your breakpoints.  That's not necessary in lldb (or 
really modern gdb's either)...  I think if you are using toy programs, stopping 
at main is pretty common, but I don't think it's all that common once you are 
debugging significant programs, main is generally pretty far from anything 
interesting.

But I don't have a strong opinion about that, if other people want to weigh in.

And to answer your direct question, you are right, you add aliases to the 
default command set by putting a new AddAlias in CommandInterpreter.cpp.

Jim


> On Sep 27, 2023, at 7:31 AM, José Lira Junior ***@***.***> wrote:
> 
> 
> What are your thoughts on creating an alias for process launch 
> --stop-at-user-entry such as the intended start (or begin, or even run -m).
> 
> Also, if I wanted to do that, the only change would be an AddAlias in 
> CommandInterpreter.cpp? Or there's something else?
> 
> —
> Reply to this email directly, view it on GitHub 
> , or 
> unsubscribe 
> .
> You are receiving this because you were mentioned.
> 



https://github.com/llvm/llvm-project/pull/67019
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits

https://github.com/clayborg created 
https://github.com/llvm/llvm-project/pull/67599

Add the ability to get a C++ vtable ValueObject from another ValueObject.

This patch adds the ability to ask a ValueObject for a ValueObject that 
represents the virtual function table for a C++ class. If the ValueObject is 
not a C++ class with a vtable, a valid ValueObject value will be returned that 
contains an appropriate error. If it is successful a valid ValueObject that 
represents vtable will be returned. The ValueObject that is returned will have 
a name that matches the demangled value for a C++ vtable mangled name like 
"vtable for ". It will have N children, one for each virtual 
function pointer. Each child's value is the function pointer itself, the 
summary is the symbolication of this function pointer, and the type will be a 
valid function pointer from the debug info if there is debug information 
corresponding to the virtual function pointer.

The vtable SBValue will have the following:
- SBValue::GetName() returns "vtable for "
- SBValue::GetValue() returns a string representation of the vtable address
- SBValue::GetSummary() returns NULL
- SBValue::GetType() returns a type appropriate for a uintptr_t type for the 
current process
- SBValue::GetLoadAddress() returns the address of the vtable adderess
- SBValue::GetValueAsUnsigned(...) returns the vtable address
- SBValue::GetNumChildren() returns the number of virtual function pointers in 
the vtable
- SBValue::GetChildAtIndex(...) returns a SBValue that represents a virtual 
function pointer

The child SBValue objects that represent a virtual function pointer has the 
following values:
- SBValue::GetName() returns "[%u]" where %u is the vtable function pointer 
index
- SBValue::GetValue() returns a string representation of the virtual function 
pointer
- SBValue::GetSummary() returns a symbolicated respresentation of the virtual 
function pointer
- SBValue::GetType() returns the function prototype type if there is debug 
info, or a generic funtion prototype if there is no debug info
- SBValue::GetLoadAddress() returns the address of the virtual function pointer
- SBValue::GetValueAsUnsigned(...) returns the virtual function pointer
- SBValue::GetNumChildren() returns 0
- SBValue::GetChildAtIndex(...) returns invalid SBValue for any index

Examples of using this API via python:

```
(lldb) script vtable = lldb.frame.FindVariable("shape_ptr").GetVTable()
(lldb) script vtable
vtable for Shape = 0x00014088 {
  [0] = 0x00013d20 a.out`Shape::~Shape() at main.cpp:3
  [1] = 0x00013e4c a.out`Shape::~Shape() at main.cpp:3
  [2] = 0x00013e7c a.out`Shape::area() at main.cpp:4
  [3] = 0x00013e3c a.out`Shape::optional() at main.cpp:7
}
(lldb) script c = vtable.GetChildAtIndex(0)
(lldb) script c
(void ()) [0] = 0x00013d20 a.out`Shape::~Shape() at main.cpp:3
```

>From 8fa9aae354ac455f4ea443de1bb5f753fe93fb51 Mon Sep 17 00:00:00 2001
From: Greg Clayton 
Date: Wed, 27 Sep 2023 13:03:40 -0700
Subject: [PATCH] Add the ability to get a C++ vtable ValueObject from another
 ValueObject.

This patch adds the ability to ask a ValueObject for a ValueObject that 
represents the virtual function table for a C++ class. If the ValueObject is 
not a C++ class with a vtable, a valid ValueObject value will be returned that 
contains an appropriate error. If it is successful a valid ValueObject that 
represents vtable will be returned. The ValueObject that is returned will have 
a name that matches the demangled value for a C++ vtable mangled name like 
"vtable for ". It will have N children, one for each virtual 
function pointer. Each child's value is the function pointer itself, the 
summary is the symbolication of this function pointer, and the type will be a 
valid function pointer from the debug info if there is debug information 
corresponding to the virtual function pointer.

The vtable SBValue will have the following:
- SBValue::GetName() returns "vtable for "
- SBValue::GetValue() returns a string representation of the vtable address
- SBValue::GetSummary() returns NULL
- SBValue::GetType() returns a type appropriate for a uintptr_t type for the 
current process
- SBValue::GetLoadAddress() returns the address of the vtable adderess
- SBValue::GetValueAsUnsigned(...) returns the vtable address
- SBValue::GetNumChildren() returns the number of virtual function pointers in 
the vtable
- SBValue::GetChildAtIndex(...) returns a SBValue that represents a virtual 
function pointer

The child SBValue objects that represent a virtual function pointer has the 
following values:
- SBValue::GetName() returns "[%u]" where %u is the vtable function pointer 
index
- SBValue::GetValue() returns a string representation of the virtual function 
pointer
- SBValue::GetSummary() returns a symbolicated respresentation of the virtual 
function pointer
- SBValue::GetType() returns the function prototype type if there is debug 
info, or a generic fu

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb


Changes

Add the ability to get a C++ vtable ValueObject from another ValueObject.

This patch adds the ability to ask a ValueObject for a ValueObject that 
represents the virtual function table for a C++ class. If the ValueObject is 
not a C++ class with a vtable, a valid ValueObject value will be returned that 
contains an appropriate error. If it is successful a valid ValueObject that 
represents vtable will be returned. The ValueObject that is returned will have 
a name that matches the demangled value for a C++ vtable mangled name like 
"vtable for ". It will have N children, one for each virtual 
function pointer. Each child's value is the function pointer itself, the 
summary is the symbolication of this function pointer, and the type will be a 
valid function pointer from the debug info if there is debug information 
corresponding to the virtual function pointer.

The vtable SBValue will have the following:
- SBValue::GetName() returns "vtable for "
- SBValue::GetValue() returns a string representation of the vtable address
- SBValue::GetSummary() returns NULL
- SBValue::GetType() returns a type appropriate for a uintptr_t type for the 
current process
- SBValue::GetLoadAddress() returns the address of the vtable adderess
- SBValue::GetValueAsUnsigned(...) returns the vtable address
- SBValue::GetNumChildren() returns the number of virtual function pointers in 
the vtable
- SBValue::GetChildAtIndex(...) returns a SBValue that represents a virtual 
function pointer

The child SBValue objects that represent a virtual function pointer has the 
following values:
- SBValue::GetName() returns "[%u]" where %u is the vtable function pointer 
index
- SBValue::GetValue() returns a string representation of the virtual function 
pointer
- SBValue::GetSummary() returns a symbolicated respresentation of the virtual 
function pointer
- SBValue::GetType() returns the function prototype type if there is debug 
info, or a generic funtion prototype if there is no debug info
- SBValue::GetLoadAddress() returns the address of the virtual function pointer
- SBValue::GetValueAsUnsigned(...) returns the virtual function pointer
- SBValue::GetNumChildren() returns 0
- SBValue::GetChildAtIndex(...) returns invalid SBValue for any index

Examples of using this API via python:

```
(lldb) script vtable = lldb.frame.FindVariable("shape_ptr").GetVTable()
(lldb) script vtable
vtable for Shape = 0x00014088 {
  [0] = 0x00013d20 a.out`Shape::~Shape() at main.cpp:3
  [1] = 0x00013e4c a.out`Shape::~Shape() at main.cpp:3
  [2] = 0x00013e7c a.out`Shape::area() at main.cpp:4
  [3] = 0x00013e3c a.out`Shape::optional() at main.cpp:7
}
(lldb) script c = vtable.GetChildAtIndex(0)
(lldb) script c
(void ()) [0] = 0x00013d20 a.out`Shape::~Shape() at main.cpp:3
```

---

Patch is 33.01 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/67599.diff


18 Files Affected:

- (modified) lldb/include/lldb/API/SBValue.h (+28) 
- (modified) lldb/include/lldb/Core/ValueObject.h (+4) 
- (modified) lldb/include/lldb/Core/ValueObjectChild.h (+1) 
- (added) lldb/include/lldb/Core/ValueObjectVTable.h (+65) 
- (modified) lldb/include/lldb/Symbol/TypeSystem.h (+4) 
- (modified) lldb/include/lldb/lldb-enumerations.h (+3-1) 
- (modified) lldb/source/API/SBValue.cpp (+14-3) 
- (modified) lldb/source/Commands/CommandObjectFrame.cpp (+2) 
- (modified) lldb/source/Core/CMakeLists.txt (+1) 
- (modified) lldb/source/Core/ValueObject.cpp (+5) 
- (added) lldb/source/Core/ValueObjectVTable.cpp (+325) 
- (modified) lldb/source/DataFormatters/CXXFunctionPointer.cpp (+5-1) 
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
(+3-1) 
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+25-1) 
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+4) 
- (added) lldb/test/API/functionalities/vtable/Makefile (+3) 
- (added) lldb/test/API/functionalities/vtable/TestVTableValue.py (+135) 
- (added) lldb/test/API/functionalities/vtable/main.cpp (+37) 


``diff
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index b66c2d5642b6f95..333bdf1738eecaf 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -374,6 +374,34 @@ class LLDB_API SBValue {
   lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write,
   SBError &error);
 
+  /// If this value represents a C++ class that has a vtable, return an value
+  /// that represents the virtual function table.
+  ///
+  /// SBValue::GetError() will be in the success state if this value represents
+  /// a C++ class with a vtable, or an appropriate error describing that the
+  /// object isn't a C++ class with a vtable or not a C++ class.
+  ///
+  /// SBValue::GetName() will be the demangled symbol name for the v

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -374,6 +374,34 @@ class LLDB_API SBValue {
   lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write,
   SBError &error);
 
+  /// If this value represents a C++ class that has a vtable, return an value
+  /// that represents the virtual function table.
+  ///
+  /// SBValue::GetError() will be in the success state if this value represents
+  /// a C++ class with a vtable, or an appropriate error describing that the
+  /// object isn't a C++ class with a vtable or not a C++ class.
+  ///
+  /// SBValue::GetName() will be the demangled symbol name for the virtual
+  /// function table like "vtable for Baseclass".

jeffreytan81 wrote:

Shouldn't this be `vtable for ChildClass` in RTTI domain?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -374,6 +374,34 @@ class LLDB_API SBValue {
   lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write,
   SBError &error);
 
+  /// If this value represents a C++ class that has a vtable, return an value
+  /// that represents the virtual function table.
+  ///
+  /// SBValue::GetError() will be in the success state if this value represents
+  /// a C++ class with a vtable, or an appropriate error describing that the
+  /// object isn't a C++ class with a vtable or not a C++ class.
+  ///
+  /// SBValue::GetName() will be the demangled symbol name for the virtual
+  /// function table like "vtable for Baseclass".

jimingham wrote:

I think "BaseClass" was just an example here, but maybe a more abstract name 
would be better.  

For an actual C++ object, the object's vtable pointer always points to the most 
specific class of the object, a fact that lldb relies on to do C++ dynamic type 
detection.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);

jimingham wrote:

This will work if the value is a pointer to an object.  But if this is a stack 
object, then this will fail, won't it?  You should check whether the parent 
ValueObject is a pointer or reference type, and if it's not, use AddressOf 
rather than GetValueAsUnsigned.  

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+

jimingham wrote:

Does the vtable of a static object in a module not get filled in till runtime?  
I don't know the answer but if static objects have valid vtable pointers this 
restriction is not necessary...

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);

jimingham wrote:

Oh, ignore that, this is still the VTableChild...

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}

jimingham wrote:

One of the reasons that people have requested the ability to see vtables in the 
past has been to detect corruption in the vtable.  If the table is corrupt, it 
might very well point to bogus memory.  So it might be better to have this 
still be valid, but have the summary value report that this looks like a bogus 
entry?  Then when I dump the value object I'll be able to see some valid 
entries and some that say "Danger Will Robinson" which might be easier to work 
with than errors?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =

jimingham wrote:

It's okay for now because we don't have any others, but there could be other 
languages that have the concept of a VTable, so at some point the 
eLanguageTypeC_plus_plus should get genericized... 

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

jeffreytan81 wrote:

Looks good in general to me. 

Several scenarios to test:
* Make sure command works when the vtable symbol can be found but the vtable 
exists in another binary which do not have any symbols/debug info (which we 
have seen failure from lldb before)
* Is vtable pointer guarantee to be in the first pointer of object? 
* Can we test this during multiple inheritance? Should we print multiple 
vtables? 
* Test in coredump to make sure it works

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =
+target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  if (type_system_or_err) {
+CompilerType proto = 
(*type_system_or_err)->CreateGenericFunctionPrototype();
+if (proto.IsFunctionType())
+  m_value.SetCompilerType(proto);
+  } else {
+consumeError(type_system_or_err.takeError());
+  }
+}
+
+// Now read our value into m_data so that our we can use the default
+// summary provider for C++ for function pointers which will get the
+// address description for our function pointer.
+if (m_error.Success()) {
+  const bool thread_and_frame_only_if_stopped = true;
+  ExecutionContext exe_ctx(
+GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+}
+SetValueDidChange(true);
+SetValueIsValid(true);
+return true;
+  };
+
+  CompilerType GetCompilerTypeImpl() override {
+return m_value.GetCompilerType();
+  }

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

jimingham wrote:

This is an oft-requested feature so thanks for doing this!

My only real complaint is that the code that determines the C++ "dynamic type" 
does much of the work that the ValueObjectVTable has to do to find the vtable 
pointer, and it's enough code that it seems a shame to have two copies of it.  
Maybe there should be a  LanguageRuntime "GetVTablePointer" that factors out 
the part of GetDynamicTypeAndAddress that finds the VTable.  Then you can get 
the LanguageRuntime from the Object and call this generic API.  That would also 
make it clear that this support is for the ItaniamuABI C++ runtime, so that if 
another runtime comes along that does some other clever thing, it will be 
straightforward to support it.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

jimingham wrote:

It might also be good to write a test that scribbles on the VTable and make 
sure that we present that usefully.  That is a significant use case for this 
feature.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Support target names with dots in more utilities (PR #65812)

2023-09-27 Thread via lldb-commits


@@ -1696,6 +1696,40 @@ TEST(Support, ReplacePathPrefix) {
   EXPECT_EQ(Path, "C:\\old/foo\\bar");
 }
 
+TEST(Support, FindProgramName) {
+  StringRef WindowsProgName =
+  path::program_name("C:\\Test\\foo.exe", path::Style::windows);
+  EXPECT_EQ(WindowsProgName, "foo");
+
+  StringRef WindowsProgNameManyDots = path::program_name(
+  "C:\\Test.7\\x86_64-freebsd14.0-clang.exe", path::Style::windows);
+  EXPECT_EQ(WindowsProgNameManyDots, "x86_64-freebsd14.0-clang");
+
+  StringRef PosixProgName =
+  path::program_name("/var/empty/clang.exe", path::Style::posix);
+  EXPECT_EQ(PosixProgName, "clang");
+
+  StringRef PosixProgNameManyDotsExe = path::program_name(
+  "/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar.exe",
+  path::Style::posix);
+  EXPECT_EQ(PosixProgNameManyDotsExe, "x86_64-portbld-freebsd13.2-llvm-ar");
+
+  StringRef PosixProgNameManyDots = path::program_name(
+  "/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar", path::Style::posix);
+  EXPECT_EQ(PosixProgNameManyDots, "x86_64-portbld-freebsd13.2-llvm-ar");
+
+  StringRef PosixProgNameSh =
+  
path::program_name("/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar.sh",
+ path::Style::posix);
+  EXPECT_EQ(PosixProgNameSh, "x86_64-portbld-freebsd13.2-llvm-ar.sh");
+
+  // TODO: determine if this is correct. What happens on windows with an 
executable
+  // named ".exe"?

dankm wrote:

Makes sense, I'll do that in a subsequent commit.. hopefully that keeps the 
review intact.. still getting used to github.

https://github.com/llvm/llvm-project/pull/65812
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -374,6 +374,34 @@ class LLDB_API SBValue {
   lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write,
   SBError &error);
 
+  /// If this value represents a C++ class that has a vtable, return an value
+  /// that represents the virtual function table.
+  ///
+  /// SBValue::GetError() will be in the success state if this value represents
+  /// a C++ class with a vtable, or an appropriate error describing that the
+  /// object isn't a C++ class with a vtable or not a C++ class.
+  ///
+  /// SBValue::GetName() will be the demangled symbol name for the virtual
+  /// function table like "vtable for Baseclass".

clayborg wrote:

I can change it to "vtable for "?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}

clayborg wrote:

Yes, good idea here. We are reading individual function pointers here, so we 
should still show it. This could also be JIT'ed code where we might not have a 
section for the address. This would be hard to test since these function 
pointers are in read only memory. Can you think of a way to test this? We won't 
get a child like this unless the parent's vtable pointer resolved to a "vtable 
for " symbol, so I am not sure how to test. I guess we can use our 
debugger superpowers to ruin the vtable pointer and test that way.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);

clayborg wrote:

yes, we know that the "value" of the parent, which will be a ValueObjectVTable, 
is the address of the first vtable function pointer.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =
+target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  if (type_system_or_err) {
+CompilerType proto = 
(*type_system_or_err)->CreateGenericFunctionPrototype();
+if (proto.IsFunctionType())
+  m_value.SetCompilerType(proto);
+  } else {
+consumeError(type_system_or_err.takeError());
+  }
+}
+
+// Now read our value into m_data so that our we can use the default
+// summary provider for C++ for function pointers which will get the
+// address description for our function pointer.
+if (m_error.Success()) {
+  const bool thread_and_frame_only_if_stopped = true;
+  ExecutionContext exe_ctx(
+GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+}
+SetValueDidChange(true);
+SetValueIsValid(true);
+return true;
+  };
+
+  CompilerType GetCompilerTypeImpl() override {
+return m_value.GetCompilerType();
+  }

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =

clayborg wrote:

I can rename these classes to be ValueObjectCPlusPlusVTable just in case. Or 
the constructor can take a language enumeration and then we use that?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+

clayborg wrote:

I guess we can switch over to using Target::ReadMemory and relax the need for 
having a process. Is this what you are hinting at?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+

clayborg wrote:

I just verified that the vtable isn't filled in when it is sitting in a .data 
section until the program runs, so looks like it is ok to require a process.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =

clayborg wrote:

Actually I can use "ValueObject::GetObjectRuntimeLanguage()"

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

https://github.com/jimingham resolved 
https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}

jimingham wrote:

Yes, I think that's probably the best way to test it.  You could in fact just 
call SetValueFromCString on one of your ValueObjectVTableChild objects, that 
should do it.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits

clayborg wrote:

> This is an oft-requested feature so thanks for doing this!
> 
> My only real complaint is that the code that determines the C++ "dynamic 
> type" does much of the work that the ValueObjectVTable has to do to find the 
> vtable pointer, and it's enough code that it seems a shame to have two copies 
> of it. Maybe there should be a LanguageRuntime "GetVTablePointer" that 
> factors out the part of GetDynamicTypeAndAddress that finds the VTable. Then 
> you can get the LanguageRuntime from the Object and call this generic API. 
> That would also make it clear that this support is for the ItaniamuABI C++ 
> runtime, so that if another runtime comes along that does some other clever 
> thing, it will be straightforward to support it.

I mention this in my inline comments, but we don't want to detect the dynamic 
type here, we just want to use what ever vtable pointer we find in the current 
ValueObject that we use to ask for the vtable. We might have dynamic typing on 
or off, and we don't want to adjust the pointer at all. If we have dynamic 
typing off, then we will just be in the middle of someone else's vtable, which 
we will locate by finding the symbol that contains it, so that is ok. If we 
have dynamic typing on, then the value we ask for the vtable for will point to 
the first vtable entry for the modified type. So there is no complexity here 
like there is in the GetDynamicTypeAndAddress(). We just read a pointer and 
look for the vtable symbol.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =
+target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  if (type_system_or_err) {
+CompilerType proto = 
(*type_system_or_err)->CreateGenericFunctionPrototype();
+if (proto.IsFunctionType())
+  m_value.SetCompilerType(proto);
+  } else {
+consumeError(type_system_or_err.takeError());
+  }
+}
+
+// Now read our value into m_data so that our we can use the default
+// summary provider for C++ for function pointers which will get the
+// address description for our function pointer.
+if (m_error.Success()) {
+  const bool thread_and_frame_only_if_stopped = true;
+  ExecutionContext exe_ctx(
+GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+}
+SetValueDidChange(true);
+SetValueIsValid(true);
+return true;
+  };
+
+  CompilerType GetCompilerTypeImpl() override {
+return m_value.GetCompilerType();
+  }

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

https://github.com/jimingham edited 
https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits

clayborg wrote:

> Looks good in general to me.
> 
> Several scenarios to test:
> 
> * Make sure command works when the vtable symbol can be found but the vtable 
> exists in another binary which do not have any debug info (which we have seen 
> failure from lldb before)

Good idea. I tried to test by stripping, but then I couldn't set a breakpoint 
where I needed it. So if we do this in another binary and just strip the shared 
library, then I can test this.

> * Is vtable pointer guarantee to be in the first pointer of object?

Yes, if the value is polymorphic. We make sure the type has virtual functions 
first before doing any of this.
> * Can we test this during multiple inheritance? Should we print multiple 
> vtables?
I can add a test for this and make sure things works when dynamic typing is on 
and off. We won't print multiple vtables, as each class has only 1 vtable, it 
will just include all of the virtual methods needed for any inherited classes.
> * Test in coredump to make sure it works
That is tricky due to the vtables never being stored in the core files since 
they are in read only sections.


https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread via lldb-commits

jimingham wrote:

> > This is an oft-requested feature so thanks for doing this!
> > My only real complaint is that the code that determines the C++ "dynamic 
> > type" does much of the work that the ValueObjectVTable has to do to find 
> > the vtable pointer, and it's enough code that it seems a shame to have two 
> > copies of it. Maybe there should be a LanguageRuntime "GetVTablePointer" 
> > that factors out the part of GetDynamicTypeAndAddress that finds the 
> > VTable. Then you can get the LanguageRuntime from the Object and call this 
> > generic API. That would also make it clear that this support is for the 
> > ItaniamuABI C++ runtime, so that if another runtime comes along that does 
> > some other clever thing, it will be straightforward to support it.
> 
> I mention this in my inline comments, but we don't want to detect the dynamic 
> type here, we just want to use what ever vtable pointer we find in the 
> current ValueObject that we use to ask for the vtable. We might have dynamic 
> typing on or off, and we don't want to adjust the pointer at all. If we have 
> dynamic typing off, then we will just be in the middle of someone else's 
> vtable, which we will locate by finding the symbol that contains it, so that 
> is ok. If we have dynamic typing on, then the value we ask for the vtable for 
> will point to the first vtable entry for the modified type. So there is no 
> complexity here like there is in the GetDynamicTypeAndAddress(). We just read 
> a pointer and look for the vtable symbol.

I don't think this is how it works.  If you have your hands on a C++ object, 
even when viewed as a subclass or even one of the more complex 
multi-inheritance base class, and you find it's vtable pointer, it will point 
to the vtable of the most specific class.  That's actually how we figure out 
what the dynamic type is, and that's true in the object, that's not something 
lldb makes up.  So in all cases, the first step is to get the vtable.

The additional complexity in GetDynamicValueAndType is all AFTER we've found 
the dynamic class, where we peer further into the runtime to determine the 
"offset to top".  But you don't need to do any of that to get the dynamic 
class, you just get the vtable & demangle its name...  So I am pretty sure the 
"get the vtable" part is going to be identical between your code and the 
GetDynamicValueAndType, and you can factor that bit out and share it between 
GetDynamicValueAndType and your Update.



https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits

https://github.com/bulbazord commented:

Overall I think this is fine, just a few comments here or there. I like the 
idea a lot, thanks for working on this.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =
+target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  if (type_system_or_err) {
+CompilerType proto = 
(*type_system_or_err)->CreateGenericFunctionPrototype();
+if (proto.IsFunctionType())
+  m_value.SetCompilerType(proto);
+  } else {
+consumeError(type_system_or_err.takeError());
+  }
+}
+
+// Now read our value into m_data so that our we can use the default
+// summary provider for C++ for function pointers which will get the
+// address description for our function pointer.
+if (m_error.Success()) {
+  const bool thread_and_frame_only_if_stopped = true;
+  ExecutionContext exe_ctx(
+GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+}
+SetValueDidChange(true);
+SetValueIsValid(true);
+return true;
+  };
+
+  CompilerType GetCompilerTypeImpl() override {
+return m_value.GetCompilerType();
+  }

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits


@@ -0,0 +1,65 @@
+//===-- ValueObjectVTable.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_CORE_VALUEOBJECTVTABLE_H
+#define LLDB_CORE_VALUEOBJECTVTABLE_H
+
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+/// A class that represents a virtual function table for a C++ class.
+///
+///

bulbazord wrote:

Empty comment lines

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =

bulbazord wrote:

One interesting use case this could work for is swift's value witness tables. 
Although not the exact same as a vtable, it is a similar concept that I think 
is worth making this more generic for.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)

bulbazord wrote:

`if (ValueObject *parent = GetParent())` ?

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits


@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.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 "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include 
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+  ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+  : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+SetFormat(eFormatPointer);
+SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+  }
+
+  ~ValueObjectVTableChild() override = default;
+
+  std::optional GetByteSize() override { return m_addr_size; };
+
+  size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+  ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+  bool IsInScope() override {
+ValueObject *parent = GetParent();
+if (parent)
+  return parent->IsInScope();
+return false;
+  };
+
+protected:
+  bool UpdateValue() override {
+SetValueIsValid(false);
+m_value.Clear();
+ValueObject *parent = GetParent();
+if (!parent) {
+  m_error.SetErrorString("no parent object");
+  return false;
+}
+
+addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+if (parent_addr == LLDB_INVALID_ADDRESS) {
+  m_error.SetErrorString("parent has invalid address");
+  return false;
+}
+
+ProcessSP process_sp = GetProcessSP();
+if (!process_sp) {
+  m_error.SetErrorString("no process");
+  return false;
+}
+
+TargetSP target_sp = GetTargetSP();
+if (!target_sp) {
+  m_error.SetErrorString("no target");
+  return false;
+}
+
+// Each `vtable_entry_addr` points to the function pointer.
+addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+addr_t vfunc_ptr =
+process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+if (m_error.Fail()) {
+  m_error.SetErrorStringWithFormat(
+  "failed to read virtual function entry 0x%16.16" PRIx64,
+  vtable_entry_addr);
+  return false;
+}
+
+Address resolved_vfunc_ptr_address;
+target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+if (!resolved_vfunc_ptr_address.IsValid()) {
+  m_error.SetErrorStringWithFormat(
+  "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+  return false;
+}
+
+// Set our value to be the load address of the function pointer in memory
+// and our type to be the function pointer type.
+m_value.SetValueType(Value::ValueType::LoadAddress);
+m_value.GetScalar() = vtable_entry_addr;
+
+// See if our resolved address points to a function in the debug info. If
+// it does, then we can report the type as a function prototype for this
+// function.
+Function *function =
+resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+if (function) {
+  m_value.SetCompilerType(function->GetCompilerType());
+} else {
+  // Set our value's compiler type to a generic function protoype so that
+  // it displays as a hex function pointer for the value and the summary
+  // will display the address description.
+  auto type_system_or_err =
+target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  if (type_system_or_err) {
+CompilerType proto = 
(*type_system_or_err)->CreateGenericFunctionPrototype();
+if (proto.IsFunctionType())
+  m_value.SetCompilerType(proto);
+  } else {
+consumeError(type_system_or_err.takeError());
+  }
+}
+
+// Now read our value into m_data so that our we can use the default
+// summary provider for C++ for function pointers which will get the
+// address description for our function pointer.
+if (m_error.Success()) {
+  const bool thread_and_frame_only_if_stopped = true;
+  ExecutionContext exe_ctx(
+GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+}
+SetValueDidChange(true);
+SetValueIsValid(true);
+return true;
+  };
+
+  CompilerType GetCompilerTypeImpl() override {
+return m_value.GetCompilerType();
+  }

[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Alex Langford via lldb-commits

https://github.com/bulbazord edited 
https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

https://github.com/jimingham created 
https://github.com/llvm/llvm-project/pull/67621

We just forget to check for interrupt while waiting for the answer to the 
prompt. But if we are in the interrupt state then the lower layers of the 
EditLine code just eat all characters so we never get out of the query prompt. 
You're pretty much stuck and have to kill lldb.

The solution is to check for the interrupt. The patch is a little bigger 
because where I needed to check the Interrupt state I only had the ::EditLine 
object, but the editor state is held in lldb's EditLine wrapper, so I had to do 
a little work to get my hands on it.

>From fab5e1f67433a29a5d54198d83960d7e608dc480 Mon Sep 17 00:00:00 2001
From: Jim Ingham 
Date: Wed, 27 Sep 2023 17:07:33 -0700
Subject: [PATCH] Fix a bug in handling ^C at the "y/n/a" completion prompt.

We just forget to check for interrupt while waiting for the answer to the 
prompt. But if we are in the interrupt state then the lower
layers of the EditLine code just eat all characters so we never get out of the 
query prompt. You're pretty much stuck and have to kill lldb.

The solution is to check for the interrupt. The patch is a little bigger 
because where I needed to check the Interrupt state I only
had the ::EditLine object, but the editor state is held in lldb's EditLine 
wrapper, so I had to do a little work to get my hands on it.
---
 lldb/include/lldb/Host/Editline.h |  4 +++
 lldb/source/Host/common/Editline.cpp  | 28 ---
 .../completion/TestIOHandlerCompletion.py |  6 
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/lldb/include/lldb/Host/Editline.h 
b/lldb/include/lldb/Host/Editline.h
index e1807aa5492680e..c598244150788da 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -161,6 +161,10 @@ class Editline {
   /// of Editline.
   static Editline *InstanceFor(::EditLine *editline);
 
+  static void
+  DisplayCompletions(Editline &editline,
+ llvm::ArrayRef results);
+
   /// Sets a string to be used as a prompt, or combined with a line number to
   /// form a prompt.
   void SetPrompt(const char *prompt);
diff --git a/lldb/source/Host/common/Editline.cpp 
b/lldb/source/Host/common/Editline.cpp
index edefbf4008129e4..82e17ec753ab235 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -943,12 +943,12 @@ PrintCompletion(FILE *output_file,
   }
 }
 
-static void
-DisplayCompletions(::EditLine *editline, FILE *output_file,
-   llvm::ArrayRef results) {
+void Editline::DisplayCompletions(
+Editline &editline, llvm::ArrayRef results) {
   assert(!results.empty());
 
-  fprintf(output_file, "\n" ANSI_CLEAR_BELOW "Available completions:\n");
+  fprintf(editline.m_output_file,
+  "\n" ANSI_CLEAR_BELOW "Available completions:\n");
   const size_t page_size = 40;
   bool all = false;
 
@@ -960,7 +960,7 @@ DisplayCompletions(::EditLine *editline, FILE *output_file,
   const size_t max_len = longest->GetCompletion().size();
 
   if (results.size() < page_size) {
-PrintCompletion(output_file, results, max_len);
+PrintCompletion(editline.m_output_file, results, max_len);
 return;
   }
 
@@ -969,17 +969,25 @@ DisplayCompletions(::EditLine *editline, FILE 
*output_file,
 size_t remaining = results.size() - cur_pos;
 size_t next_size = all ? remaining : std::min(page_size, remaining);
 
-PrintCompletion(output_file, results.slice(cur_pos, next_size), max_len);
+PrintCompletion(editline.m_output_file, results.slice(cur_pos, next_size),
+max_len);
 
 cur_pos += next_size;
 
 if (cur_pos >= results.size())
   break;
 
-fprintf(output_file, "More (Y/n/a): ");
+fprintf(editline.m_output_file, "More (Y/n/a): ");
 char reply = 'n';
-int got_char = el_getc(editline, &reply);
-fprintf(output_file, "\n");
+int got_char = el_getc(editline.m_editline, &reply);
+// Check for a ^C or other interruption.
+if (editline.m_editor_status == EditorStatus::Interrupted) {
+  editline.m_editor_status = EditorStatus::Editing;
+  fprintf(editline.m_output_file, "^C\n");
+  break;
+}
+
+fprintf(editline.m_output_file, "\n");
 if (got_char == -1 || reply == 'n')
   break;
 if (reply == 'a')
@@ -1050,7 +1058,7 @@ unsigned char Editline::TabCommand(int ch) {
 return CC_REDISPLAY;
   }
 
-  DisplayCompletions(m_editline, m_output_file, results);
+  DisplayCompletions(*this, results);
 
   DisplayInput();
   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
diff --git a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py 
b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
index 0e28a94adf1e4a3..a74a6572f71f872 100644
--- a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
+++ b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
@@ -75

[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb


Changes

We just forget to check for interrupt while waiting for the answer to the 
prompt. But if we are in the interrupt state then the lower layers of the 
EditLine code just eat all characters so we never get out of the query prompt. 
You're pretty much stuck and have to kill lldb.

The solution is to check for the interrupt. The patch is a little bigger 
because where I needed to check the Interrupt state I only had the ::EditLine 
object, but the editor state is held in lldb's EditLine wrapper, so I had to do 
a little work to get my hands on it.

---
Full diff: https://github.com/llvm/llvm-project/pull/67621.diff


3 Files Affected:

- (modified) lldb/include/lldb/Host/Editline.h (+4) 
- (modified) lldb/source/Host/common/Editline.cpp (+18-10) 
- (modified) lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py (+6) 


``diff
diff --git a/lldb/include/lldb/Host/Editline.h 
b/lldb/include/lldb/Host/Editline.h
index e1807aa5492680e..c598244150788da 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -161,6 +161,10 @@ class Editline {
   /// of Editline.
   static Editline *InstanceFor(::EditLine *editline);
 
+  static void
+  DisplayCompletions(Editline &editline,
+ llvm::ArrayRef results);
+
   /// Sets a string to be used as a prompt, or combined with a line number to
   /// form a prompt.
   void SetPrompt(const char *prompt);
diff --git a/lldb/source/Host/common/Editline.cpp 
b/lldb/source/Host/common/Editline.cpp
index edefbf4008129e4..82e17ec753ab235 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -943,12 +943,12 @@ PrintCompletion(FILE *output_file,
   }
 }
 
-static void
-DisplayCompletions(::EditLine *editline, FILE *output_file,
-   llvm::ArrayRef results) {
+void Editline::DisplayCompletions(
+Editline &editline, llvm::ArrayRef results) {
   assert(!results.empty());
 
-  fprintf(output_file, "\n" ANSI_CLEAR_BELOW "Available completions:\n");
+  fprintf(editline.m_output_file,
+  "\n" ANSI_CLEAR_BELOW "Available completions:\n");
   const size_t page_size = 40;
   bool all = false;
 
@@ -960,7 +960,7 @@ DisplayCompletions(::EditLine *editline, FILE *output_file,
   const size_t max_len = longest->GetCompletion().size();
 
   if (results.size() < page_size) {
-PrintCompletion(output_file, results, max_len);
+PrintCompletion(editline.m_output_file, results, max_len);
 return;
   }
 
@@ -969,17 +969,25 @@ DisplayCompletions(::EditLine *editline, FILE 
*output_file,
 size_t remaining = results.size() - cur_pos;
 size_t next_size = all ? remaining : std::min(page_size, remaining);
 
-PrintCompletion(output_file, results.slice(cur_pos, next_size), max_len);
+PrintCompletion(editline.m_output_file, results.slice(cur_pos, next_size),
+max_len);
 
 cur_pos += next_size;
 
 if (cur_pos >= results.size())
   break;
 
-fprintf(output_file, "More (Y/n/a): ");
+fprintf(editline.m_output_file, "More (Y/n/a): ");
 char reply = 'n';
-int got_char = el_getc(editline, &reply);
-fprintf(output_file, "\n");
+int got_char = el_getc(editline.m_editline, &reply);
+// Check for a ^C or other interruption.
+if (editline.m_editor_status == EditorStatus::Interrupted) {
+  editline.m_editor_status = EditorStatus::Editing;
+  fprintf(editline.m_output_file, "^C\n");
+  break;
+}
+
+fprintf(editline.m_output_file, "\n");
 if (got_char == -1 || reply == 'n')
   break;
 if (reply == 'a')
@@ -1050,7 +1058,7 @@ unsigned char Editline::TabCommand(int ch) {
 return CC_REDISPLAY;
   }
 
-  DisplayCompletions(m_editline, m_output_file, results);
+  DisplayCompletions(*this, results);
 
   DisplayInput();
   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
diff --git a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py 
b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
index 0e28a94adf1e4a3..a74a6572f71f872 100644
--- a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
+++ b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
@@ -75,6 +75,12 @@ def test_completion(self):
 self.child.send("n")
 self.expect_prompt()
 
+# Start tab completion and abort showing more commands with '^C'.
+self.child.send("\t")
+self.child.expect_exact("More (Y/n/a)")
+self.child.sendcontrol('c')
+self.expect_prompt()
+
 # Shouldn't crash or anything like that.
 self.child.send("regoinvalid\t")
 self.expect_prompt()

``




https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

github-actions[bot] wrote:




:warning: Python code formatter, darker found issues in your code. :warning:



You can test this locally with the following command:


``bash
darker --check --diff -r 
22433cc541ff706d9e845774ef1c8c959dc67799..fab5e1f67433a29a5d54198d83960d7e608dc480
 lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
``





View the diff from darker here.


``diff
--- TestIOHandlerCompletion.py  2023-09-28 00:07:33.00 +
+++ TestIOHandlerCompletion.py  2023-09-28 00:12:29.727805 +
@@ -76,11 +76,11 @@
 self.expect_prompt()
 
 # Start tab completion and abort showing more commands with '^C'.
 self.child.send("\t")
 self.child.expect_exact("More (Y/n/a)")
-self.child.sendcontrol('c')
+self.child.sendcontrol("c")
 self.expect_prompt()
 
 # Shouldn't crash or anything like that.
 self.child.send("regoinvalid\t")
 self.expect_prompt()

``




https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread Alex Langford via lldb-commits

https://github.com/bulbazord approved this pull request.

LGTM, thanks!

Please fix the python formatting before landing.

https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

jimingham wrote:

> LGTM, thanks!
> 
> Please fix the python formatting before landing.

Seriously, we're enforcing "" vrs. ''?  This is silly.

https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] 0f339e6 - Fix a bug in handling ^C at the "y/n/a" completion prompt.

2023-09-27 Thread Jim Ingham via lldb-commits

Author: Jim Ingham
Date: 2023-09-27T17:20:48-07:00
New Revision: 0f339e6567bffb290e409ef5de272fb75ce70234

URL: 
https://github.com/llvm/llvm-project/commit/0f339e6567bffb290e409ef5de272fb75ce70234
DIFF: 
https://github.com/llvm/llvm-project/commit/0f339e6567bffb290e409ef5de272fb75ce70234.diff

LOG: Fix a bug in handling ^C at the "y/n/a" completion prompt.

We just forget to check for interrupt while waiting for the answer to the 
prompt. But if we are in the interrupt state then the lower
layers of the EditLine code just eat all characters so we never get out of the 
query prompt. You're pretty much stuck and have to kill lldb.

The solution is to check for the interrupt. The patch is a little bigger 
because where I needed to check the Interrupt state I only
had the ::EditLine object, but the editor state is held in lldb's EditLine 
wrapper, so I had to do a little work to get my hands on it.

Added: 


Modified: 
lldb/include/lldb/Host/Editline.h
lldb/source/Host/common/Editline.cpp
lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py

Removed: 




diff  --git a/lldb/include/lldb/Host/Editline.h 
b/lldb/include/lldb/Host/Editline.h
index e1807aa5492680e..c598244150788da 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -161,6 +161,10 @@ class Editline {
   /// of Editline.
   static Editline *InstanceFor(::EditLine *editline);
 
+  static void
+  DisplayCompletions(Editline &editline,
+ llvm::ArrayRef results);
+
   /// Sets a string to be used as a prompt, or combined with a line number to
   /// form a prompt.
   void SetPrompt(const char *prompt);

diff  --git a/lldb/source/Host/common/Editline.cpp 
b/lldb/source/Host/common/Editline.cpp
index edefbf4008129e4..82e17ec753ab235 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -943,12 +943,12 @@ PrintCompletion(FILE *output_file,
   }
 }
 
-static void
-DisplayCompletions(::EditLine *editline, FILE *output_file,
-   llvm::ArrayRef results) {
+void Editline::DisplayCompletions(
+Editline &editline, llvm::ArrayRef results) {
   assert(!results.empty());
 
-  fprintf(output_file, "\n" ANSI_CLEAR_BELOW "Available completions:\n");
+  fprintf(editline.m_output_file,
+  "\n" ANSI_CLEAR_BELOW "Available completions:\n");
   const size_t page_size = 40;
   bool all = false;
 
@@ -960,7 +960,7 @@ DisplayCompletions(::EditLine *editline, FILE *output_file,
   const size_t max_len = longest->GetCompletion().size();
 
   if (results.size() < page_size) {
-PrintCompletion(output_file, results, max_len);
+PrintCompletion(editline.m_output_file, results, max_len);
 return;
   }
 
@@ -969,17 +969,25 @@ DisplayCompletions(::EditLine *editline, FILE 
*output_file,
 size_t remaining = results.size() - cur_pos;
 size_t next_size = all ? remaining : std::min(page_size, remaining);
 
-PrintCompletion(output_file, results.slice(cur_pos, next_size), max_len);
+PrintCompletion(editline.m_output_file, results.slice(cur_pos, next_size),
+max_len);
 
 cur_pos += next_size;
 
 if (cur_pos >= results.size())
   break;
 
-fprintf(output_file, "More (Y/n/a): ");
+fprintf(editline.m_output_file, "More (Y/n/a): ");
 char reply = 'n';
-int got_char = el_getc(editline, &reply);
-fprintf(output_file, "\n");
+int got_char = el_getc(editline.m_editline, &reply);
+// Check for a ^C or other interruption.
+if (editline.m_editor_status == EditorStatus::Interrupted) {
+  editline.m_editor_status = EditorStatus::Editing;
+  fprintf(editline.m_output_file, "^C\n");
+  break;
+}
+
+fprintf(editline.m_output_file, "\n");
 if (got_char == -1 || reply == 'n')
   break;
 if (reply == 'a')
@@ -1050,7 +1058,7 @@ unsigned char Editline::TabCommand(int ch) {
 return CC_REDISPLAY;
   }
 
-  DisplayCompletions(m_editline, m_output_file, results);
+  DisplayCompletions(*this, results);
 
   DisplayInput();
   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);

diff  --git a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py 
b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
index 0e28a94adf1e4a3..b16869b05e7df0e 100644
--- a/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
+++ b/lldb/test/API/iohandler/completion/TestIOHandlerCompletion.py
@@ -75,6 +75,12 @@ def test_completion(self):
 self.child.send("n")
 self.expect_prompt()
 
+# Start tab completion and abort showing more commands with '^C'.
+self.child.send("\t")
+self.child.expect_exact("More (Y/n/a)")
+self.child.sendcontrol("c")
+self.expect_prompt()
+
 # Shouldn't crash or anything like that.
 self.child.send("regoinvalid\t")
 self.expect_prompt()


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

jimingham wrote:

I pushed this from the repro, going through the PR hoops was too much work just 
for uglification...

https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Fix a bug in handling ^C at the "y/n/a" completion prompt. (PR #67621)

2023-09-27 Thread via lldb-commits

https://github.com/jimingham closed 
https://github.com/llvm/llvm-project/pull/67621
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread River Riddle via lldb-commits

https://github.com/River707 created 
https://github.com/llvm/llvm-project/pull/67628

LLDB_EXPORT_ALL_SYMBOLS is useful when building out-of-tree plugins and 
extensions that rely on LLDB's internal symbols. For example, this is how the 
Mojo language provides its REPL and debugger support.

Supporting this on windows is kind of tricky because this is normally expected 
to be done using dllexport/dllimport, but lldb uses these with the public api. 
This PR takes an approach similar to what LLVM does with 
LLVM_EXPORT_SYMBOLS_FOR_PLUGINS, and what chromium does for 
[abseil](https://github.com/chromium/chromium/blob/253d14e20fdc0cab05e5516770dceca18f9bddaf/third_party/abseil-cpp/generate_def_files.py),
 and uses a python script to extract the necessary symbols by looking at the 
symbol table for the various lldb libraries.

>From 4cc073bb514fe08115f194143987e8460d43a77d Mon Sep 17 00:00:00 2001
From: River Riddle 
Date: Wed, 27 Sep 2023 18:59:53 -0700
Subject: [PATCH] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS

LLDB_EXPORT_ALL_SYMBOLS is useful when building out-of-tree
plugins and extensions that rely on LLDB's internal symbols. For
example, this is how the Mojo language provides its REPL and
debugger support.

Supporting this on windows is kind of tricky because this is normally
expected to be done using dllexport/dllimport, but lldb uses these
with the public api. This PR takes an approach similar to what LLVM
does with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS, and what chromium
does for 
[abseil](https://github.com/chromium/chromium/blob/253d14e20fdc0cab05e5516770dceca18f9bddaf/third_party/abseil-cpp/generate_def_files.py),
and uses a python script to extract the necessary symbols by looking at
the symbol table for the various lldb libraries.
---
 lldb/cmake/modules/LLDBConfig.cmake  |  10 +-
 lldb/scripts/msvc_extract_private_symbols.py | 100 +++
 lldb/source/API/CMakeLists.txt   |  37 +++
 3 files changed, 139 insertions(+), 8 deletions(-)
 create mode 100644 lldb/scripts/msvc_extract_private_symbols.py

diff --git a/lldb/cmake/modules/LLDBConfig.cmake 
b/lldb/cmake/modules/LLDBConfig.cmake
index 19283b3cbb0194f..380016ce48015fa 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -122,14 +122,8 @@ if(APPLE AND CMAKE_GENERATOR STREQUAL Xcode)
   endif()
 endif()
 
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
-  set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
-"Causes lldb to export all symbols when building liblldb.")
-else()
-  # Windows doesn't support toggling this, so don't bother making it a
-  # cache variable.
-  set(LLDB_EXPORT_ALL_SYMBOLS 0)
-endif()
+set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
+  "Causes lldb to export all symbols when building liblldb.")
 
 if ((NOT MSVC) OR MSVC12)
   add_definitions( -DHAVE_ROUND )
diff --git a/lldb/scripts/msvc_extract_private_symbols.py 
b/lldb/scripts/msvc_extract_private_symbols.py
new file mode 100644
index 000..47325d56c0d792f
--- /dev/null
+++ b/lldb/scripts/msvc_extract_private_symbols.py
@@ -0,0 +1,100 @@
+"""A tool for extracting a list of private lldb symbols to export for MSVC.
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. Private symbols in LLDB don't explicitly specific dllexport, so we
+automate that by examining the symbol table.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def extract_symbols(nm_path: str, lib: str):
+"""Extract all of the private lldb symbols from the given path to llvm-nm 
and
+library to extract from."""
+
+# Matches mangled symbols containing 'lldb_private'.
+lldb_sym_re = r"0* [BT] (?P[?]+[^?].*lldb_private.*)"
+
+# '-g' means we only get global symbols.
+# '-p' do not waste time sorting the symbols.
+process = subprocess.Popen(
+[nm_path, "-g", "-p", lib],
+bufsize=1,
+stdout=subprocess.PIPE,
+stdin=subprocess.PIPE,
+universal_newlines=True,
+)
+process.stdin.close()
+
+lldb_symbols = set()
+for line in process.stdout:
+match = re.match(lldb_sym_re, line)
+if match:
+symbol = match.group("symbol")
+assert symbol.count(" ") == 0, (
+"Regex matched too much, probably got " "undecorated name as 
well"
+)
+# Deleting destructors start with ?_G or ?_E and can be discarded
+# because link.exe gives you a warning telling you they can't be
+# exported if you don't.
+if symbol.startswith("??_G") or symbol.startswith("??_E"):
+continue
+lldb_symbols.add(symbol)
+
+return lldb_symbols
+
+
+def main():
+parser = argparse.ArgumentParser(description="Generate LLDB dll exports")
+parser.add_argument(
+"-o", metavar="file", type=str, help="Th

[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread River Riddle via lldb-commits

https://github.com/River707 updated 
https://github.com/llvm/llvm-project/pull/67628

>From 5174dcdd77567cc4e0dd063f6e5b7fce18dd767b Mon Sep 17 00:00:00 2001
From: River Riddle 
Date: Wed, 27 Sep 2023 18:59:53 -0700
Subject: [PATCH] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS

LLDB_EXPORT_ALL_SYMBOLS is useful when building out-of-tree
plugins and extensions that rely on LLDB's internal symbols. For
example, this is how the Mojo language provides its REPL and
debugger support.

Supporting this on windows is kind of tricky because this is normally
expected to be done using dllexport/dllimport, but lldb uses these
with the public api. This PR takes an approach similar to what LLVM
does with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS, and what chromium
does for 
[abseil](https://github.com/chromium/chromium/blob/253d14e20fdc0cab05e5516770dceca18f9bddaf/third_party/abseil-cpp/generate_def_files.py),
and uses a python script to extract the necessary symbols by looking at
the symbol table for the various lldb libraries.
---
 lldb/cmake/modules/LLDBConfig.cmake  |  10 +-
 lldb/scripts/msvc_extract_private_symbols.py | 100 +++
 lldb/source/API/CMakeLists.txt   |  37 +++
 3 files changed, 139 insertions(+), 8 deletions(-)
 create mode 100644 lldb/scripts/msvc_extract_private_symbols.py

diff --git a/lldb/cmake/modules/LLDBConfig.cmake 
b/lldb/cmake/modules/LLDBConfig.cmake
index 19283b3cbb0194f..380016ce48015fa 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -122,14 +122,8 @@ if(APPLE AND CMAKE_GENERATOR STREQUAL Xcode)
   endif()
 endif()
 
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
-  set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
-"Causes lldb to export all symbols when building liblldb.")
-else()
-  # Windows doesn't support toggling this, so don't bother making it a
-  # cache variable.
-  set(LLDB_EXPORT_ALL_SYMBOLS 0)
-endif()
+set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
+  "Causes lldb to export all symbols when building liblldb.")
 
 if ((NOT MSVC) OR MSVC12)
   add_definitions( -DHAVE_ROUND )
diff --git a/lldb/scripts/msvc_extract_private_symbols.py 
b/lldb/scripts/msvc_extract_private_symbols.py
new file mode 100644
index 000..91ed02ffa8665f0
--- /dev/null
+++ b/lldb/scripts/msvc_extract_private_symbols.py
@@ -0,0 +1,100 @@
+"""A tool for extracting a list of private lldb symbols to export for MSVC.
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. Private symbols in LLDB don't explicitly specific dllexport, so we
+automate that by examining the symbol table.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def extract_symbols(nm_path: str, lib: str):
+"""Extract all of the private lldb symbols from the given path to llvm-nm 
and
+library to extract from."""
+
+# Matches mangled symbols containing 'lldb_private'.
+lldb_sym_re = r"0* [BT] (?P[?]+[^?].*lldb_private.*)"
+
+# '-g' means we only get global symbols.
+# '-p' do not waste time sorting the symbols.
+process = subprocess.Popen(
+[nm_path, "-g", "-p", lib],
+bufsize=1,
+stdout=subprocess.PIPE,
+stdin=subprocess.PIPE,
+universal_newlines=True,
+)
+process.stdin.close()
+
+lldb_symbols = set()
+for line in process.stdout:
+match = re.match(lldb_sym_re, line)
+if match:
+symbol = match.group("symbol")
+assert symbol.count(" ") == 0, (
+"Regex matched too much, probably got undecorated name as well"
+)
+# Deleting destructors start with ?_G or ?_E and can be discarded
+# because link.exe gives you a warning telling you they can't be
+# exported if you don't.
+if symbol.startswith("??_G") or symbol.startswith("??_E"):
+continue
+lldb_symbols.add(symbol)
+
+return lldb_symbols
+
+
+def main():
+parser = argparse.ArgumentParser(description="Generate LLDB dll exports")
+parser.add_argument(
+"-o", metavar="file", type=str, help="The name of the resultant export 
file."
+)
+parser.add_argument("--nm", help="Path to the llvm-nm executable.")
+parser.add_argument(
+"libs",
+metavar="lib",
+type=str,
+nargs="+",
+help="The libraries to extract symbols from.",
+)
+args = parser.parse_args()
+
+# Get the list of libraries to extract symbols from
+libs = list()
+for lib in args.libs:
+# When invoked by cmake the arguments are the cmake target names of the
+# libraries, so we need to add .lib/.a to the end and maybe lib to the
+# start to get the filename. Also allow objects.
+suffixes = [".lib", ".a", ".obj", ".o"]
+if not any([lib.endswith(s) for s in suffixes]):
+ 

[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb


Changes

LLDB_EXPORT_ALL_SYMBOLS is useful when building out-of-tree plugins and 
extensions that rely on LLDB's internal symbols. For example, this is how the 
Mojo language provides its REPL and debugger support.

Supporting this on windows is kind of tricky because this is normally expected 
to be done using dllexport/dllimport, but lldb uses these with the public api. 
This PR takes an approach similar to what LLVM does with 
LLVM_EXPORT_SYMBOLS_FOR_PLUGINS, and what chromium does for 
[abseil](https://github.com/chromium/chromium/blob/253d14e20fdc0cab05e5516770dceca18f9bddaf/third_party/abseil-cpp/generate_def_files.py),
 and uses a python script to extract the necessary symbols by looking at the 
symbol table for the various lldb libraries.

---
Full diff: https://github.com/llvm/llvm-project/pull/67628.diff


3 Files Affected:

- (modified) lldb/cmake/modules/LLDBConfig.cmake (+2-8) 
- (added) lldb/scripts/msvc_extract_private_symbols.py (+100) 
- (modified) lldb/source/API/CMakeLists.txt (+37) 


``diff
diff --git a/lldb/cmake/modules/LLDBConfig.cmake 
b/lldb/cmake/modules/LLDBConfig.cmake
index 19283b3cbb0194f..380016ce48015fa 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -122,14 +122,8 @@ if(APPLE AND CMAKE_GENERATOR STREQUAL Xcode)
   endif()
 endif()
 
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
-  set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
-"Causes lldb to export all symbols when building liblldb.")
-else()
-  # Windows doesn't support toggling this, so don't bother making it a
-  # cache variable.
-  set(LLDB_EXPORT_ALL_SYMBOLS 0)
-endif()
+set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
+  "Causes lldb to export all symbols when building liblldb.")
 
 if ((NOT MSVC) OR MSVC12)
   add_definitions( -DHAVE_ROUND )
diff --git a/lldb/scripts/msvc_extract_private_symbols.py 
b/lldb/scripts/msvc_extract_private_symbols.py
new file mode 100644
index 000..91ed02ffa8665f0
--- /dev/null
+++ b/lldb/scripts/msvc_extract_private_symbols.py
@@ -0,0 +1,100 @@
+"""A tool for extracting a list of private lldb symbols to export for MSVC.
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. Private symbols in LLDB don't explicitly specific dllexport, so we
+automate that by examining the symbol table.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def extract_symbols(nm_path: str, lib: str):
+"""Extract all of the private lldb symbols from the given path to llvm-nm 
and
+library to extract from."""
+
+# Matches mangled symbols containing 'lldb_private'.
+lldb_sym_re = r"0* [BT] (?P[?]+[^?].*lldb_private.*)"
+
+# '-g' means we only get global symbols.
+# '-p' do not waste time sorting the symbols.
+process = subprocess.Popen(
+[nm_path, "-g", "-p", lib],
+bufsize=1,
+stdout=subprocess.PIPE,
+stdin=subprocess.PIPE,
+universal_newlines=True,
+)
+process.stdin.close()
+
+lldb_symbols = set()
+for line in process.stdout:
+match = re.match(lldb_sym_re, line)
+if match:
+symbol = match.group("symbol")
+assert symbol.count(" ") == 0, (
+"Regex matched too much, probably got undecorated name as well"
+)
+# Deleting destructors start with ?_G or ?_E and can be discarded
+# because link.exe gives you a warning telling you they can't be
+# exported if you don't.
+if symbol.startswith("??_G") or symbol.startswith("??_E"):
+continue
+lldb_symbols.add(symbol)
+
+return lldb_symbols
+
+
+def main():
+parser = argparse.ArgumentParser(description="Generate LLDB dll exports")
+parser.add_argument(
+"-o", metavar="file", type=str, help="The name of the resultant export 
file."
+)
+parser.add_argument("--nm", help="Path to the llvm-nm executable.")
+parser.add_argument(
+"libs",
+metavar="lib",
+type=str,
+nargs="+",
+help="The libraries to extract symbols from.",
+)
+args = parser.parse_args()
+
+# Get the list of libraries to extract symbols from
+libs = list()
+for lib in args.libs:
+# When invoked by cmake the arguments are the cmake target names of the
+# libraries, so we need to add .lib/.a to the end and maybe lib to the
+# start to get the filename. Also allow objects.
+suffixes = [".lib", ".a", ".obj", ".o"]
+if not any([lib.endswith(s) for s in suffixes]):
+for s in suffixes:
+if os.path.exists(lib + s):
+lib = lib + s
+break
+if os.path.exists("lib" + lib + s):
+lib = "lib" + lib + s
+bre

[Lldb-commits] [lldb] [Clang] Fix crash when visting a fold expression in a default argument (PR #67514)

2023-09-27 Thread Shafik Yaghmour via lldb-commits

https://github.com/shafik updated 
https://github.com/llvm/llvm-project/pull/67514

>From e2e0e10e13748ba9369b73c7547c035ee75dfffa Mon Sep 17 00:00:00 2001
From: Shafik Yaghmour 
Date: Tue, 26 Sep 2023 18:55:44 -0700
Subject: [PATCH] [Clang] Fix crash when visting a fold expression in a default
 argument

CheckDefaultArgumentVisitor::Visit(...) assumes that the children of Expr will
not be NULL. This is not a valid assumption and when we have a CXXFoldExpr
the children can be NULL and this causes a crash.

Fixes: https://github.com/llvm/llvm-project/issues/67395
---
 clang/docs/ReleaseNotes.rst| 4 
 clang/lib/Sema/SemaDeclCXX.cpp | 3 ++-
 clang/test/SemaTemplate/cxx1z-fold-expressions.cpp | 8 
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8a136aae5489a8c..3a65e40b7274f5f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -357,6 +357,10 @@ Bug Fixes to C++ Support
   reference. Fixes:
   (`#64162 `_)
 
+- Fix crash when fold expression was used in the initialization of default
+  argument. Fixes:
+  (`#67395 `_)
+
 Bug Fixes to AST Handling
 ^
 - Fixed an import failure of recursive friend class template.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0091e0ecf6f3986..302e944d5d74f1c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -86,7 +86,8 @@ class CheckDefaultArgumentVisitor
 bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
   bool IsInvalid = false;
   for (const Stmt *SubStmt : Node->children())
-IsInvalid |= Visit(SubStmt);
+if (SubStmt)
+  IsInvalid |= Visit(SubStmt);
   return IsInvalid;
 }
 
diff --git a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp 
b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
index 518eaf0e05239e0..47a252eb335f6e5 100644
--- a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
+++ b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp
@@ -124,3 +124,11 @@ namespace PR30738 {
   int test_h3 = h(1, 2, 3);
   N::S test_h4 = h(N::S(), N::S(), N::S()); // expected-note 
{{instantiation of}}
 }
+
+namespace GH67395 {
+template 
+bool f();
+
+template 
+void g(bool = (f() || ...));
+}

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)

2023-09-27 Thread Greg Clayton via lldb-commits

clayborg wrote:

I am implementing the fixes in the LanguageRuntime stuff. I have it working. 
Stay tuned to updates to this patch.

https://github.com/llvm/llvm-project/pull/67599
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread Walter Erquinigo via lldb-commits

https://github.com/walter-erquinigo approved this pull request.

Other than a few nits, this is awesome!

https://github.com/llvm/llvm-project/pull/67628
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread Walter Erquinigo via lldb-commits

https://github.com/walter-erquinigo edited 
https://github.com/llvm/llvm-project/pull/67628
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread Walter Erquinigo via lldb-commits


@@ -0,0 +1,100 @@
+"""A tool for extracting a list of private lldb symbols to export for MSVC.
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. Private symbols in LLDB don't explicitly specific dllexport, so we
+automate that by examining the symbol table.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def extract_symbols(nm_path: str, lib: str):
+"""Extract all of the private lldb symbols from the given path to llvm-nm 
and
+library to extract from."""
+
+# Matches mangled symbols containing 'lldb_private'.
+lldb_sym_re = r"0* [BT] (?P[?]+[^?].*lldb_private.*)"
+
+# '-g' means we only get global symbols.
+# '-p' do not waste time sorting the symbols.
+process = subprocess.Popen(
+[nm_path, "-g", "-p", lib],
+bufsize=1,
+stdout=subprocess.PIPE,
+stdin=subprocess.PIPE,
+universal_newlines=True,
+)
+process.stdin.close()
+
+lldb_symbols = set()
+for line in process.stdout:
+match = re.match(lldb_sym_re, line)
+if match:
+symbol = match.group("symbol")
+assert symbol.count(" ") == 0, (
+"Regex matched too much, probably got undecorated name as well"
+)
+# Deleting destructors start with ?_G or ?_E and can be discarded
+# because link.exe gives you a warning telling you they can't be
+# exported if you don't.
+if symbol.startswith("??_G") or symbol.startswith("??_E"):
+continue
+lldb_symbols.add(symbol)
+
+return lldb_symbols
+
+
+def main():
+parser = argparse.ArgumentParser(description="Generate LLDB dll exports")
+parser.add_argument(
+"-o", metavar="file", type=str, help="The name of the resultant export 
file."
+)
+parser.add_argument("--nm", help="Path to the llvm-nm executable.")
+parser.add_argument(
+"libs",
+metavar="lib",
+type=str,
+nargs="+",
+help="The libraries to extract symbols from.",
+)
+args = parser.parse_args()
+
+# Get the list of libraries to extract symbols from
+libs = list()
+for lib in args.libs:
+# When invoked by cmake the arguments are the cmake target names of the
+# libraries, so we need to add .lib/.a to the end and maybe lib to the
+# start to get the filename. Also allow objects.
+suffixes = [".lib", ".a", ".obj", ".o"]
+if not any([lib.endswith(s) for s in suffixes]):
+for s in suffixes:
+if os.path.exists(lib + s):
+lib = lib + s
+break
+if os.path.exists("lib" + lib + s):
+lib = "lib" + lib + s
+break

walter-erquinigo wrote:

I'd rewrite this like 
```suggestion
for suffix in suffixes:
   for path in [lib + suffix, "lib" + lib + suffix]:
 if os.path.exists(path):
   lib = path
   break
```

https://github.com/llvm/llvm-project/pull/67628
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)

2023-09-27 Thread Walter Erquinigo via lldb-commits


@@ -0,0 +1,100 @@
+"""A tool for extracting a list of private lldb symbols to export for MSVC.
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. Private symbols in LLDB don't explicitly specific dllexport, so we
+automate that by examining the symbol table.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def extract_symbols(nm_path: str, lib: str):
+"""Extract all of the private lldb symbols from the given path to llvm-nm 
and
+library to extract from."""
+
+# Matches mangled symbols containing 'lldb_private'.
+lldb_sym_re = r"0* [BT] (?P[?]+[^?].*lldb_private.*)"
+
+# '-g' means we only get global symbols.
+# '-p' do not waste time sorting the symbols.
+process = subprocess.Popen(
+[nm_path, "-g", "-p", lib],
+bufsize=1,
+stdout=subprocess.PIPE,
+stdin=subprocess.PIPE,
+universal_newlines=True,
+)
+process.stdin.close()
+
+lldb_symbols = set()
+for line in process.stdout:
+match = re.match(lldb_sym_re, line)
+if match:
+symbol = match.group("symbol")
+assert symbol.count(" ") == 0, (
+"Regex matched too much, probably got undecorated name as well"
+)
+# Deleting destructors start with ?_G or ?_E and can be discarded
+# because link.exe gives you a warning telling you they can't be
+# exported if you don't.
+if symbol.startswith("??_G") or symbol.startswith("??_E"):
+continue
+lldb_symbols.add(symbol)
+
+return lldb_symbols
+
+
+def main():
+parser = argparse.ArgumentParser(description="Generate LLDB dll exports")
+parser.add_argument(
+"-o", metavar="file", type=str, help="The name of the resultant export 
file."
+)
+parser.add_argument("--nm", help="Path to the llvm-nm executable.")
+parser.add_argument(
+"libs",
+metavar="lib",
+type=str,
+nargs="+",
+help="The libraries to extract symbols from.",
+)
+args = parser.parse_args()
+
+# Get the list of libraries to extract symbols from
+libs = list()
+for lib in args.libs:
+# When invoked by cmake the arguments are the cmake target names of the
+# libraries, so we need to add .lib/.a to the end and maybe lib to the
+# start to get the filename. Also allow objects.
+suffixes = [".lib", ".a", ".obj", ".o"]
+if not any([lib.endswith(s) for s in suffixes]):
+for s in suffixes:
+if os.path.exists(lib + s):
+lib = lib + s
+break
+if os.path.exists("lib" + lib + s):
+lib = "lib" + lib + s
+break
+if not any([lib.endswith(s) for s in suffixes]):
+print("Don't know what to do with argument " + lib, 
file=sys.stderr)

walter-erquinigo wrote:

you could make this error more precise

https://github.com/llvm/llvm-project/pull/67628
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] 34ee53c - [lldb][test] Fix TestCallBuiltinFunction.py

2023-09-27 Thread Fangrui Song via lldb-commits

Author: Fangrui Song
Date: 2023-09-27T22:37:24-07:00
New Revision: 34ee53c9e390019d757b453ceba9cc3e47ab0df1

URL: 
https://github.com/llvm/llvm-project/commit/34ee53c9e390019d757b453ceba9cc3e47ab0df1
DIFF: 
https://github.com/llvm/llvm-project/commit/34ee53c9e390019d757b453ceba9cc3e47ab0df1.diff

LOG: [lldb][test] Fix TestCallBuiltinFunction.py

A constant __builtin_abs(-14) cannot be evaluated without a running target
as Clang now emits llvm.abs.*

Added: 


Modified: 
lldb/test/API/commands/expression/call-function/TestCallBuiltinFunction.py

Removed: 




diff  --git 
a/lldb/test/API/commands/expression/call-function/TestCallBuiltinFunction.py 
b/lldb/test/API/commands/expression/call-function/TestCallBuiltinFunction.py
index 1f79aae139a7bf3..80163147650a0f4 100644
--- a/lldb/test/API/commands/expression/call-function/TestCallBuiltinFunction.py
+++ b/lldb/test/API/commands/expression/call-function/TestCallBuiltinFunction.py
@@ -23,4 +23,3 @@ def test(self):
 "__builtin_isnormal(0.0f)", result_type="int", result_value="0"
 )
 self.expect_expr("__builtin_constant_p(1)", result_type="int", 
result_value="1")
-self.expect_expr("__builtin_abs(-14)", result_type="int", 
result_value="14")



___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits