From 5d8aa56de5d20fcbcd200bb99a21afe0bccb7ba0 Mon Sep 17 00:00:00 2001 From: peace-maker Date: Sun, 5 Jan 2025 22:47:06 +0100 Subject: [PATCH 1/2] Add functions to iterate function names to IPluginDebugInfo Allow to inspect the list of functions defined in a plugin as well as the corresponding source filename if available and requested. --- include/sp_vm_api.h | 16 +++++++++++++++- vm/legacy-image.h | 8 ++++++++ vm/plugin-runtime.cpp | 10 ++++++++++ vm/plugin-runtime.h | 2 ++ vm/smx-v1-image.cpp | 22 ++++++++++++++++++++++ vm/smx-v1-image.h | 2 ++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/sp_vm_api.h b/include/sp_vm_api.h index 4ad040866..6e312a0c2 100644 --- a/include/sp_vm_api.h +++ b/include/sp_vm_api.h @@ -24,7 +24,7 @@ /** SourcePawn Engine API Versions */ #define SOURCEPAWN_ENGINE2_API_VERSION 0x10 -#define SOURCEPAWN_API_VERSION 0x0213 +#define SOURCEPAWN_API_VERSION 0x0214 namespace SourceMod { struct IdentityToken_t; @@ -365,6 +365,20 @@ class IPluginDebugInfo * @return Full file name of source file or NULL if not found. */ virtual const char* GetFileName(size_t index) = 0; + + /** + * @brief Returns the number of functions defined in this plugin. + */ + virtual size_t NumFunctions() = 0; + + /** + * @brief Returns the function name at the given index. + * + * @param index Index of the function in the list of functions. + * @param file Output pointer to store filename where the function is defined in. + * @return Name of the function or NULL if not found. + */ + virtual const char* GetFunctionName(size_t index, const char** file) = 0; }; class ICompilation; diff --git a/vm/legacy-image.h b/vm/legacy-image.h index 24a4668ec..d6c61c92a 100644 --- a/vm/legacy-image.h +++ b/vm/legacy-image.h @@ -59,6 +59,8 @@ class LegacyImage virtual bool LookupLineAddress(const uint32_t line, const char* file, ucell_t* addr) const = 0; virtual size_t NumFiles() const = 0; virtual const char* GetFileName(size_t index) const = 0; + virtual size_t NumFunctions() const = 0; + virtual const char* GetFunctionName(size_t index, const char** filename) const = 0; virtual bool HasRtti() const = 0; virtual const smx_rtti_method* GetMethodRttiByOffset(uint32_t pcode_offset) const = 0; }; @@ -141,6 +143,12 @@ class EmptyImage : public LegacyImage const char* GetFileName(size_t index) const override { return nullptr; } + size_t NumFunctions() const override { + return 0; + } + const char* GetFunctionName(size_t index, const char** filename) const override { + return nullptr; + } const smx_rtti_method* GetMethodRttiByOffset(uint32_t pcode_offset) const override { return nullptr; } diff --git a/vm/plugin-runtime.cpp b/vm/plugin-runtime.cpp index 73bd37c08..733868470 100644 --- a/vm/plugin-runtime.cpp +++ b/vm/plugin-runtime.cpp @@ -598,6 +598,16 @@ PluginRuntime::GetFileName(size_t index) return image_->GetFileName(index); } +size_t +PluginRuntime::NumFunctions() { + return image_->NumFunctions(); +} + +const char* +PluginRuntime::GetFunctionName(size_t index, const char** filename) { + return image_->GetFunctionName(index, filename); +} + int PluginRuntime::LookupFunctionAddress(const char* function, const char* file, ucell_t* addr) { diff --git a/vm/plugin-runtime.h b/vm/plugin-runtime.h index 638cfc2c2..f70abbe16 100644 --- a/vm/plugin-runtime.h +++ b/vm/plugin-runtime.h @@ -84,6 +84,8 @@ class PluginRuntime int LookupFile(ucell_t addr, const char** filename) override; size_t NumFiles() override; const char* GetFileName(size_t index) override; + size_t NumFunctions() override; + const char* GetFunctionName(size_t index, const char** filename) override; int LookupFunctionAddress(const char* function, const char* file, ucell_t* addr) override; int LookupLineAddress(const uint32_t line, const char* file, ucell_t* addr) override; const char* GetFilename() override { diff --git a/vm/smx-v1-image.cpp b/vm/smx-v1-image.cpp index 83c591319..fe5e3f274 100644 --- a/vm/smx-v1-image.cpp +++ b/vm/smx-v1-image.cpp @@ -1060,6 +1060,28 @@ SmxV1Image::GetFileName(size_t index) const return debug_names_ + debug_files_[index].name; } +size_t +SmxV1Image::NumFunctions() const { + if (rtti_methods_) { + return rtti_methods_->row_count; + } + return 0; +} + +const char* +SmxV1Image::GetFunctionName(size_t index, const char** filename) const { + if (rtti_methods_) { + if (index >= rtti_methods_->row_count) + return nullptr; + + const smx_rtti_method* method = getRttiRow(rtti_methods_, index); + if (filename) + *filename = LookupFile(method->pcode_start); + return names_ + method->name; + } + return nullptr; +} + template bool SmxV1Image::getFunctionAddress(const SymbolType* syms, const char* function, ucell_t* funcaddr, uint32_t& index) const diff --git a/vm/smx-v1-image.h b/vm/smx-v1-image.h index 99ef6105a..454b33c72 100644 --- a/vm/smx-v1-image.h +++ b/vm/smx-v1-image.h @@ -69,6 +69,8 @@ class SmxV1Image bool LookupLineAddress(const uint32_t line, const char* file, ucell_t* addr) const override; size_t NumFiles() const override; const char* GetFileName(size_t index) const override; + size_t NumFunctions() const override; + const char* GetFunctionName(size_t index, const char** filename) const override; bool HasRtti() const override; const smx_rtti_method* GetMethodRttiByOffset(uint32_t pcode_offset) const override; From 19e1ec091ffa3a3c2d3d8580472271e379b7d327 Mon Sep 17 00:00:00 2001 From: peace-maker Date: Sun, 5 Jan 2025 22:51:00 +0100 Subject: [PATCH 2/2] Support pre-RTTI debug symbol information Allow to use the API on old .smx binaries too. --- vm/smx-v1-image.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++-- vm/smx-v1-image.h | 4 +++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/vm/smx-v1-image.cpp b/vm/smx-v1-image.cpp index fe5e3f274..35449c5ed 100644 --- a/vm/smx-v1-image.cpp +++ b/vm/smx-v1-image.cpp @@ -1060,12 +1060,71 @@ SmxV1Image::GetFileName(size_t index) const return debug_names_ + debug_files_[index].name; } +template +uint32_t +SmxV1Image::getFunctionCount(const SymbolType* syms) const { + const uint8_t* cursor = reinterpret_cast(syms); + const uint8_t* cursor_end = cursor + debug_symbols_section_->size; + uint32_t func_count = 0; + for (uint32_t i = 0; i < debug_info_->num_syms; i++) { + if (cursor + sizeof(SymbolType) > cursor_end) + break; + + const SymbolType* sym = reinterpret_cast(cursor); + if (sym->ident == sp::IDENT_FUNCTION) + func_count++; + + if (sym->dimcount > 0) + cursor += sizeof(DimType) * sym->dimcount; + cursor += sizeof(SymbolType); + } + return func_count; +} + size_t SmxV1Image::NumFunctions() const { if (rtti_methods_) { return rtti_methods_->row_count; } - return 0; + + // Count function symbols once. + static uint32_t num_debug_functions = 0; + if (num_debug_functions == 0) { + if (debug_syms_) + num_debug_functions = getFunctionCount(debug_syms_); + else + num_debug_functions = getFunctionCount(debug_syms_unpacked_); + } + return num_debug_functions; +} + +template +const char* +SmxV1Image::getFunctionName(const SymbolType* syms, const char** filename, uint32_t index) const { + const uint8_t* cursor = reinterpret_cast(syms); + const uint8_t* cursor_end = cursor + debug_symbols_section_->size; + uint32_t func_count = 0; + for (uint32_t i = 0; i < debug_info_->num_syms; i++) { + if (cursor + sizeof(SymbolType) > cursor_end) + break; + + const SymbolType* sym = reinterpret_cast(cursor); + if (sym->ident == sp::IDENT_FUNCTION) { + if (func_count == index) { + if (filename) + *filename = LookupFile(sym->addr); + if (sym->name < debug_names_section_->size) + return debug_names_ + sym->name; + return nullptr; + } + func_count++; + } + + if (sym->dimcount > 0) + cursor += sizeof(DimType) * sym->dimcount; + cursor += sizeof(SymbolType); + } + return nullptr; } const char* @@ -1079,7 +1138,12 @@ SmxV1Image::GetFunctionName(size_t index, const char** filename) const { *filename = LookupFile(method->pcode_start); return names_ + method->name; } - return nullptr; + + if (debug_syms_) { + return getFunctionName(debug_syms_, filename, index); + } else { + return getFunctionName(debug_syms_unpacked_, filename, index); + } } template diff --git a/vm/smx-v1-image.h b/vm/smx-v1-image.h index 454b33c72..6764196db 100644 --- a/vm/smx-v1-image.h +++ b/vm/smx-v1-image.h @@ -221,6 +221,10 @@ class SmxV1Image template const char* lookupFunction(const SymbolType* syms, uint32_t addr) const; template + uint32_t getFunctionCount(const SymbolType* syms) const; + template + const char* getFunctionName(const SymbolType* syms, const char** filename, uint32_t index) const; + template bool getFunctionAddress(const SymbolType* syms, const char* function, ucell_t* funcaddr, uint32_t& index) const; const smx_rtti_table_header* findRttiSection(const char* name) const {