[Lldb-commits] [lldb] ec8df0c - [LLDB] Skip TestTlsGlobals.py for Linux Arm/AArch64
Author: Muhammad Omair Javaid Date: 2023-09-28T16:16:41+05:00 New Revision: ec8df0c7e3a3d9e6352a3d8c5c4540a9d0352ca0 URL: https://github.com/llvm/llvm-project/commit/ec8df0c7e3a3d9e6352a3d8c5c4540a9d0352ca0 DIFF: https://github.com/llvm/llvm-project/commit/ec8df0c7e3a3d9e6352a3d8c5c4540a9d0352ca0.diff LOG: [LLDB] Skip TestTlsGlobals.py for Linux Arm/AArch64 Recently added TLS linux support fails on Arm/AArch64. I am skiping test for now and will investigate the issue later. Added: Modified: lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py Removed: diff --git a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py index a853b284c2cce4d..dfe29b451df0a66 100644 --- a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py +++ b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py @@ -38,6 +38,7 @@ def setUp(self): # TLS works diff erently on Windows, this would need to be implemented # separately. @skipIfWindows +@skipIf(oslist=["linux"], archs=["arm", "aarch64"]) @skipIf(oslist=no_match([lldbplatformutil.getDarwinOSTriples(), "linux"])) def test(self): """Test thread-local storage.""" ___ 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)
junior-jl wrote: I understand, thank you, Jim. Is there anything else I should change in this PR? 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] Support target names with dots in more utilities (PR #65812)
https://github.com/dankm updated https://github.com/llvm/llvm-project/pull/65812 >From 5f5e57a5c01088e7f0b9276ed02dd436a3f9cc0a Mon Sep 17 00:00:00 2001 From: Dan McGregor Date: Mon, 14 Aug 2023 18:44:08 -0600 Subject: [PATCH 1/3] Support: hoist lld's executable name code to Path Instead of using custom code to find the program name throughout the codebase, write one function as a path helper to consistently determine the program name. This globally correctly finds target names with dots in them (ie freebsd13.2). --- lld/COFF/Driver.cpp| 2 +- lld/Common/Args.cpp| 6 -- lld/ELF/Driver.cpp | 2 +- lld/MachO/Driver.cpp | 2 +- lld/include/lld/Common/Args.h | 2 -- lld/wasm/Driver.cpp| 2 +- lldb/tools/driver/Driver.cpp | 2 +- llvm/include/llvm/Support/Path.h | 15 +++ llvm/lib/Support/Path.cpp | 7 +++ llvm/tools/llvm-ar/llvm-ar.cpp | 3 ++- llvm/tools/llvm-cov/llvm-cov.cpp | 2 +- llvm/tools/llvm-driver/llvm-driver.cpp | 2 +- llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 2 +- llvm/tools/llvm-objdump/llvm-objdump.cpp | 2 +- llvm/tools/llvm-rc/llvm-rc.cpp | 2 +- llvm/tools/llvm-readobj/llvm-readobj.cpp | 2 +- llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 2 +- 17 files changed, 36 insertions(+), 21 deletions(-) diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index d7476e91e03e384..03a63bf3a306b4d 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -68,7 +68,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, auto *ctx = new COFFLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now" " (use /errorlimit:0 to see all errors)"; diff --git a/lld/Common/Args.cpp b/lld/Common/Args.cpp index 48c934df3a2c931..b02d023fe19aeb5 100644 --- a/lld/Common/Args.cpp +++ b/lld/Common/Args.cpp @@ -85,9 +85,3 @@ std::vector lld::args::getLines(MemoryBufferRef mb) { } return ret; } - -StringRef lld::args::getFilenameWithoutExe(StringRef path) { - if (path.ends_with_insensitive(".exe")) -return sys::path::stem(path); - return sys::path::filename(path); -} diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 9d167293574fa64..957d0da1589caf8 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -143,7 +143,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, SharedFile::vernauxNum = 0; }; - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " "--error-limit=0 to see all errors)"; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index 00ff3439a043be9..ed0b66d4b2ec6ba 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1428,7 +1428,7 @@ bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, InputFile::resetIdCount(); }; - ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]); + ctx->e.logName = sys::path::program_name(argsArr[0]); MachOOptTable parser; InputArgList args = parser.parse(argsArr.slice(1)); diff --git a/lld/include/lld/Common/Args.h b/lld/include/lld/Common/Args.h index 60f83fbbbf1a3c9..8822707a6a1f212 100644 --- a/lld/include/lld/Common/Args.h +++ b/lld/include/lld/Common/Args.h @@ -38,8 +38,6 @@ uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key, std::vector getLines(MemoryBufferRef mb); -StringRef getFilenameWithoutExe(StringRef path); - } // namespace args } // namespace lld diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index c2f5f0185781f36..f13aa520f35b100 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -89,7 +89,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, auto *ctx = new CommonLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index f8058f868d53ffe..2fb760ca97a001d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -754,7 +754,7 @@ int main(int argc, char const *argv[]) { ArrayRef arg_arr = ArrayRef(argv + 1, argc - 1); opt::InputArgList input_args = T.ParseArgs(arg_arr, MissingA
[Lldb-commits] [lldb] Support target names with dots in more utilities (PR #65812)
https://github.com/dankm resolved 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] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)
https://github.com/River707 resolved 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)
https://github.com/River707 resolved 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)
https://github.com/River707 unresolved 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] Support target names with dots in more utilities (PR #65812)
https://github.com/dankm updated https://github.com/llvm/llvm-project/pull/65812 >From 5f5e57a5c01088e7f0b9276ed02dd436a3f9cc0a Mon Sep 17 00:00:00 2001 From: Dan McGregor Date: Mon, 14 Aug 2023 18:44:08 -0600 Subject: [PATCH 1/4] Support: hoist lld's executable name code to Path Instead of using custom code to find the program name throughout the codebase, write one function as a path helper to consistently determine the program name. This globally correctly finds target names with dots in them (ie freebsd13.2). --- lld/COFF/Driver.cpp| 2 +- lld/Common/Args.cpp| 6 -- lld/ELF/Driver.cpp | 2 +- lld/MachO/Driver.cpp | 2 +- lld/include/lld/Common/Args.h | 2 -- lld/wasm/Driver.cpp| 2 +- lldb/tools/driver/Driver.cpp | 2 +- llvm/include/llvm/Support/Path.h | 15 +++ llvm/lib/Support/Path.cpp | 7 +++ llvm/tools/llvm-ar/llvm-ar.cpp | 3 ++- llvm/tools/llvm-cov/llvm-cov.cpp | 2 +- llvm/tools/llvm-driver/llvm-driver.cpp | 2 +- llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 2 +- llvm/tools/llvm-objdump/llvm-objdump.cpp | 2 +- llvm/tools/llvm-rc/llvm-rc.cpp | 2 +- llvm/tools/llvm-readobj/llvm-readobj.cpp | 2 +- llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 2 +- 17 files changed, 36 insertions(+), 21 deletions(-) diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index d7476e91e03e384..03a63bf3a306b4d 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -68,7 +68,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, auto *ctx = new COFFLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now" " (use /errorlimit:0 to see all errors)"; diff --git a/lld/Common/Args.cpp b/lld/Common/Args.cpp index 48c934df3a2c931..b02d023fe19aeb5 100644 --- a/lld/Common/Args.cpp +++ b/lld/Common/Args.cpp @@ -85,9 +85,3 @@ std::vector lld::args::getLines(MemoryBufferRef mb) { } return ret; } - -StringRef lld::args::getFilenameWithoutExe(StringRef path) { - if (path.ends_with_insensitive(".exe")) -return sys::path::stem(path); - return sys::path::filename(path); -} diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 9d167293574fa64..957d0da1589caf8 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -143,7 +143,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, SharedFile::vernauxNum = 0; }; - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " "--error-limit=0 to see all errors)"; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index 00ff3439a043be9..ed0b66d4b2ec6ba 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1428,7 +1428,7 @@ bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, InputFile::resetIdCount(); }; - ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]); + ctx->e.logName = sys::path::program_name(argsArr[0]); MachOOptTable parser; InputArgList args = parser.parse(argsArr.slice(1)); diff --git a/lld/include/lld/Common/Args.h b/lld/include/lld/Common/Args.h index 60f83fbbbf1a3c9..8822707a6a1f212 100644 --- a/lld/include/lld/Common/Args.h +++ b/lld/include/lld/Common/Args.h @@ -38,8 +38,6 @@ uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key, std::vector getLines(MemoryBufferRef mb); -StringRef getFilenameWithoutExe(StringRef path); - } // namespace args } // namespace lld diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index c2f5f0185781f36..f13aa520f35b100 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -89,7 +89,7 @@ bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, auto *ctx = new CommonLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); + ctx->e.logName = sys::path::program_name(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index f8058f868d53ffe..2fb760ca97a001d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -754,7 +754,7 @@ int main(int argc, char const *argv[]) { ArrayRef arg_arr = ArrayRef(argv + 1, argc - 1); opt::InputArgList input_args = T.ParseArgs(arg_arr, MissingA
[Lldb-commits] [lldb] [lldb] Add windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)
@@ -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 River707 wrote: Tried this, but it actually ends up being a bit more convoluted because there are two loops to break from instead of just one (either need to recheck the suffix, or use the weird `else` after for loop + continue/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 stop-at-user-entry option to process launch (PR #67019)
=?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior Message-ID: In-Reply-To: https://github.com/jimingham approved this pull request. Other than that trivial doc style comment, this LGTM. 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)
=?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: @@ -38,7 +39,37 @@ 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::set entryPointNamesSet; +for (LanguageType lang_type : Language::GetSupportedLanguages()) { + Language *lang = Language::FindPlugin(lang_type); + if (lang) { +std::string entryPointName = lang->GetUserEntryPointName(); +if (!entryPointName.empty()) + entryPointNamesSet.insert(entryPointName); + } +} +std::vector entryPointNames(entryPointNamesSet.begin(), + entryPointNamesSet.end()); +BreakpointSP bp_sp = target_sp->CreateBreakpoint( +/*containingModules=*/&shared_lib_filter, jimingham wrote: We tend to put this sort of doc comment after the variable rather than before, and don't put it on arguments where the variable name being passed (e.g. `shared_lib_filter`) is self-documenting. 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)
=?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: https://github.com/jimingham edited 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)
@@ -38,7 +39,37 @@ 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::set entryPointNamesSet; +for (LanguageType lang_type : Language::GetSupportedLanguages()) { + Language *lang = Language::FindPlugin(lang_type); + if (lang) { +std::string entryPointName = lang->GetUserEntryPointName(); +if (!entryPointName.empty()) + entryPointNamesSet.insert(entryPointName); + } +} +std::vector entryPointNames(entryPointNamesSet.begin(), + entryPointNamesSet.end()); +BreakpointSP bp_sp = target_sp->CreateBreakpoint( +/*containingModules=*/&shared_lib_filter, junior-jl wrote: You mean like this? ```cpp BreakpointSP bp_sp = target_sp->CreateBreakpoint( &shared_lib_filter, nullptr, // containingSourceFiles entryPointNames, eFunctionNameTypeFull, // func_name_type_mask eLanguageTypeUnknown,// language 0, // offset eLazyBoolNo, // skip_prologue false// internal false// hardware ); ``` 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 windows support for LLDB_EXPORT_ALL_SYMBOLS (PR #67628)
https://github.com/River707 updated https://github.com/llvm/llvm-project/pull/67628 >From da965dd04c810f0bde7ed3353f13ce5d7d064d88 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 | 102 +++ lldb/source/API/CMakeLists.txt | 37 +++ 3 files changed, 141 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..05e8b0e2095ca33 --- /dev/null +++ b/lldb/scripts/msvc_extract_private_symbols.py @@ -0,0 +1,102 @@ +"""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 stop-at-user-entry option to process launch (PR #67019)
=?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: @@ -38,7 +39,37 @@ 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::set entryPointNamesSet; +for (LanguageType lang_type : Language::GetSupportedLanguages()) { + Language *lang = Language::FindPlugin(lang_type); + if (lang) { +std::string entryPointName = lang->GetUserEntryPointName(); +if (!entryPointName.empty()) + entryPointNamesSet.insert(entryPointName); + } +} +std::vector entryPointNames(entryPointNamesSet.begin(), Michael137 wrote: Feel free to ignore llvm has a `SetVector` type that you could consider using here (it allows you to specify the underlying `vector` container too; then calling `SetVector::takeVector()` will give you the container) 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)
=?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior , =?utf-8?q?Jos=C3=A9?= L. Junior Message-ID: In-Reply-To: @@ -38,7 +39,37 @@ 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::set entryPointNamesSet; +for (LanguageType lang_type : Language::GetSupportedLanguages()) { + Language *lang = Language::FindPlugin(lang_type); + if (lang) { +std::string entryPointName = lang->GetUserEntryPointName(); +if (!entryPointName.empty()) + entryPointNamesSet.insert(entryPointName); + } +} +std::vector entryPointNames(entryPointNamesSet.begin(), + entryPointNamesSet.end()); +BreakpointSP bp_sp = target_sp->CreateBreakpoint( +/*containingModules=*/&shared_lib_filter, jimingham wrote: Yes. 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)
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/67599 >From 8fa9aae354ac455f4ea443de1bb5f753fe93fb51 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Wed, 27 Sep 2023 13:03:40 -0700 Subject: [PATCH 1/2] 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 ``` --- lldb/include/lldb/API/SBValue.h | 28 ++ lldb/include/lldb/Core/ValueObject.h | 4 + lldb/include/lldb/Core/ValueObjectChild.h | 1 + lldb/include/lldb/Core/ValueObjectVTable.h| 65 lldb/include/lldb/Symbol/TypeSystem.h | 4 + lldb/include/lldb/lldb-enumerations.h | 4 +- lldb/source/API/SBValue.cpp | 17 +- lldb/source/Commands/CommandObjectFrame.cpp | 2 + lldb/source/Core/CMakeLists.txt | 1 + lldb/source/Core/ValueObject.cpp | 5 + lldb/source/Core/ValueObjectVTable.cpp| 325 ++ .../DataFormatters/CXXFunctionPointer.cpp | 6 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 4 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 +- .../TypeSystem/Clang/TypeSystemClang.h| 4 + lldb/test/API/functionalities/vtable/Makefile | 3 + .../functionalities/vtable/TestVTableValue.py | 135 lldb/test/API/functionalities/vtable/main.cpp | 37 ++ 18 files changed, 664 insertions(+), 7 deletions(-) create mode 100644 lldb/include/lldb/Core/ValueObjectVTable.h create mode 100644 lldb/source/Core/ValueObjectVTable.cpp create mode 100644 lldb/test/API/functionalities/vtable/Makefile create mode 100644 lldb/test/API/functionalities/vtable/TestVTableValue.py create mode 100644 lldb/test/API/functionalities/vtable/main.cpp 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. + /// + /// SBValu
[Lldb-commits] [lldb] [InstCombine] Canonicalize `and(zext(A), B)` into `select A, B & 1, 0` (PR #66740)
https://github.com/dtcxzyw closed https://github.com/llvm/llvm-project/pull/66740 ___ 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)
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/67599 >From 8fa9aae354ac455f4ea443de1bb5f753fe93fb51 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Wed, 27 Sep 2023 13:03:40 -0700 Subject: [PATCH 1/3] 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 ``` --- lldb/include/lldb/API/SBValue.h | 28 ++ lldb/include/lldb/Core/ValueObject.h | 4 + lldb/include/lldb/Core/ValueObjectChild.h | 1 + lldb/include/lldb/Core/ValueObjectVTable.h| 65 lldb/include/lldb/Symbol/TypeSystem.h | 4 + lldb/include/lldb/lldb-enumerations.h | 4 +- lldb/source/API/SBValue.cpp | 17 +- lldb/source/Commands/CommandObjectFrame.cpp | 2 + lldb/source/Core/CMakeLists.txt | 1 + lldb/source/Core/ValueObject.cpp | 5 + lldb/source/Core/ValueObjectVTable.cpp| 325 ++ .../DataFormatters/CXXFunctionPointer.cpp | 6 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 4 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 +- .../TypeSystem/Clang/TypeSystemClang.h| 4 + lldb/test/API/functionalities/vtable/Makefile | 3 + .../functionalities/vtable/TestVTableValue.py | 135 lldb/test/API/functionalities/vtable/main.cpp | 37 ++ 18 files changed, 664 insertions(+), 7 deletions(-) create mode 100644 lldb/include/lldb/Core/ValueObjectVTable.h create mode 100644 lldb/source/Core/ValueObjectVTable.cpp create mode 100644 lldb/test/API/functionalities/vtable/Makefile create mode 100644 lldb/test/API/functionalities/vtable/TestVTableValue.py create mode 100644 lldb/test/API/functionalities/vtable/main.cpp 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. + /// + /// SBValu
[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
https://github.com/clayborg 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)
@@ -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)
https://github.com/clayborg commented: Ok. I have address all review comments. Jim, please take a look at the LanguageRuntime changes to see if you agree on how I did things. Things factored out quite nicely I believe. 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][NFCI] Move functionality for getting unsupported DW_FORM values (PR #67579)
https://github.com/bulbazord closed 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] 36a5183 - [lldb][NFCI] Move functionality for getting unsupported DW_FORM values (#67579)
Author: Alex Langford Date: 2023-09-28T12:18:08-07:00 New Revision: 36a518317fdaab377830f8d18ead9301b06e9e8d URL: https://github.com/llvm/llvm-project/commit/36a518317fdaab377830f8d18ead9301b06e9e8d DIFF: https://github.com/llvm/llvm-project/commit/36a518317fdaab377830f8d18ead9301b06e9e8d.diff LOG: [lldb][NFCI] Move functionality for getting unsupported DW_FORM values (#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. Added: Modified: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Removed: 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 = ___ lldb
[Lldb-commits] [lldb] [Clang] Fix crash when visting a fold expression in a default argument (PR #67514)
https://github.com/shafik closed https://github.com/llvm/llvm-project/pull/67514 ___ 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)
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)
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)
@@ -0,0 +1,298 @@ +//===-- 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/Target/Language.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private-enumerations.h" + +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 { +if (ValueObject *parent = GetParent()) + 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; +} + + +// 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 = nullptr; +Address resolved_vfunc_ptr_address; +target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address); +if (resolved_vfunc_ptr_address.IsValid()) + function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction(); +if (function) { + m_value.SetCompilerType(function->GetCompilerType().GetPointerType()); +} 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. + + // Get the original type that this vtable is based off of so we can get + // the language from it correctly. + ValueObject *val = parent->GetParent(); + auto type_system = target_sp->GetScratchTypeSystemForLanguage( +val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus); + if (type_system) { +m_value.SetCompilerType( +(*type_system)->CreateGenericFunctionPrototype().GetPointerType()); + } else { +consumeError(type_system.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(); + }; + + const
[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -54,134 +54,182 @@ bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { check_objc); } -TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( -ValueObject &in_value, lldb::addr_t original_ptr, -lldb::addr_t vtable_load_addr) { - if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { -// Find the symbol that contains the "vtable_load_addr" address -Address vtable_addr; -Target &target = m_process->GetTarget(); -if (!target.GetSectionLoadList().IsEmpty()) { - if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, - vtable_addr)) { -// See if we have cached info for this type already -TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); -if (type_info) - return type_info; - -SymbolContext sc; -target.GetImages().ResolveSymbolContextForAddress( -vtable_addr, eSymbolContextSymbol, sc); -Symbol *symbol = sc.symbol; -if (symbol != nullptr) { - const char *name = - symbol->GetMangled().GetDemangledName().AsCString(); - if (name && strstr(name, vtable_demangled_prefix) == name) { -Log *log = GetLog(LLDBLog::Object); -LLDB_LOGF(log, - "0x%16.16" PRIx64 - ": static-type = '%s' has vtable symbol '%s'\n", - original_ptr, in_value.GetTypeName().GetCString(), name); -// We are a C++ class, that's good. Get the class name and look it -// up: -const char *class_name = name + strlen(vtable_demangled_prefix); -// We know the class name is absolute, so tell FindTypes that by -// prefixing it with the root namespace: -std::string lookup_name("::"); -lookup_name.append(class_name); - -type_info.SetName(class_name); -const bool exact_match = true; -TypeList class_types; - -// First look in the module that the vtable symbol came from and -// look for a single exact match. -llvm::DenseSet searched_symbol_files; -if (sc.module_sp) - sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, +TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfo( +ValueObject &in_value, const VTableInfo &vtable_info) { + if (vtable_info.addr.IsSectionOffset()) { +// See if we have cached info for this type already +TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr); +if (type_info) + return type_info; + +if (vtable_info.symbol) { + Log *log = GetLog(LLDBLog::Object); + llvm::StringRef symbol_name = + vtable_info.symbol->GetMangled().GetDemangledName().GetStringRef(); + LLDB_LOGF(log, +"0x%16.16" PRIx64 +": static-type = '%s' has vtable symbol '%s'\n", +in_value.GetPointerValue(), +in_value.GetTypeName().GetCString(), +symbol_name.str().c_str()); + // We are a C++ class, that's good. Get the class name and look it + // up: + llvm::StringRef class_name = symbol_name; + class_name.consume_front(vtable_demangled_prefix); + // We know the class name is absolute, so tell FindTypes that by + // prefixing it with the root namespace: + std::string lookup_name("::"); + lookup_name.append(class_name.data(), class_name.size()); + + type_info.SetName(class_name); + const bool exact_match = true; + TypeList class_types; + + // First look in the module that the vtable symbol came from and + // look for a single exact match. + llvm::DenseSet searched_symbol_files; + ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule(); + if (module_sp) +module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, + searched_symbol_files, class_types); + + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible + Target &target = m_process->GetTarget(); + if (class_types.Empty()) +target.GetImages().FindTypes(nullptr, ConstString(lookup_name), + exact_match, UINT32_MAX, searched_symbol_files, class_types); -// If we didn't find a symbol, then move on to the entire module -// list in the target and get as many unique matches as possible -if (class_types.Empty()) - target.GetImages().FindTypes(nullptr, ConstString(lookup_name), - exact_match, UINT32_MAX, - searched_symbol_files,
[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
https://github.com/jimingham commented: This is much nicer looking! I had a couple small comments about apportioning duties between the ValueObjectVTable::Update and the GetVTableInfo in the comments. It doesn't look like you handled corrupted tables yet? Are you still intending to do that? Another thing it might be good to test - though from what you've done it should indeed work is if I have: BaseClass Foo my_foo = FirstChildOfFoo(); // Stop after this line and do `vtbl = frame.FindVariable("my_foo").GetVTable()` and check the vtable has the right functions for FirstChildOfFoo() my_foo = SecondChildOfFoo(); // Stop after this line and check the `vtbl` variable again, it should now have the functions for SecondChildOfFoo... That will make sure both that we notice the change in the parent & update the vtable appropriately, and that we don't mess up the memory management, such that holding onto just the vtable child doesn't keep the whole tree valid. 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)
@@ -0,0 +1,298 @@ +//===-- 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/Target/Language.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private-enumerations.h" + +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 { +if (ValueObject *parent = GetParent()) + 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; +} + + +// 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 = nullptr; +Address resolved_vfunc_ptr_address; +target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address); +if (resolved_vfunc_ptr_address.IsValid()) + function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction(); +if (function) { + m_value.SetCompilerType(function->GetCompilerType().GetPointerType()); +} 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. + + // Get the original type that this vtable is based off of so we can get + // the language from it correctly. + ValueObject *val = parent->GetParent(); + auto type_system = target_sp->GetScratchTypeSystemForLanguage( +val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus); + if (type_system) { +m_value.SetCompilerType( +(*type_system)->CreateGenericFunctionPrototype().GetPointerType()); + } else { +consumeError(type_system.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(); + }; + + const
[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -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)
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)
@@ -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: Sounds good 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)
@@ -0,0 +1,298 @@ +//===-- 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/Target/Language.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private-enumerations.h" + +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 { +if (ValueObject *parent = GetParent()) + 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; +} + + +// 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 = nullptr; +Address resolved_vfunc_ptr_address; +target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address); +if (resolved_vfunc_ptr_address.IsValid()) + function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction(); +if (function) { + m_value.SetCompilerType(function->GetCompilerType().GetPointerType()); +} 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. + + // Get the original type that this vtable is based off of so we can get + // the language from it correctly. + ValueObject *val = parent->GetParent(); + auto type_system = target_sp->GetScratchTypeSystemForLanguage( +val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus); + if (type_system) { +m_value.SetCompilerType( +(*type_system)->CreateGenericFunctionPrototype().GetPointerType()); + } else { +consumeError(type_system.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(); + }; + + const
[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -54,134 +54,182 @@ bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { check_objc); } -TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( -ValueObject &in_value, lldb::addr_t original_ptr, -lldb::addr_t vtable_load_addr) { - if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { -// Find the symbol that contains the "vtable_load_addr" address -Address vtable_addr; -Target &target = m_process->GetTarget(); -if (!target.GetSectionLoadList().IsEmpty()) { - if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, - vtable_addr)) { -// See if we have cached info for this type already -TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); -if (type_info) - return type_info; - -SymbolContext sc; -target.GetImages().ResolveSymbolContextForAddress( -vtable_addr, eSymbolContextSymbol, sc); -Symbol *symbol = sc.symbol; -if (symbol != nullptr) { - const char *name = - symbol->GetMangled().GetDemangledName().AsCString(); - if (name && strstr(name, vtable_demangled_prefix) == name) { -Log *log = GetLog(LLDBLog::Object); -LLDB_LOGF(log, - "0x%16.16" PRIx64 - ": static-type = '%s' has vtable symbol '%s'\n", - original_ptr, in_value.GetTypeName().GetCString(), name); -// We are a C++ class, that's good. Get the class name and look it -// up: -const char *class_name = name + strlen(vtable_demangled_prefix); -// We know the class name is absolute, so tell FindTypes that by -// prefixing it with the root namespace: -std::string lookup_name("::"); -lookup_name.append(class_name); - -type_info.SetName(class_name); -const bool exact_match = true; -TypeList class_types; - -// First look in the module that the vtable symbol came from and -// look for a single exact match. -llvm::DenseSet searched_symbol_files; -if (sc.module_sp) - sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, +TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfo( +ValueObject &in_value, const VTableInfo &vtable_info) { + if (vtable_info.addr.IsSectionOffset()) { +// See if we have cached info for this type already +TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr); +if (type_info) + return type_info; + +if (vtable_info.symbol) { + Log *log = GetLog(LLDBLog::Object); + llvm::StringRef symbol_name = + vtable_info.symbol->GetMangled().GetDemangledName().GetStringRef(); + LLDB_LOGF(log, +"0x%16.16" PRIx64 +": static-type = '%s' has vtable symbol '%s'\n", +in_value.GetPointerValue(), +in_value.GetTypeName().GetCString(), +symbol_name.str().c_str()); + // We are a C++ class, that's good. Get the class name and look it + // up: + llvm::StringRef class_name = symbol_name; + class_name.consume_front(vtable_demangled_prefix); + // We know the class name is absolute, so tell FindTypes that by + // prefixing it with the root namespace: + std::string lookup_name("::"); + lookup_name.append(class_name.data(), class_name.size()); + + type_info.SetName(class_name); + const bool exact_match = true; + TypeList class_types; + + // First look in the module that the vtable symbol came from and + // look for a single exact match. + llvm::DenseSet searched_symbol_files; + ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule(); + if (module_sp) +module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, + searched_symbol_files, class_types); + + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible + Target &target = m_process->GetTarget(); + if (class_types.Empty()) +target.GetImages().FindTypes(nullptr, ConstString(lookup_name), + exact_match, UINT32_MAX, searched_symbol_files, class_types); -// If we didn't find a symbol, then move on to the entire module -// list in the target and get as many unique matches as possible -if (class_types.Empty()) - target.GetImages().FindTypes(nullptr, ConstString(lookup_name), - exact_match, UINT32_MAX, - searched_symbol_files,
[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)
emaste wrote: > I will let other FreeBSD folks do the final approval since I don't work on > FreeBSD. @clayborg this change LGTM for FreeBSD. I'm still not fully sorted on the approach for landing the commits post transition to GitHub. Also see the comment about author name above. 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] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -54,134 +54,182 @@ bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { check_objc); } -TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( -ValueObject &in_value, lldb::addr_t original_ptr, -lldb::addr_t vtable_load_addr) { - if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { -// Find the symbol that contains the "vtable_load_addr" address -Address vtable_addr; -Target &target = m_process->GetTarget(); -if (!target.GetSectionLoadList().IsEmpty()) { - if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, - vtable_addr)) { -// See if we have cached info for this type already -TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); -if (type_info) - return type_info; - -SymbolContext sc; -target.GetImages().ResolveSymbolContextForAddress( -vtable_addr, eSymbolContextSymbol, sc); -Symbol *symbol = sc.symbol; -if (symbol != nullptr) { - const char *name = - symbol->GetMangled().GetDemangledName().AsCString(); - if (name && strstr(name, vtable_demangled_prefix) == name) { -Log *log = GetLog(LLDBLog::Object); -LLDB_LOGF(log, - "0x%16.16" PRIx64 - ": static-type = '%s' has vtable symbol '%s'\n", - original_ptr, in_value.GetTypeName().GetCString(), name); -// We are a C++ class, that's good. Get the class name and look it -// up: -const char *class_name = name + strlen(vtable_demangled_prefix); -// We know the class name is absolute, so tell FindTypes that by -// prefixing it with the root namespace: -std::string lookup_name("::"); -lookup_name.append(class_name); - -type_info.SetName(class_name); -const bool exact_match = true; -TypeList class_types; - -// First look in the module that the vtable symbol came from and -// look for a single exact match. -llvm::DenseSet searched_symbol_files; -if (sc.module_sp) - sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, +TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfo( +ValueObject &in_value, const VTableInfo &vtable_info) { + if (vtable_info.addr.IsSectionOffset()) { +// See if we have cached info for this type already +TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr); +if (type_info) + return type_info; + +if (vtable_info.symbol) { + Log *log = GetLog(LLDBLog::Object); + llvm::StringRef symbol_name = + vtable_info.symbol->GetMangled().GetDemangledName().GetStringRef(); + LLDB_LOGF(log, +"0x%16.16" PRIx64 +": static-type = '%s' has vtable symbol '%s'\n", +in_value.GetPointerValue(), +in_value.GetTypeName().GetCString(), +symbol_name.str().c_str()); + // We are a C++ class, that's good. Get the class name and look it + // up: + llvm::StringRef class_name = symbol_name; + class_name.consume_front(vtable_demangled_prefix); + // We know the class name is absolute, so tell FindTypes that by + // prefixing it with the root namespace: + std::string lookup_name("::"); + lookup_name.append(class_name.data(), class_name.size()); + + type_info.SetName(class_name); + const bool exact_match = true; + TypeList class_types; + + // First look in the module that the vtable symbol came from and + // look for a single exact match. + llvm::DenseSet searched_symbol_files; + ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule(); + if (module_sp) +module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, + searched_symbol_files, class_types); + + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible + Target &target = m_process->GetTarget(); + if (class_types.Empty()) +target.GetImages().FindTypes(nullptr, ConstString(lookup_name), + exact_match, UINT32_MAX, searched_symbol_files, class_types); -// If we didn't find a symbol, then move on to the entire module -// list in the target and get as many unique matches as possible -if (class_types.Empty()) - target.GetImages().FindTypes(nullptr, ConstString(lookup_name), - exact_match, UINT32_MAX, - searched_symbol_files,
[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)
clayborg wrote: > > I will let other FreeBSD folks do the final approval since I don't work on > > FreeBSD. > > @clayborg this change LGTM for FreeBSD. I'm still not fully sorted on the > approach for landing the commits post transition to GitHub. Also see the > comment about author name above. There is a web page that covers the new submission process: https://llvm.org/docs/GitHub.html I haven't done it yet either 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)
https://github.com/clayborg approved this pull request. 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] [libc++] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,145 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H + +#include <__algorithm/ranges_starts_with.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains_subrange { +struct __fn { + template _Sent1, +input_iterator _Iter2, +sentinel_for<_Iter2> _Sent2, +class _Pred, +class _Proj1, +class _Proj2, +class _Offset> + static _LIBCPP_HIDE_FROM_ABI constexpr bool __contains_subrange_fn_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + _Offset __offset) { +if (__offset < 0) + return false; +else { + for (; __offset >= 0; __offset--, __first1++) { +auto result = ranges::starts_with( +std::move(__first1), +std::move(__last1), +std::move(__first2), +std::move(__last2), +std::ref(__pred), +std::ref(__proj1), +std::ref(__proj2)); +if (result) + return true; + } + return false; +} ZijunZhaoCCK wrote: Yes. Initially, I didn't aware that I can use `ranges::search`. Then I tried to replace `ranges::starts_with` with `ranges::search` and I got > constraints not satisfied for class template 'subrange' [with _Iter = > cpp20_input_iterator, _Sent = cpp20_input_iterator, _Kind = > std::ranges::subrange_kind::unsized] error in the test file. I tried to test with forward iterator. It works well. https://github.com/llvm/llvm-project/pull/66963 ___ 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)
https://github.com/emaste approved this pull request. 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)
emaste wrote: https://llvm.org/docs/GitHub.html#landing-your-change > There are two different ways to do this: > > - [Interactive rebase](https://git-scm.com/docs/git-rebase#_interactive_mode) > with fixup’s. This is the recommended method since you can control the final > commit message and inspect that the final commit looks as you expect. When > your local state is correct, remember to force-push to your branch and press > the merge button afterwards. > > - Use the button Squash and merge in GitHub’s web interface, if you do this > remember to review the commit message when prompted. So I suspect the best way to go here is @aokblast locally squashes these commits into one, updates author if desired, fixes up commit messages if necessary, and then force-pushes to this pull request. Then @clayborg or I push the merge button. 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] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/67599 >From 8fa9aae354ac455f4ea443de1bb5f753fe93fb51 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Wed, 27 Sep 2023 13:03:40 -0700 Subject: [PATCH 1/4] 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 ``` --- lldb/include/lldb/API/SBValue.h | 28 ++ lldb/include/lldb/Core/ValueObject.h | 4 + lldb/include/lldb/Core/ValueObjectChild.h | 1 + lldb/include/lldb/Core/ValueObjectVTable.h| 65 lldb/include/lldb/Symbol/TypeSystem.h | 4 + lldb/include/lldb/lldb-enumerations.h | 4 +- lldb/source/API/SBValue.cpp | 17 +- lldb/source/Commands/CommandObjectFrame.cpp | 2 + lldb/source/Core/CMakeLists.txt | 1 + lldb/source/Core/ValueObject.cpp | 5 + lldb/source/Core/ValueObjectVTable.cpp| 325 ++ .../DataFormatters/CXXFunctionPointer.cpp | 6 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 4 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 +- .../TypeSystem/Clang/TypeSystemClang.h| 4 + lldb/test/API/functionalities/vtable/Makefile | 3 + .../functionalities/vtable/TestVTableValue.py | 135 lldb/test/API/functionalities/vtable/main.cpp | 37 ++ 18 files changed, 664 insertions(+), 7 deletions(-) create mode 100644 lldb/include/lldb/Core/ValueObjectVTable.h create mode 100644 lldb/source/Core/ValueObjectVTable.cpp create mode 100644 lldb/test/API/functionalities/vtable/Makefile create mode 100644 lldb/test/API/functionalities/vtable/TestVTableValue.py create mode 100644 lldb/test/API/functionalities/vtable/main.cpp 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. + /// + /// SBValu
[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)
emaste wrote: Oh, I think we should also mention GSoC in the commit message. Something like `This project was part of FreeBSD's participation in Google Summer of Code 2023.` or so. 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] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -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"); jeffreytan81 wrote: This is public facing error right? Maybe be clear what is "parent" in this context. Like `can't get parent vtable address`. 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)
@@ -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 jeffreytan81 wrote: Like! 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)
https://github.com/jeffreytan81 commented: Oops, I found my old comments from yesterday did not go out. Still need to learn the new UI. 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)
@@ -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)
https://github.com/jeffreytan81 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)
jeffreytan81 wrote: > > * Can we test this during multiple inheritance? Should we print multiple > > vtables? > [Greg] 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. I remember some compiler's multi-inheritance implementation is putting one vtable_ptr in object for each parent class. Maybe not in clang? > > * Test in coredump to make sure it works > [Greg] That is tricky due to the vtables never being stored in the core > files since they are in read only sections. Right, I am not asking for a testcase, but manual testing. 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][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)
aokblast wrote: As my mentor Li-Wen Hsu suggest, It is better to separate this patch into two commits. One for DynamicLoaderFreeBSDKernel class, and another for the modification about ObjectFile.cpp. Should I use 1 commits to include both of these change or separate it as two? 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)
clayborg wrote: > As my mentor Li-Wen Hsu suggest, It is better to separate this patch into two > commits. One for DynamicLoaderFreeBSDKernel class, and another for the > modification about ObjectFile.cpp. Should I use 1 commits to include both of > these change or separate it as two? I am ok with it being one patch since it is related to implementing kernel debugging. 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] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
@@ -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)
clayborg wrote: > > > * Can we test this during multiple inheritance? Should we print multiple > > > vtables? > > > [Greg] 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. > > I remember some compiler's multi-inheritance implementation is putting one > vtable_ptr in object for each parent class. Maybe not in clang? Each class has a single vtable and this table will contain a copy of all vtables that are needed for each class. 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)
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/67599 >From 8fa9aae354ac455f4ea443de1bb5f753fe93fb51 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Wed, 27 Sep 2023 13:03:40 -0700 Subject: [PATCH 1/5] 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 ``` --- lldb/include/lldb/API/SBValue.h | 28 ++ lldb/include/lldb/Core/ValueObject.h | 4 + lldb/include/lldb/Core/ValueObjectChild.h | 1 + lldb/include/lldb/Core/ValueObjectVTable.h| 65 lldb/include/lldb/Symbol/TypeSystem.h | 4 + lldb/include/lldb/lldb-enumerations.h | 4 +- lldb/source/API/SBValue.cpp | 17 +- lldb/source/Commands/CommandObjectFrame.cpp | 2 + lldb/source/Core/CMakeLists.txt | 1 + lldb/source/Core/ValueObject.cpp | 5 + lldb/source/Core/ValueObjectVTable.cpp| 325 ++ .../DataFormatters/CXXFunctionPointer.cpp | 6 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 4 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 +- .../TypeSystem/Clang/TypeSystemClang.h| 4 + lldb/test/API/functionalities/vtable/Makefile | 3 + .../functionalities/vtable/TestVTableValue.py | 135 lldb/test/API/functionalities/vtable/main.cpp | 37 ++ 18 files changed, 664 insertions(+), 7 deletions(-) create mode 100644 lldb/include/lldb/Core/ValueObjectVTable.h create mode 100644 lldb/source/Core/ValueObjectVTable.cpp create mode 100644 lldb/test/API/functionalities/vtable/Makefile create mode 100644 lldb/test/API/functionalities/vtable/TestVTableValue.py create mode 100644 lldb/test/API/functionalities/vtable/main.cpp 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. + /// + /// SBValu