From 523888ce45a1ec7083cd71c3e3295df1adf09b20 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 31 May 2024 12:55:52 -0500 Subject: [PATCH 01/20] -Write macro records correctly. Fixes #7 --- src/SQLiteDB.cpp | 67 +++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index 242a504d..669ca995 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -484,9 +484,7 @@ int SQLiteDB::writeElfToDatabase(ElfFile& inElf) */ int SQLiteDB::writeMacrosToDatabase(ElfFile& inElf) { - int rc = SQLITEDB_OK; - char* errorMessage = NULL; - + int rc = SQLITEDB_OK; for (auto macro : inElf.getDefineMacros()) { /* @@ -494,41 +492,58 @@ int SQLiteDB::writeMacrosToDatabase(ElfFile& inElf) * but I'm not sure what is the best way to do that without it being * messy. */ - std::string writeMacroQuery{}; - writeMacroQuery += - "INSERT INTO macros(name, value) " - "VALUES(\""; - writeMacroQuery += macro.getName(); - writeMacroQuery += "\","; - writeMacroQuery += "\""; - writeMacroQuery += macro.getValue(); - writeMacroQuery += "\""; - writeMacroQuery += ");"; + // Create a SQL statement with placeholders + sqlite3_stmt* stmt; + const char* sql = "INSERT INTO macros (name, value) VALUES (?, ?);"; - logger.logDebug("Sending \"%s\" query to database.", writeMacroQuery.c_str()); + // Prepare the SQL statement + rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - rc = sqlite3_exec(database, writeMacroQuery.c_str(), NULL, NULL, &errorMessage); - - if (SQLITE_OK == rc) + if (rc != SQLITE_OK) { - logger.logDebug( - "Elf values were written to the macros schema with " - "SQLITE_OK status."); + std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; } else { - if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + // Bind values to placeholders + sqlite3_bind_text(stmt, 1, macro.getName().c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, macro.getValue().c_str(), -1, SQLITE_STATIC); + + // Execute the SQL statement + if (sqlite3_step(stmt) != SQLITE_DONE) { - logger.logDebug("%s.", errorMessage); - rc = SQLITE_OK; + const char* errorMessage = sqlite3_errmsg(database); + // std::cerr << "Execution failed: " << sqlite3_errmsg(database) << std::endl; + + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the macros schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the elfs table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } } else { - logger.logDebug("There was an error while writing data to the elfs table."); - logger.logDebug("%s.", errorMessage); - rc = SQLITEDB_ERROR; + // std::cout << "Records created successfully" << std::endl; } + + // Finalize the statement + sqlite3_finalize(stmt); } } From 32f52e602f15d9ba483401843995cc351573a767 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 31 May 2024 12:58:27 -0500 Subject: [PATCH 02/20] -Cleanup --- src/SQLiteDB.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index 669ca995..05327762 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -514,8 +514,6 @@ int SQLiteDB::writeMacrosToDatabase(ElfFile& inElf) if (sqlite3_step(stmt) != SQLITE_DONE) { const char* errorMessage = sqlite3_errmsg(database); - // std::cerr << "Execution failed: " << sqlite3_errmsg(database) << std::endl; - if (SQLITE_OK == rc) { logger.logDebug( @@ -537,10 +535,6 @@ int SQLiteDB::writeMacrosToDatabase(ElfFile& inElf) } } } - else - { - // std::cout << "Records created successfully" << std::endl; - } // Finalize the statement sqlite3_finalize(stmt); From 8b97106dff236c804cf73fdf387fd3d79cf95e4f Mon Sep 17 00:00:00 2001 From: lgomez Date: Tue, 17 Dec 2024 18:17:46 -0600 Subject: [PATCH 03/20] -Add namespaces unit test. WIP. --- unit-test/namespaces_test.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 unit-test/namespaces_test.cpp diff --git a/unit-test/namespaces_test.cpp b/unit-test/namespaces_test.cpp new file mode 100644 index 00000000..79b380a6 --- /dev/null +++ b/unit-test/namespaces_test.cpp @@ -0,0 +1,21 @@ +namespace World +{ +struct Shape +{ + int width; + int length; +}; +} // namespace World + +class WorldClass +{ + public: + struct Shape + { + int width; + int length; + }; +}; // namespace World + +World::Shape myShape{}; +WorldClass::Shape classyShape{}; From 39b667c442c6d643a8989973b9c2b3a0043552d9 Mon Sep 17 00:00:00 2001 From: lgomez Date: Wed, 18 Dec 2024 14:15:19 -0600 Subject: [PATCH 04/20] -Add namespaces unit test. WIP. --- unit-test/namespaces_test.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/unit-test/namespaces_test.cpp b/unit-test/namespaces_test.cpp index 79b380a6..e0782e05 100644 --- a/unit-test/namespaces_test.cpp +++ b/unit-test/namespaces_test.cpp @@ -1,3 +1,5 @@ +namespace Universe +{ namespace World { struct Shape @@ -6,6 +8,17 @@ struct Shape int length; }; } // namespace World +} // namespace Universe + +namespace Universe +{ + +struct Shape2 +{ + int width; + int length; +}; +} // namespace Universe class WorldClass { @@ -17,5 +30,7 @@ class WorldClass }; }; // namespace World -World::Shape myShape{}; -WorldClass::Shape classyShape{}; +Universe::World::Shape myShape{}; + +Universe::Shape2 myShape2{}; +WorldClass::Shape classyShape{}; From bc1222c3cc3bdca50dc5c3b511f899f4a3cb57fe Mon Sep 17 00:00:00 2001 From: lgomez Date: Wed, 18 Dec 2024 18:01:26 -0600 Subject: [PATCH 05/20] -Add namespaces. WIP. --- src/Namespace.cpp | 7 +++++++ src/Namespace.hpp | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/Namespace.cpp create mode 100644 src/Namespace.hpp diff --git a/src/Namespace.cpp b/src/Namespace.cpp new file mode 100644 index 00000000..c4cbc324 --- /dev/null +++ b/src/Namespace.cpp @@ -0,0 +1,7 @@ +#include "Namespace.hpp" + +Namespace::Namespace(std::string name) { this->name = name; } + +void Namespace::setName(std::string name) { this->name = name; } + +std::string Namespace::getName() { return name; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp new file mode 100644 index 00000000..c3677749 --- /dev/null +++ b/src/Namespace.hpp @@ -0,0 +1,16 @@ +#include +#include + +#include "Symbol.h" + +class Namespace +{ + public: + Namespace(std::string name); + std::string getName(); + void setName(std::string name); + + private: + std::string name; + std::vector symbols; +}; \ No newline at end of file From 77797baf964cbab58686fef8eeeec3fcfbd92a46 Mon Sep 17 00:00:00 2001 From: lgomez Date: Thu, 19 Dec 2024 17:57:26 -0600 Subject: [PATCH 06/20] -Add namespaces table --- src/SQLiteDB.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++++++ src/SQLiteDB.h | 8 ++++ 2 files changed, 112 insertions(+) diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index bd6f8e60..239453b9 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -393,6 +393,8 @@ int SQLiteDB::write(ElfFile& inElf) logger.logDebug( "Variable entries were written to the variables schema " "with SQLITE_OK status."); + + rc = writeNamespacesToDatabase(inElf); } else { @@ -1848,6 +1850,70 @@ int SQLiteDB::writeEncodingsToDatabase(ElfFile& inElf) return rc; } +int SQLiteDB::writeNamespacesToDatabase(ElfFile& inElf) +{ + int rc = SQLITEDB_OK; + char* errorMessage = NULL; + + for (auto&& namespace_ : inElf.getNamespaces()) + { + std::string writeNamespaceQuery{}; + + sqlite3_stmt* stmt; + const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + // Prepare the SQL statement + rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + if (rc != SQLITE_OK) + { + std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; + } + else + { + // Bind values to placeholders + sqlite3_bind_text(stmt, 1, namespace_.getName().c_str(), -1, SQLITE_STATIC); + + rc = sqlite3_step(stmt); + + // Execute the SQL statement + if (rc != SQLITE_DONE) + { + const char* errorMessage = sqlite3_errmsg(database); + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the encodings schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the encodings table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } + } + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) + { + logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + } + } + } + + return rc; +} + /** *@brief This method creates all of the schemas that will be needed to store *the DWARF and ELF data. @@ -1939,6 +2005,20 @@ int SQLiteDB::createSchemas(void) logger.logDebug( "createEncodingsTableSchema() created the variables schema " "successfully."); + + rc = createNamespacesTableSchema(); + + if (rc == SQLITE_OK) + { + logger.logDebug( + "createNamespacesTableSchema() created the namespaces schema " + "successfully."); + } + else + { + logger.logDebug("createNamespacesTableSchema() failed."); + rc = SQLITEDB_ERROR; + } } else { @@ -2359,3 +2439,27 @@ int SQLiteDB::createEncodingsTableSchema(void) return rc; } + +int SQLiteDB::createNamespacesTableSchema(void) +{ + std::string createNamespacesTableQuery{CREATE_NAMESPACES_TABLE}; + + int rc = SQLITE_OK; + + /*@todo The last argument for sqlite3_exec is an error handler that is not + * necessary to pass in, but I really think we should for better error + * logging.*/ + rc = sqlite3_exec(database, createNamespacesTableQuery.c_str(), NULL, NULL, NULL); + + if (SQLITE_OK == rc) + { + logger.logDebug("Created table \"namespaces\" with OK status"); + } + else + { + logger.logError("Failed to create the namespaces table. '%s'", sqlite3_errmsg(database)); + rc = SQLITEDB_ERROR; + } + + return rc; +} diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index d023345e..9953f570 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -156,6 +156,12 @@ encoding TEXT NOT NULL,\ UNIQUE (encoding));" +#define CREATE_NAMESPACES_TABLE \ + "CREATE TABLE IF NOT EXISTS namespaces(\ + id INTEGER PRIMARY KEY,\ + name TEXT NOT NULL,\ + UNIQUE (name)); " + //#define CREATE_DATA_OBJECTS_TABLE \ // "CREATE TABLE IF NOT EXISTS data_objects(\ // id INTEGER PRIMARY KEY,\ @@ -194,6 +200,7 @@ class SQLiteDB : public IDataContainer int createElfSectionsSchema(void); int createElfSymbolTableSchema(void); int createEncodingsTableSchema(void); + int createNamespacesTableSchema(void); int writeElfToDatabase(ElfFile &inModule); int writeMacrosToDatabase(ElfFile &inModule); int writeVariablesToDatabase(ElfFile &inModule); @@ -205,6 +212,7 @@ class SQLiteDB : public IDataContainer int writeEnumerationsToDatabase(ElfFile &inModule); int writeDimensionsListToDatabase(ElfFile &inElf); int writeEncodingsToDatabase(ElfFile &inElf); + int writeNamespacesToDatabase(ElfFile &inElf); static int doesRowExistCallback(void *veryUsed, int argc, char **argv, char **azColName); bool doesSymbolExist(std::string name); bool doesArtifactExist(std::string name); From 8f6656fe45d4927b11eb37a3a76c29fc55d570a0 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 20 Dec 2024 13:31:32 -0600 Subject: [PATCH 07/20] -Add namespace child and parent. Might be better to represent this as a std::list. WIP. --- src/ElfFile.cpp | 19 +++++++- src/ElfFile.h | 12 ++++- src/Juicer.cpp | 113 ++++++++++++++++++++++++++++++++++++++++------ src/Juicer.h | 6 ++- src/Namespace.cpp | 9 ++++ src/Namespace.hpp | 20 ++++++-- src/SQLiteDB.cpp | 2 +- src/SQLiteDB.h | 6 ++- 8 files changed, 163 insertions(+), 24 deletions(-) diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index c78c42cd..6fef9eb0 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -238,4 +238,21 @@ void ElfFile::setElfClass(int newelfClass) } } -int ElfFile::getElfClass() { return elfClass; } +int ElfFile::getElfClass() { return elfClass; } + +void ElfFile::addNamespace(Namespace newNamespace) { namespaces.push_back(std::make_unique(newNamespace)); } + +Namespace* ElfFile::getNamespace(std::string name) +{ + for (auto&& namespace_ : namespaces) + { + if (namespace_->getName() == name) + { + return namespace_.get(); + } + } + + return nullptr; +} + +std::vector>& ElfFile::getNamespaces() { return namespaces; } diff --git a/src/ElfFile.h b/src/ElfFile.h index c6e236ac..cddf01d0 100644 --- a/src/ElfFile.h +++ b/src/ElfFile.h @@ -21,6 +21,7 @@ #include "Field.h" #include "Juicer.h" #include "Logger.h" +#include "Namespace.hpp" #include "Variable.h" #include "dwarf.h" @@ -28,6 +29,7 @@ class Symbol; class Field; class Enumeration; class Variable; +class Namespace; /** * The elf class contains an "module" with a user-defined name. @@ -91,6 +93,10 @@ class ElfFile void setElfClass(int newelfClass); + void addNamespace(Namespace newNamespace); + std::vector> &getNamespaces(); + Namespace *getNamespace(std::string name); + private: std::string md5; /** @@ -155,7 +161,7 @@ class ElfFile }; - Encoding &getDWARFEncoding(); + Encoding &getDWARFEncoding(); /** * @brief elfClass @@ -164,7 +170,9 @@ class ElfFile * #define ELFCLASS32 1 32-bit objects * #define ELFCLASS64 2 64-bit objects */ - int elfClass{ELFCLASSNONE}; + int elfClass{ELFCLASSNONE}; + + std::vector> namespaces{}; }; #endif /* ElfFile_H_ */ diff --git a/src/Juicer.cpp b/src/Juicer.cpp index e19d941a..1ae507b6 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -55,20 +55,10 @@ #include "Enumeration.h" #include "Field.h" #include "IDataContainer.h" +#include "Namespace.hpp" #include "Symbol.h" #include "Variable.h" -struct macro_counts_s -{ - long mc_start_file; - long mc_end_file; - long mc_define; - long mc_undef; - long mc_extension; - long mc_code_zero; - long mc_unknown; -}; - Juicer::Juicer() {} DefineMacro Juicer::getDefineMacroFromString(std::string macro_string) @@ -413,7 +403,7 @@ int Juicer::readCUList(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Error &error) dbgSourceFiles.insert(dbgSourceFiles.begin(), filePaths, &filePaths[fileCount]); } - return_value = getDieAndSiblings(elf, dbg, cu_die, 0); + return_value = getDieAndSiblings(elf, dbg, cu_die, 0, nullptr); } if (JUICER_OK != return_value) @@ -639,6 +629,59 @@ char *Juicer::getFirstAncestorName(Dwarf_Die inDie) return outName; } +int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace *currentNamespace) +{ + Dwarf_Attribute attr_struct; + Dwarf_Error error = 0; + char *name = nullptr; + int res = 0; + Namespace ns{}; + + res = dwarf_attr(inDie, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + std::cout << "Namespace: " << name << std::endl; + } + + if (res == DW_DLV_OK) + { + ns.setName(name); + ns.setParent(currentNamespace); + elf.addNamespace(ns); + + if (currentNamespace != nullptr) + { + currentNamespace->setChild(elf.getNamespace(name)); + } + } + + // Dwarf_Die child; + // res = dwarf_child(inDie, &child, &error); + + // if (res == DW_DLV_ERROR) + // { + // logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // res = JUICER_ERROR; + // } + // else if (res == DW_DLV_OK) + // { + // int res = getDieAndSiblings(elf, dbg, child, in_level + 1, elf.getNamespace(ns.getName())); + // } + + return res; +} + Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) { Symbol *outSymbol = 0; @@ -4322,7 +4365,7 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) * @return 0 if the die, its children and siblings are scanned successfully. * 1 if there is a problem with dies or any of its children. */ -int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level) +int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace *currentNamespace) { int res = DW_DLV_ERROR; Dwarf_Die cur_die = in_die; @@ -4485,6 +4528,48 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i } break; } + + case DW_TAG_namespace: + { + // res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, ns); + + Dwarf_Attribute attr_struct; + Dwarf_Error error = 0; + char *name = nullptr; + int res = 0; + Namespace ns{}; + + res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + std::cout << "Namespace: " << name << std::endl; + } + + if (res == DW_DLV_OK) + { + ns.setName(name); + ns.setParent(currentNamespace); + elf.addNamespace(ns); + + if (currentNamespace != nullptr) + { + currentNamespace->setChild(elf.getNamespace(name)); + } + } + + break; + } } res = dwarf_child(cur_die, &child, &error); @@ -4495,7 +4580,7 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i } else if (res == DW_DLV_OK) { - getDieAndSiblings(elf, dbg, child, in_level + 1); + getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); } /* res == DW_DLV_NO_ENTRY */ diff --git a/src/Juicer.h b/src/Juicer.h index 61353c0c..b4078825 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -50,10 +50,11 @@ #include "Enumeration.h" #include "Field.h" #include "Logger.h" +#include "Namespace.hpp" #include "Symbol.h" #include "dwarf.h" #include "libdwarf.h" - +class Namespace; class Field; /* @@ -111,7 +112,7 @@ class Juicer Dwarf_Handler errhand; Dwarf_Ptr errarg = 0; int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); - int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level); + int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); @@ -120,6 +121,7 @@ class Juicer void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); + int process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); char* getFirstAncestorName(Dwarf_Die inDie); int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); char* dwarfStringToChar(char* dwarfString); diff --git a/src/Namespace.cpp b/src/Namespace.cpp index c4cbc324..ac206aa8 100644 --- a/src/Namespace.cpp +++ b/src/Namespace.cpp @@ -1,7 +1,16 @@ #include "Namespace.hpp" +Namespace::Namespace() {} Namespace::Namespace(std::string name) { this->name = name; } void Namespace::setName(std::string name) { this->name = name; } std::string Namespace::getName() { return name; } + +Namespace* Namespace::getChild() { return child; } + +void Namespace::setChild(Namespace* child) { this->child = child; } + +void Namespace::setParent(Namespace* parent) { this->parent = parent; } + +Namespace* Namespace::getParent() { return parent; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp index c3677749..fd02410c 100644 --- a/src/Namespace.hpp +++ b/src/Namespace.hpp @@ -1,3 +1,6 @@ +#ifndef NAMESPACE_HPP +#define NAMESPACE_HPP + #include #include @@ -6,11 +9,22 @@ class Namespace { public: + Namespace(); Namespace(std::string name); std::string getName(); void setName(std::string name); + Namespace* getChild(); + void setChild(Namespace* child); + void setParent(Namespace* parent); + Namespace* getParent(); private: - std::string name; - std::vector symbols; -}; \ No newline at end of file + std::string name; + // std::list is owrth considering here + Namespace* parent; + Namespace* child; + uint32_t id; + // std::vector symbols; +}; + +#endif // NAMESPACE_HPP \ No newline at end of file diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index 239453b9..7fc8d40d 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -1872,7 +1872,7 @@ int SQLiteDB::writeNamespacesToDatabase(ElfFile& inElf) else { // Bind values to placeholders - sqlite3_bind_text(stmt, 1, namespace_.getName().c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); rc = sqlite3_step(stmt); diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index 9953f570..0880acb1 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -160,7 +160,11 @@ "CREATE TABLE IF NOT EXISTS namespaces(\ id INTEGER PRIMARY KEY,\ name TEXT NOT NULL,\ - UNIQUE (name)); " + parent INTEGER ,\ + child INTEGER ,\ + FOREIGN KEY (parent) REFERENCES namespaces(id),\ + FOREIGN KEY (child) REFERENCES namespaces(id),\ + UNIQUE (name, parent, child)); " //#define CREATE_DATA_OBJECTS_TABLE \ // "CREATE TABLE IF NOT EXISTS data_objects(\ From 46e03f1283035e8a98539748f47ffd9d986ca02b Mon Sep 17 00:00:00 2001 From: lgomez Date: Tue, 7 Jan 2025 11:27:42 -0600 Subject: [PATCH 08/20] -Refactor namespace class. Return name as reference rather than copy. --- src/Namespace.cpp | 15 +++++++++------ src/Namespace.hpp | 24 +++++++++++++----------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/Namespace.cpp b/src/Namespace.cpp index ac206aa8..0df12853 100644 --- a/src/Namespace.cpp +++ b/src/Namespace.cpp @@ -3,14 +3,17 @@ Namespace::Namespace() {} Namespace::Namespace(std::string name) { this->name = name; } -void Namespace::setName(std::string name) { this->name = name; } +void Namespace::setName(std::string name) { this->name = name; } -std::string Namespace::getName() { return name; } +std::string& Namespace::getName() { return name; } -Namespace* Namespace::getChild() { return child; } +Namespace* Namespace::getChild() { return child; } -void Namespace::setChild(Namespace* child) { this->child = child; } +void Namespace::setChild(Namespace* child) { this->child = child; } -void Namespace::setParent(Namespace* parent) { this->parent = parent; } +void Namespace::setParent(Namespace* parent) { this->parent = parent; } -Namespace* Namespace::getParent() { return parent; } +Namespace* Namespace::getParent() { return parent; } + +std::optional Namespace::getId() { return id; } +void Namespace::setId(int id) { this->id = id; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp index fd02410c..8b2be694 100644 --- a/src/Namespace.hpp +++ b/src/Namespace.hpp @@ -11,19 +11,21 @@ class Namespace public: Namespace(); Namespace(std::string name); - std::string getName(); - void setName(std::string name); - Namespace* getChild(); - void setChild(Namespace* child); - void setParent(Namespace* parent); - Namespace* getParent(); + std::string& getName(); + void setName(std::string name); + Namespace* getChild(); + void setChild(Namespace* child); + void setParent(Namespace* parent); + Namespace* getParent(); + std::optional getId(); + void setId(int id); private: - std::string name; - // std::list is owrth considering here - Namespace* parent; - Namespace* child; - uint32_t id; + std::string name; + // std::list is worth considering here + Namespace* parent{nullptr}; + Namespace* child{nullptr}; + std::optional id{std::nullopt}; // std::vector symbols; }; From a031a0bb8ef98854fa4b767cbc918fb949a9880c Mon Sep 17 00:00:00 2001 From: lgomez Date: Tue, 7 Jan 2025 17:01:14 -0600 Subject: [PATCH 09/20] -Namespace implementation almost complete --- src/Juicer.cpp | 10 +- src/Juicer.h.patch | 13 ++ src/Namespace.cpp | 33 +++- src/Namespace.hpp | 27 ++- src/SQLiteDB.cpp | 466 ++++++++++++++++++++++++++++++++++++++++++++- src/SQLiteDB.h | 9 +- 6 files changed, 536 insertions(+), 22 deletions(-) create mode 100644 src/Juicer.h.patch diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 1ae507b6..5e0bae73 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -657,12 +657,12 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in if (res == DW_DLV_OK) { ns.setName(name); - ns.setParent(currentNamespace); + // ns.setParent(currentNamespace); elf.addNamespace(ns); if (currentNamespace != nullptr) { - currentNamespace->setChild(elf.getNamespace(name)); + currentNamespace->addChild(elf.getNamespace(name)); } } @@ -4559,13 +4559,15 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i if (res == DW_DLV_OK) { ns.setName(name); - ns.setParent(currentNamespace); + // ns.setParent(currentNamespace); elf.addNamespace(ns); if (currentNamespace != nullptr) { - currentNamespace->setChild(elf.getNamespace(name)); + currentNamespace->addChild(elf.getNamespace(name)); } + + currentNamespace = elf.getNamespace(name); } break; diff --git a/src/Juicer.h.patch b/src/Juicer.h.patch new file mode 100644 index 00000000..e48594fc --- /dev/null +++ b/src/Juicer.h.patch @@ -0,0 +1,13 @@ +diff --git a/src/Juicer.h b/src/Juicer.h +index 61353c0c..297ab716 100644 +--- a/src/Juicer.h ++++ b/src/Juicer.h +@@ -150,6 +150,8 @@ class Juicer + DefineMacro getDefineMacroFromString(std::string macro_string); + std::map> getObjDataFromElf(ElfFile* elfFileObj); + ++ std::string generateRandomName(int length); ++ + bool extras; + + unsigned int groupNumber{0}; diff --git a/src/Namespace.cpp b/src/Namespace.cpp index 0df12853..27139181 100644 --- a/src/Namespace.cpp +++ b/src/Namespace.cpp @@ -1,9 +1,17 @@ #include "Namespace.hpp" Namespace::Namespace() {} -Namespace::Namespace(std::string name) { this->name = name; } - -void Namespace::setName(std::string name) { this->name = name; } +Namespace::Namespace(std::string name) +{ + this->name = name; + fullyQualifiedName = name; +} + +void Namespace::setName(std::string name) +{ + this->name = name; + fullyQualifiedName = name; +} std::string& Namespace::getName() { return name; } @@ -17,3 +25,22 @@ Namespace* Namespace::getParent() { return parent; } std::optional Namespace::getId() { return id; } void Namespace::setId(int id) { this->id = id; } + +void Namespace::addChild(Namespace* child) +{ + child->setParent(this); + children.push_back(child); + // fullyQualifiedName += separator + child->getName(); +} + +std::string Namespace::getFullyQualifiedName() +{ + while (parent != nullptr) + { + fullyQualifiedName = parent->getName() + separator + fullyQualifiedName; + parent = parent->getParent(); + } + return fullyQualifiedName; +} + +std::vector& Namespace::getChildren() { return children; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp index 8b2be694..7518daa9 100644 --- a/src/Namespace.hpp +++ b/src/Namespace.hpp @@ -11,21 +11,32 @@ class Namespace public: Namespace(); Namespace(std::string name); - std::string& getName(); - void setName(std::string name); - Namespace* getChild(); - void setChild(Namespace* child); - void setParent(Namespace* parent); - Namespace* getParent(); - std::optional getId(); - void setId(int id); + std::string& getName(); + void setName(std::string name); + Namespace* getChild(); + void setChild(Namespace* child); + void addChild(Namespace* child); + Namespace* getParent(); + std::optional getId(); + void setId(int id); + + std::vector& getChildren(); + + // std::string& getFullyQualifiedName() { return fullyQualifiedName; } + + std::string getFullyQualifiedName(); private: std::string name; + std::string fullyQualifiedName; // Fully qualified name of the namespace. e.g. "Universe::Earth" + const std::string separator{"::"}; + std::vector children; // std::list is worth considering here Namespace* parent{nullptr}; Namespace* child{nullptr}; + std::optional id{std::nullopt}; + void setParent(Namespace* parent); // std::vector symbols; }; diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index 7fc8d40d..ca5bc400 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -394,7 +394,7 @@ int SQLiteDB::write(ElfFile& inElf) "Variable entries were written to the variables schema " "with SQLITE_OK status."); - rc = writeNamespacesToDatabase(inElf); + rc = writeAllNamespacesToDatabase(inElf); } else { @@ -1850,17 +1850,344 @@ int SQLiteDB::writeEncodingsToDatabase(ElfFile& inElf) return rc; } -int SQLiteDB::writeNamespacesToDatabase(ElfFile& inElf) +bool SQLiteDB::doesNamespaceExistInDB(const std::string& fullyqualifiedName) +{ + // Update query to also check for parent and child + + std::string query = "SELECT COUNT(*) FROM namespaces WHERE fully_qualified_name = \"" + fullyqualifiedName + "\" ;"; + + int count = 0; + char* errorMessage = nullptr; + + int rc = sqlite3_exec( + database, query.c_str(), + [](void* data, int argc, char** argv, char** azColName) -> int + { + int* count = static_cast(data); + *count = std::stoi(argv[0]); + return 0; + }, + &count, &errorMessage); + + if (rc != SQLITE_OK) + { + logger.logError("SQL error: %s", errorMessage); + sqlite3_free(errorMessage); + return false; + } + + return count > 0; +} + +int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std::optional parentID) +{ + int rc = SQLITEDB_OK; + char* errorMessage = NULL; + + sqlite3_int64 lastRowId = -1; + + for (auto& namespace_ : namespaces) + { + // Check if namespace already exists in database + bool namespaceExists = doesNamespaceExistInDB(namespace_->getFullyQualifiedName()); + + if (namespaceExists) + { + logger.logDebug("Namespace %s already exists in the database.", namespace_->getFullyQualifiedName().c_str()); + continue; + } + + sqlite3_stmt* stmt; + const char* sql = "INSERT INTO namespaces (name, parent, fully_qualified_name) VALUES (?,?,?);"; + + // Prepare the SQL statement + rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + if (rc != SQLITE_OK) + { + std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; + } + else + { + // Bind values to placeholders + sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); + + // if (namespace_->getParent() != nullptr) + // { + // if (!namespace_->getParent()->getId().has_value()) + // { + // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + // sqlite3_stmt* stmt; + + // // Prepare the SQL statement + // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + // rc = sqlite3_bind_text(stmt, 1, namespace_->getParent()->getName().c_str(), -1, SQLITE_STATIC); + + // rc = sqlite3_step(stmt); + + // // Execute the SQL statement + // if (rc != SQLITE_DONE) + // { + // const char* errorMessage = sqlite3_errmsg(database); + // if (SQLITE_OK == rc) + // { + // logger.logDebug( + // "Elf values were written to the encodings schema with " + // "SQLITE_OK status."); + // } + // else + // { + // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + // { + // logger.logDebug("%s.", errorMessage); + // rc = SQLITE_OK; + // } + // else + // { + // logger.logDebug("There was an error while writing data to the encodings table."); + // logger.logDebug("%s.", errorMessage); + // rc = SQLITEDB_ERROR; + // } + // } + // } + + // // Finalize the statement + // rc = sqlite3_finalize(stmt); + // if (rc != SQLITE_OK) + // { + // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + // } + // else + // { + // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + // namespace_->getParent()->setId(lastRowId); + // } + // } + + // sqlite3_bind_int(stmt, 2, namespace_->getParent()->getId().value()); + // } + // else + // { + // sqlite3_bind_int(stmt, 2, -1); + // } + + sqlite3_bind_int(stmt, 2, parentID.value_or(-1)); + + if (namespace_->getChildren().size() > 0) + { + for (auto& child : namespace_->getChildren()) + { + // Parent is the current namespace. So we need to write it to the database first. + // Then we can get the id of the parent (and store it in parentID) and write it to the child. + + + int lastRowID = writeNamespacesToDatabase(child->getChildren(), parentID); + + // if (!child->getId().has_value()) + // { + // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + // sqlite3_stmt* stmt; + + // // Prepare the SQL statement + // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + // rc = sqlite3_bind_text(stmt, 1, child->getName().c_str(), -1, SQLITE_STATIC); + + // rc = sqlite3_step(stmt); + + // // Execute the SQL statement + // if (rc != SQLITE_DONE) + // { + // const char* errorMessage = sqlite3_errmsg(database); + // if (SQLITE_OK == rc) + // { + // logger.logDebug( + // "Elf values were written to the encodings schema with " + // "SQLITE_OK status."); + // } + // else + // { + // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + // { + // logger.logDebug("%s.", errorMessage); + // rc = SQLITE_OK; + // } + // else + // { + // logger.logDebug("There was an error while writing data to the encodings table."); + // logger.logDebug("%s.", errorMessage); + // rc = SQLITEDB_ERROR; + // } + // } + // } + + // // Finalize the statement + // rc = sqlite3_finalize(stmt); + // if (rc != SQLITE_OK) + // { + // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + // } + // else + // { + // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + // child->setId(lastRowId); + // } + // } + + // sqlite3_bind_int(stmt, 3, child->getId().value()); + // sqlite3_bind_int(stmt, 3, lastRowID); + } + } + else + { + // sqlite3_bind_int(stmt, 3, -1); + } + + std::string fqn = namespace_->getFullyQualifiedName(); + + sqlite3_bind_text(stmt, 3, fqn.c_str(), -1, SQLITE_STATIC); + + rc = sqlite3_step(stmt); + + // Execute the SQL statement + if (rc != SQLITE_DONE) + { + const char* errorMessage = sqlite3_errmsg(database); + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the encodings schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the encodings table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } + } + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) + { + logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + } + else + { + lastRowId = sqlite3_last_insert_rowid(database); + + namespace_->setId(lastRowId); + } + } + } + + return lastRowId; +} + +int SQLiteDB::writeAllNamespacesToDatabase(ElfFile& inElf) { int rc = SQLITEDB_OK; char* errorMessage = NULL; + std::vector namespacesPointers{}; + for (auto&& namespace_ : inElf.getNamespaces()) { + namespacesPointers.push_back(namespace_.get()); + } + + writeNamespacesToDatabase(namespacesPointers, std::nullopt); + + // for (auto&& namespace_ : inElf.getNamespaces()) + // { + // std::string writeNamespaceQuery{}; + + // sqlite3_stmt* stmt; + // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + // // Prepare the SQL statement + // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + // if (rc != SQLITE_OK) + // { + // std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; + // } + // else + // { + // // Bind values to placeholders + // sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); + // rc = sqlite3_step(stmt); + + // // Execute the SQL statement + // if (rc != SQLITE_DONE) + // { + // const char* errorMessage = sqlite3_errmsg(database); + // if (SQLITE_OK == rc) + // { + // logger.logDebug( + // "Elf values were written to the encodings schema with " + // "SQLITE_OK status."); + // } + // else + // { + // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + // { + // logger.logDebug("%s.", errorMessage); + // rc = SQLITE_OK; + // } + // else + // { + // logger.logDebug("There was an error while writing data to the encodings table."); + // logger.logDebug("%s.", errorMessage); + // rc = SQLITEDB_ERROR; + // } + // } + // } + + // // Finalize the statement + // rc = sqlite3_finalize(stmt); + // if (rc != SQLITE_OK) + // { + // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + // } + // else + // { + // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + // namespace_->setId(lastRowId); + // } + // } + // } + + for (auto&& namespace_ : inElf.getNamespaces()) + { + // Check if namespace already exists in database + bool namespaceExists = doesNamespaceExistInDB(namespace_->getFullyQualifiedName()); + + if (namespaceExists) + { + logger.logDebug("Namespace %s already exists in the database.", namespace_->getFullyQualifiedName().c_str()); + continue; + } + std::string writeNamespaceQuery{}; sqlite3_stmt* stmt; - const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + const char* sql = "INSERT INTO namespaces (name,parent) VALUES (?,?);"; // Prepare the SQL statement rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); @@ -1874,6 +2201,133 @@ int SQLiteDB::writeNamespacesToDatabase(ElfFile& inElf) // Bind values to placeholders sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); + if (namespace_->getParent() != nullptr) + { + if (!namespace_->getParent()->getId().has_value()) + { + const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + sqlite3_stmt* stmt; + + // Prepare the SQL statement + rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + rc = sqlite3_bind_text(stmt, 1, namespace_->getParent()->getName().c_str(), -1, SQLITE_STATIC); + + rc = sqlite3_step(stmt); + + // Execute the SQL statement + if (rc != SQLITE_DONE) + { + const char* errorMessage = sqlite3_errmsg(database); + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the encodings schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the encodings table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } + } + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) + { + logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + } + else + { + sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + namespace_->getParent()->setId(lastRowId); + } + } + + sqlite3_bind_int(stmt, 2, namespace_->getParent()->getId().value()); + } + else + { + sqlite3_bind_int(stmt, 2, -1); + } + + if (namespace_->getChildren().size() > 0) + { + for (auto&& child : namespace_->getChildren()) + { + if (!child->getId().has_value()) + { + const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; + + sqlite3_stmt* stmt; + + // Prepare the SQL statement + rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); + + rc = sqlite3_bind_text(stmt, 1, child->getName().c_str(), -1, SQLITE_STATIC); + + rc = sqlite3_step(stmt); + + // Execute the SQL statement + if (rc != SQLITE_DONE) + { + const char* errorMessage = sqlite3_errmsg(database); + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the encodings schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the encodings table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } + } + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) + { + logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + } + else + { + sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + child->setId(lastRowId); + } + } + + sqlite3_bind_int(stmt, 3, child->getId().value()); + } + } + else + { + sqlite3_bind_int(stmt, 3, -1); + } + rc = sqlite3_step(stmt); // Execute the SQL statement @@ -1908,6 +2362,12 @@ int SQLiteDB::writeNamespacesToDatabase(ElfFile& inElf) { logger.logDebug("There was an error while finalizing the sql statement for encodings table."); } + else + { + sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); + + namespace_->setId(lastRowId); + } } } diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index 0880acb1..f3d39c28 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -161,10 +161,9 @@ id INTEGER PRIMARY KEY,\ name TEXT NOT NULL,\ parent INTEGER ,\ - child INTEGER ,\ + fully_qualified_name TEXT NOT NULL,\ FOREIGN KEY (parent) REFERENCES namespaces(id),\ - FOREIGN KEY (child) REFERENCES namespaces(id),\ - UNIQUE (name, parent, child)); " + UNIQUE (fully_qualified_name)); " //#define CREATE_DATA_OBJECTS_TABLE \ // "CREATE TABLE IF NOT EXISTS data_objects(\ @@ -216,12 +215,14 @@ class SQLiteDB : public IDataContainer int writeEnumerationsToDatabase(ElfFile &inModule); int writeDimensionsListToDatabase(ElfFile &inElf); int writeEncodingsToDatabase(ElfFile &inElf); - int writeNamespacesToDatabase(ElfFile &inElf); + int writeNamespacesToDatabase(std::vector &namespaces, std::optional parentID); + int writeAllNamespacesToDatabase(ElfFile &inElf); static int doesRowExistCallback(void *veryUsed, int argc, char **argv, char **azColName); bool doesSymbolExist(std::string name); bool doesArtifactExist(std::string name); bool doEncodingsExist(); + bool doesNamespaceExistInDB(const std::string &fullyqualifiedName); public: SQLiteDB(); From 04c64333f550c8222784390517eafc9edc34e230 Mon Sep 17 00:00:00 2001 From: lgomez Date: Wed, 8 Jan 2025 18:17:54 -0600 Subject: [PATCH 10/20] -Minimally working impl of namespaces. --- src/ElfFile.cpp | 31 +++++++++++++- src/ElfFile.h | 1 + src/Juicer.cpp | 95 ++++++++++++++++++++---------------------- src/Juicer.cpp.patch | 83 +++++++++++++++++++++++++++++++++++++ src/Namespace.cpp | 20 +++++++++ src/SQLiteDB.cpp | 98 ++++++++++++++++++++++---------------------- src/SQLiteDB.h | 2 +- 7 files changed, 226 insertions(+), 104 deletions(-) create mode 100644 src/Juicer.cpp.patch diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index 6fef9eb0..6a87fd8a 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -238,9 +238,36 @@ void ElfFile::setElfClass(int newelfClass) } } -int ElfFile::getElfClass() { return elfClass; } +int ElfFile::getElfClass() { return elfClass; } -void ElfFile::addNamespace(Namespace newNamespace) { namespaces.push_back(std::make_unique(newNamespace)); } +void ElfFile::addNamespace(Namespace newNamespace) +{ + // Check if the namespace already exists + // for (auto&& namespace_ : namespaces) + // { + // if (namespace_->getName() == newNamespace.getName()) + // { + // // Logger::getInstance().logError("Namespace already exists in the list"); + // return; + // } + // } + namespaces.push_back(std::make_unique(newNamespace)); +} + + +void ElfFile::addNamespace(std::unique_ptr newNamespace) +{ + // Check if the namespace already exists + for (auto&& namespace_ : namespaces) + { + if (namespace_->getFullyQualifiedName() == newNamespace->getFullyQualifiedName()) + { + // Logger::getInstance().logError("Namespace already exists in the list"); + return; + } + } + namespaces.push_back(std::move(newNamespace)); +} Namespace* ElfFile::getNamespace(std::string name) { diff --git a/src/ElfFile.h b/src/ElfFile.h index cddf01d0..3907fdf3 100644 --- a/src/ElfFile.h +++ b/src/ElfFile.h @@ -94,6 +94,7 @@ class ElfFile void setElfClass(int newelfClass); void addNamespace(Namespace newNamespace); + void addNamespace(std::unique_ptr newNamespace); std::vector> &getNamespaces(); Namespace *getNamespace(std::string name); diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 5e0bae73..a2c35b65 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -654,30 +654,55 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in std::cout << "Namespace: " << name << std::endl; } + // // check if namespace already exists + // TODO: Need to think about the edge case where the namespace already exists but at a different level, meaning they are not the same namespace. + // I think they way to go might be to use the fully qualified name of the namespace. + // for (auto &ns : elf.getNamespaces() ) + // { + // if (ns->getName() == name && currentNamespace == nullptr) + // { + // return DW_DLV_OK; + // break; + // } + // } + + std::unique_ptr nsPtr = std::make_unique(); + if (res == DW_DLV_OK) { ns.setName(name); - // ns.setParent(currentNamespace); + // nsPtr->setName(name); elf.addNamespace(ns); if (currentNamespace != nullptr) { currentNamespace->addChild(elf.getNamespace(name)); + // currentNamespace->addChild(nsPtr.get()); } + + else + { + currentNamespace = elf.getNamespace(name); + // currentNamespace = nsPtr.get(); + } + + // elf.addNamespace(std::move(nsPtr)); } - // Dwarf_Die child; - // res = dwarf_child(inDie, &child, &error); + Dwarf_Die child; + res = dwarf_child(inDie, &child, &error); - // if (res == DW_DLV_ERROR) - // { - // logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // res = JUICER_ERROR; - // } - // else if (res == DW_DLV_OK) - // { - // int res = getDieAndSiblings(elf, dbg, child, in_level + 1, elf.getNamespace(ns.getName())); - // } + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + res = JUICER_ERROR; + } + else if (res == DW_DLV_OK) + { + int res = getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); + } + + currentNamespace = nullptr; return res; } @@ -4531,49 +4556,13 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i case DW_TAG_namespace: { - // res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, ns); - - Dwarf_Attribute attr_struct; - Dwarf_Error error = 0; - char *name = nullptr; - int res = 0; - Namespace ns{}; - - res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); - } - - if (res == DW_DLV_OK) - { - res = dwarf_formstring(attr_struct, &name, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - } - - std::cout << "Namespace: " << name << std::endl; - } - - if (res == DW_DLV_OK) - { - ns.setName(name); - // ns.setParent(currentNamespace); - elf.addNamespace(ns); - - if (currentNamespace != nullptr) - { - currentNamespace->addChild(elf.getNamespace(name)); - } - - currentNamespace = elf.getNamespace(name); - } - + res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); break; } } + // iterate through all children at this level + res = dwarf_child(cur_die, &child, &error); if (res == DW_DLV_ERROR) { @@ -4585,6 +4574,8 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); } + // currentNamespace = nullptr; + /* res == DW_DLV_NO_ENTRY */ res = dwarf_siblingof(dbg, cur_die, &sib_die, &error); if (res == DW_DLV_ERROR) @@ -4608,6 +4599,8 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i cur_die = sib_die; } + // currentNamespace = nullptr; + return return_value; } diff --git a/src/Juicer.cpp.patch b/src/Juicer.cpp.patch new file mode 100644 index 00000000..45a04887 --- /dev/null +++ b/src/Juicer.cpp.patch @@ -0,0 +1,83 @@ +diff --git a/src/Juicer.cpp b/src/Juicer.cpp +index e19d941a..07d93bf1 100644 +--- a/src/Juicer.cpp ++++ b/src/Juicer.cpp +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + #include "Artifact.h" + #include "ElfFile.h" +@@ -1032,7 +1033,22 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & + else + { + /* Couldn't find the name at all. */ +- res = DW_DLV_ERROR; ++ ++ // std::string outName = getFirstAncestorName(inDie); ++ // std::cout << "outName-->" << outName << std::endl; ++ Artifact newArtifact{elf, "NOT_FOUND:" + cName}; ++ std::string checkSum{}; ++ newArtifact.setMD5(checkSum); ++ // std::string s{"ImSPecial"}; ++ cName = {generateRandomName(16)}; ++ dieName = cName.data(); ++ ++ ++ // outSymbol = elf.addSymbol(s, byteSize, newArtifact); ++ ++ // process_DW_TAG_structure_type(elf, *outSymbol, dbg, typeDie); ++ // res = DW_DLV_ERROR; ++ res = DW_DLV_OK; + } + + if (res == DW_DLV_OK) +@@ -1047,17 +1063,22 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & + + if (res == DW_DLV_OK) + { +- std::string cName{""}; ++ + if (dieName != nullptr) + { + cName = dieName; ++ ++ if(cName == "VC_HkTlm_t") ++ { ++ printf("break *****\n"); ++ } + } + else + { + logger.logWarning("Symbol does not have a name. This usually means an anonymous struct or union."); + } + +- res = dwarf_attr(inDie, DW_AT_decl_file, &attr_struct, &error); ++ res = dwarf_attr(typeDie, DW_AT_decl_file, &attr_struct, &error); + + if (DW_DLV_OK == res) + { +@@ -4524,6 +4545,21 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i + return return_value; + } + ++// Function to generate a random name of a given length ++std::string Juicer::generateRandomName(int length) { ++ const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; ++ std::string randomName; ++ std::random_device rd; ++ std::mt19937 generator(rd()); ++ std::uniform_int_distribution<> distrib(0, characters.size() - 1); ++ ++ for (int i = 0; i < length; ++i) { ++ randomName += characters[distrib(generator)]; ++ } ++ ++ return randomName; ++} ++ + /** + * @brief prints the data on the DIE dwarf node. + * @param print_me the DIE dwarf node containing the DWARF data to explore. diff --git a/src/Namespace.cpp b/src/Namespace.cpp index 27139181..9e2d17e4 100644 --- a/src/Namespace.cpp +++ b/src/Namespace.cpp @@ -28,6 +28,26 @@ void Namespace::setId(int id) { this->id = id; } void Namespace::addChild(Namespace* child) { + if (child == nullptr) + { + return; + } + + // NOTE: It might be better to use a map instead of a vector to store children, maybe... + + // Check child is not already in the list using fully qualified name + for (auto& c : children) + { + std::string c_fqn = c->getFullyQualifiedName(); + std::string child_fqn = child->getFullyQualifiedName(); + if (c_fqn == child_fqn) + { + // log error + // Logger::getInstance().logError("Namespace::addChild: Child already exists in the list"); + return; + } + } + child->setParent(this); children.push_back(child); // fullyQualifiedName += separator + child->getName(); diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index ca5bc400..a0a4a803 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -1976,16 +1976,59 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std sqlite3_bind_int(stmt, 2, parentID.value_or(-1)); + std::string fqn = namespace_->getFullyQualifiedName(); + + sqlite3_bind_text(stmt, 3, fqn.c_str(), -1, SQLITE_STATIC); + + rc = sqlite3_step(stmt); + + // Execute the SQL statement + if (rc != SQLITE_DONE) + { + const char* errorMessage = sqlite3_errmsg(database); + if (SQLITE_OK == rc) + { + logger.logDebug( + "Elf values were written to the encodings schema with " + "SQLITE_OK status."); + } + else + { + if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) + { + logger.logDebug("%s.", errorMessage); + rc = SQLITE_OK; + } + else + { + logger.logDebug("There was an error while writing data to the encodings table."); + logger.logDebug("%s.", errorMessage); + rc = SQLITEDB_ERROR; + } + } + } + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) + { + logger.logDebug("There was an error while finalizing the sql statement for encodings table."); + } + else + { + lastRowId = sqlite3_last_insert_rowid(database); + + namespace_->setId(lastRowId); + } + if (namespace_->getChildren().size() > 0) { + int lastRowID = writeNamespacesToDatabase(namespace_->getChildren(), namespace_->getId()); for (auto& child : namespace_->getChildren()) { // Parent is the current namespace. So we need to write it to the database first. // Then we can get the id of the parent (and store it in parentID) and write it to the child. - - int lastRowID = writeNamespacesToDatabase(child->getChildren(), parentID); - // if (!child->getId().has_value()) // { // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; @@ -2047,51 +2090,6 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std { // sqlite3_bind_int(stmt, 3, -1); } - - std::string fqn = namespace_->getFullyQualifiedName(); - - sqlite3_bind_text(stmt, 3, fqn.c_str(), -1, SQLITE_STATIC); - - rc = sqlite3_step(stmt); - - // Execute the SQL statement - if (rc != SQLITE_DONE) - { - const char* errorMessage = sqlite3_errmsg(database); - if (SQLITE_OK == rc) - { - logger.logDebug( - "Elf values were written to the encodings schema with " - "SQLITE_OK status."); - } - else - { - if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - { - logger.logDebug("%s.", errorMessage); - rc = SQLITE_OK; - } - else - { - logger.logDebug("There was an error while writing data to the encodings table."); - logger.logDebug("%s.", errorMessage); - rc = SQLITEDB_ERROR; - } - } - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) - { - logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - } - else - { - lastRowId = sqlite3_last_insert_rowid(database); - - namespace_->setId(lastRowId); - } } } @@ -2100,8 +2098,8 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std int SQLiteDB::writeAllNamespacesToDatabase(ElfFile& inElf) { - int rc = SQLITEDB_OK; - char* errorMessage = NULL; + int rc = SQLITEDB_OK; + char* errorMessage = NULL; std::vector namespacesPointers{}; diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index f3d39c28..a4216f69 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -215,7 +215,7 @@ class SQLiteDB : public IDataContainer int writeEnumerationsToDatabase(ElfFile &inModule); int writeDimensionsListToDatabase(ElfFile &inElf); int writeEncodingsToDatabase(ElfFile &inElf); - int writeNamespacesToDatabase(std::vector &namespaces, std::optional parentID); + int writeNamespacesToDatabase(std::vector &namespaces, std::optional parentID); int writeAllNamespacesToDatabase(ElfFile &inElf); static int doesRowExistCallback(void *veryUsed, int argc, char **argv, char **azColName); bool doesSymbolExist(std::string name); From 2f4577d48df63836a6097e8b7d27c9f1b31362da Mon Sep 17 00:00:00 2001 From: lgomez Date: Thu, 9 Jan 2025 18:13:12 -0600 Subject: [PATCH 11/20] -Minimally working impl for namespaces. Needs to be cleaned up and linked to structs. WIP. --- src/ElfFile.cpp | 3 +- src/Juicer.cpp | 380 ++++++++++++++++++++++++++++++++++++++++++++-- src/Juicer.h | 1 + src/Namespace.cpp | 10 +- src/Namespace.hpp | 2 +- src/SQLiteDB.cpp | 61 -------- 6 files changed, 373 insertions(+), 84 deletions(-) diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index 6a87fd8a..2f5c9ebf 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -254,7 +254,6 @@ void ElfFile::addNamespace(Namespace newNamespace) namespaces.push_back(std::make_unique(newNamespace)); } - void ElfFile::addNamespace(std::unique_ptr newNamespace) { // Check if the namespace already exists @@ -273,7 +272,7 @@ Namespace* ElfFile::getNamespace(std::string name) { for (auto&& namespace_ : namespaces) { - if (namespace_->getName() == name) + if (namespace_->getFullyQualifiedName() == name) { return namespace_.get(); } diff --git a/src/Juicer.cpp b/src/Juicer.cpp index a2c35b65..5d61f17b 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -404,6 +404,7 @@ int Juicer::readCUList(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Error &error) } return_value = getDieAndSiblings(elf, dbg, cu_die, 0, nullptr); + // return_value = getDieAndSiblingsNamespaces(elf, dbg, cu_die, 0, nullptr); } if (JUICER_OK != return_value) @@ -637,6 +638,8 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in int res = 0; Namespace ns{}; + // Need to figure out if this die has already been processed. + res = dwarf_attr(inDie, DW_AT_name, &attr_struct, &error); if (res != DW_DLV_OK) { @@ -654,18 +657,59 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in std::cout << "Namespace: " << name << std::endl; } + bool namespaceExists = false; + std::string strName{name}; + + if (strName == "_4D") + { + printf("break here.....\n"); + } + + std::string currentNamespaceFQN = name; + + if (currentNamespace) + { + currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; + } + + // currentNamespaceFQN = currentNamespace->getFullyQualifiedName(); + // // check if namespace already exists // TODO: Need to think about the edge case where the namespace already exists but at a different level, meaning they are not the same namespace. // I think they way to go might be to use the fully qualified name of the namespace. - // for (auto &ns : elf.getNamespaces() ) - // { - // if (ns->getName() == name && currentNamespace == nullptr) - // { - // return DW_DLV_OK; - // break; - // } - // } + for (auto &ns : elf.getNamespaces()) + { + if (currentNamespace != nullptr) + { + std::string nsFQN = ns->getFullyQualifiedName(); + + if (nsFQN == currentNamespaceFQN) + { + return DW_DLV_OK; + namespaceExists = true; + break; + } + else + { + printf("break here.....\n"); + } + } + + else + { + if (ns->getName() == name) + { + return DW_DLV_OK; + namespaceExists = true; + break; + } + } + } + if (namespaceExists) + { + return DW_DLV_OK; + } std::unique_ptr nsPtr = std::make_unique(); if (res == DW_DLV_OK) @@ -682,9 +726,10 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in else { - currentNamespace = elf.getNamespace(name); + // currentNamespace = elf.getNamespace(name); // currentNamespace = nsPtr.get(); } + currentNamespace = elf.getNamespace(name); // elf.addNamespace(std::move(nsPtr)); } @@ -699,7 +744,7 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in } else if (res == DW_DLV_OK) { - int res = getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); + int res = getDieAndSiblingsNamespaces(elf, dbg, child, in_level + 1, currentNamespace); } currentNamespace = nullptr; @@ -4383,6 +4428,220 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) return isSupported; } +int Juicer::getDieAndSiblingsNamespaces(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace *currentNamespace) +{ + int res = DW_DLV_ERROR; + Dwarf_Die cur_die = in_die; + Dwarf_Die child = 0; + Dwarf_Error error = 0; + char *dieName; + Dwarf_Attribute attr_struct; + int return_value = JUICER_OK; + + Symbol *outSymbol = nullptr; + + for (;;) + { + Dwarf_Die sib_die = 0; + Dwarf_Half tag = 0; + Dwarf_Off offset = 0; + + res = dwarf_dieoffset(cur_die, &offset, &error); + + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_dieoffset , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + } + + DisplayDie(cur_die, in_level); + + res = dwarf_tag(cur_die, &tag, &error); + + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + } + + if (DW_DLV_OK == res) + { + bool isDwarfSupported = isDWARFVersionSupported(cur_die); + + if (isDwarfSupported == false) + { + logger.logWarning("This DWARF version is not supported for this die. At the moment only DWARF Version 4 is supported."); + } + } + + switch (tag) + { + // case DW_TAG_base_type: + // { + // process_DW_TAG_base_type(elf, dbg, cur_die); + + // break; + // } + + // case DW_TAG_typedef: + // { + // process_DW_TAG_typedef(elf, dbg, cur_die); + + // break; + // } + + // case DW_TAG_structure_type: + // { + // res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + // if (res == DW_DLV_OK) + // { + // res = dwarf_formstring(attr_struct, &dieName, &error); + // if (res != DW_DLV_OK) + // { + // logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + // } + // else + // { + // Dwarf_Unsigned byteSize; + // unsigned long long file_path_numbr = 0; + // res = dwarf_bytesize(cur_die, &byteSize, &error); + // std::string sDieName{dieName}; + + // res = dwarf_attr(cur_die, DW_AT_decl_file, &attr_struct, &error); + + // if (DW_DLV_OK == res) + // { + // unsigned long long pathIndex = 0; + // res = dwarf_formudata(attr_struct, &pathIndex, &error); + + // /** + // * According to 6.2 Line Number Information in DWARF 4: + // * Line number information generated for a compilation unit is represented in the .debug_line + // * section of an object file and is referenced by a corresponding compilation unit debugging + // * information entry (see Section 3.1.1) in the .debug_info section. + // * This is why we are using dwarf_siblingof_b instead of dwarf_siblingof and setting + // * the is_info to true. + // * + // * We are using a new Dwarf_Die because if we use cur_die, we segfault. + // * + // * My theory on this is that even though when we initially call dwarf_siblingof on + // * cur_die and as we read different kinds of tags/attributes(in particular type-related), + // * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. + // * + // * Notice that in + // * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 + // * + // * This is just a a theory, however. In the future we may revisit this + // * to figure out the root cause of this. + // * + // */ + + // if (pathIndex != 0) + // { + // /** + // * Why we are checking against 0 as per DWARF section 2.14: + // * + // * The value of the DW_AT_decl_file attribute corresponds to a file number from the line number + // * information table for the compilation unit containing the debugging information entry and + // * represents the source file in which the declaration appeared (see Section 6.2 ). The value 0 + // * indicates that no source file has been specified. + // * + // */ + // Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; + // std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); + // newArtifact.setMD5(checkSum); + // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + // } + // else + // { + // Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; + // std::string checkSum{}; + // newArtifact.setMD5(checkSum); + // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + // } + // } + // else + // { + // Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; + // std::string checkSum{}; + // newArtifact.setMD5(checkSum); + // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + // } + + // process_DW_TAG_structure_type(elf, *outSymbol, dbg, cur_die); + // } + // } + + // break; + // } + // case DW_TAG_array_type: + // { + // Symbol s{elf}; + + // res = process_DW_TAG_array_type(elf, s, dbg, cur_die); + + // break; + // } + + // case DW_TAG_variable: + // { + // if (extras) + // { + // process_DW_TAG_variable_type(elf, dbg, cur_die); + // } + // break; + // } + + case DW_TAG_namespace: + { + res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); + break; + } + } + + // iterate through all children at this level + + // res = dwarf_child(cur_die, &child, &error); + // if (res == DW_DLV_ERROR) + // { + // logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // return_value = JUICER_ERROR; + // } + // else if (res == DW_DLV_OK) + // { + // // getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); + // } + + // currentNamespace = nullptr; + + /* res == DW_DLV_NO_ENTRY */ + res = dwarf_siblingof(dbg, cur_die, &sib_die, &error); + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_siblingof , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + } + + if (res == DW_DLV_NO_ENTRY) + { + /* Done at this level. */ + break; + } + + /* res == DW_DLV_OK */ + if (cur_die != in_die) + { + dwarf_dealloc(dbg, cur_die, DW_DLA_DIE); + } + + cur_die = sib_die; + } + + // currentNamespace = nullptr; + + return return_value; +} + /** * @brief Inspects the data on the die and its own children recursively. * @param in_die the die entry that has the dwarf data. @@ -4402,6 +4661,9 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i Symbol *outSymbol = nullptr; + std::string namespaceName{""}; + Namespace* newParentNamespace = nullptr; + for (;;) { Dwarf_Die sib_die = 0; @@ -4556,7 +4818,97 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i case DW_TAG_namespace: { - res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); + // res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); + // getDieAndSiblingsNamespaces(elf, dbg, cur_die, in_level, currentNamespace); + Dwarf_Attribute attr_struct; + Dwarf_Error error = 0; + char *name = nullptr; + int res = 0; + Namespace ns{}; + + // Need to figure out if this die has already been processed. + + res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + std::cout << "Namespace: " << name << std::endl; + } + + bool namespaceExists = false; + namespaceName = name; + + if (namespaceName == "Universe") + { + printf("break here.....\n"); + } + + std::string currentNamespaceFQN = name; + + if (currentNamespace) + { + currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; + } + // // check if namespace already exists + // TODO: Need to think about the edge case where the namespace already exists but at a different level, meaning they are not the same namespace. + // I think they way to go might be to use the fully qualified name of the namespace. + for (auto &ns : elf.getNamespaces()) + { + if (currentNamespace != nullptr) + { + std::string nsFQN = ns->getFullyQualifiedName(); + + if (nsFQN == currentNamespaceFQN) + { + // return DW_DLV_OK; + namespaceExists = true; + break; + } + else + { + printf("break here.....\n"); + } + } + + else + { + if (ns->getName() == name) + { + // return DW_DLV_OK; + namespaceExists = true; + break; + } + } + } + + if (!namespaceExists) + { + std::unique_ptr nsPtr = std::make_unique(); + + if (res == DW_DLV_OK) + { + ns.setName(name); + ns.setParent(currentNamespace); + elf.addNamespace(ns); + newParentNamespace = elf.getNamespace(ns.getFullyQualifiedName()); + + if (currentNamespace != nullptr) + { + currentNamespace->addChild(elf.getNamespace(ns.getFullyQualifiedName())); + } + } + } + break; } } @@ -4571,11 +4923,9 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i } else if (res == DW_DLV_OK) { - getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); + getDieAndSiblings(elf, dbg, child, in_level + 1, newParentNamespace); } - // currentNamespace = nullptr; - /* res == DW_DLV_NO_ENTRY */ res = dwarf_siblingof(dbg, cur_die, &sib_die, &error); if (res == DW_DLV_ERROR) @@ -4599,8 +4949,6 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i cur_die = sib_die; } - // currentNamespace = nullptr; - return return_value; } diff --git a/src/Juicer.h b/src/Juicer.h index b4078825..625f9131 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -113,6 +113,7 @@ class Juicer Dwarf_Ptr errarg = 0; int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); + int getDieAndSiblingsNamespaces(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); diff --git a/src/Namespace.cpp b/src/Namespace.cpp index 9e2d17e4..d761bbb1 100644 --- a/src/Namespace.cpp +++ b/src/Namespace.cpp @@ -50,15 +50,17 @@ void Namespace::addChild(Namespace* child) child->setParent(this); children.push_back(child); - // fullyQualifiedName += separator + child->getName(); } std::string Namespace::getFullyQualifiedName() { - while (parent != nullptr) + // Ensure we don't set the member parent to nullptr + Namespace* tmpParent = parent; + fullyQualifiedName = name; + while (tmpParent != nullptr) { - fullyQualifiedName = parent->getName() + separator + fullyQualifiedName; - parent = parent->getParent(); + fullyQualifiedName = tmpParent->getName() + separator + fullyQualifiedName; + tmpParent = tmpParent->getParent(); } return fullyQualifiedName; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp index 7518daa9..24c6da4e 100644 --- a/src/Namespace.hpp +++ b/src/Namespace.hpp @@ -25,6 +25,7 @@ class Namespace // std::string& getFullyQualifiedName() { return fullyQualifiedName; } std::string getFullyQualifiedName(); + void setParent(Namespace* parent); private: std::string name; @@ -36,7 +37,6 @@ class Namespace Namespace* child{nullptr}; std::optional id{std::nullopt}; - void setParent(Namespace* parent); // std::vector symbols; }; diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index a0a4a803..5d3f9db8 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -2110,67 +2110,6 @@ int SQLiteDB::writeAllNamespacesToDatabase(ElfFile& inElf) writeNamespacesToDatabase(namespacesPointers, std::nullopt); - // for (auto&& namespace_ : inElf.getNamespaces()) - // { - // std::string writeNamespaceQuery{}; - - // sqlite3_stmt* stmt; - // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; - - // // Prepare the SQL statement - // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - // if (rc != SQLITE_OK) - // { - // std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; - // } - // else - // { - // // Bind values to placeholders - // sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); - // rc = sqlite3_step(stmt); - - // // Execute the SQL statement - // if (rc != SQLITE_DONE) - // { - // const char* errorMessage = sqlite3_errmsg(database); - // if (SQLITE_OK == rc) - // { - // logger.logDebug( - // "Elf values were written to the encodings schema with " - // "SQLITE_OK status."); - // } - // else - // { - // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - // { - // logger.logDebug("%s.", errorMessage); - // rc = SQLITE_OK; - // } - // else - // { - // logger.logDebug("There was an error while writing data to the encodings table."); - // logger.logDebug("%s.", errorMessage); - // rc = SQLITEDB_ERROR; - // } - // } - // } - - // // Finalize the statement - // rc = sqlite3_finalize(stmt); - // if (rc != SQLITE_OK) - // { - // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - // } - // else - // { - // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - // namespace_->setId(lastRowId); - // } - // } - // } - for (auto&& namespace_ : inElf.getNamespaces()) { // Check if namespace already exists in database From 2cf67db6476c478cfa3fa57df50a7b4737e8400f Mon Sep 17 00:00:00 2001 From: lgomez Date: Thu, 9 Jan 2025 18:13:52 -0600 Subject: [PATCH 12/20] -Update unit tests for namespaces --- unit-test/namespaces_test.cpp | 48 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/unit-test/namespaces_test.cpp b/unit-test/namespaces_test.cpp index e0782e05..125ec391 100644 --- a/unit-test/namespaces_test.cpp +++ b/unit-test/namespaces_test.cpp @@ -1,36 +1,52 @@ namespace Universe { -namespace World +namespace Earth { struct Shape { int width; int length; }; -} // namespace World + +} // namespace Earth + +namespace Mars +{ +struct Shape +{ + int width; + int length; +}; +} // namespace Mars } // namespace Universe -namespace Universe +namespace Plane +{ +namespace _3D { +struct Shape +{ + int width; + int length; +}; +} // namespace _3D -struct Shape2 +namespace _4D +{ +namespace Universe +{ +struct Shape { int width; int length; }; } // namespace Universe +} // namespace _4D -class WorldClass -{ - public: - struct Shape - { - int width; - int length; - }; -}; // namespace World +} // namespace Plane +Universe::Earth::Shape earth{}; +// Universe::Mars::Shape mars{}; -Universe::World::Shape myShape{}; +// Plane::_3D::Shape Space{}; -Universe::Shape2 myShape2{}; -WorldClass::Shape classyShape{}; +Plane::_4D::Universe::Shape Star{}; From da5d37cf7eb85d6d0def6e91fc3cd5f500476387 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 10 Jan 2025 09:47:04 -0600 Subject: [PATCH 13/20] -Format code --- src/Juicer.cpp | 2 +- src/Namespace.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 5d61f17b..5294b30c 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -4662,7 +4662,7 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i Symbol *outSymbol = nullptr; std::string namespaceName{""}; - Namespace* newParentNamespace = nullptr; + Namespace *newParentNamespace = nullptr; for (;;) { diff --git a/src/Namespace.hpp b/src/Namespace.hpp index 24c6da4e..c699e710 100644 --- a/src/Namespace.hpp +++ b/src/Namespace.hpp @@ -25,7 +25,7 @@ class Namespace // std::string& getFullyQualifiedName() { return fullyQualifiedName; } std::string getFullyQualifiedName(); - void setParent(Namespace* parent); + void setParent(Namespace* parent); private: std::string name; From 273e766397a29c3a6b42960b3a30fa3b337be3a8 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 10 Jan 2025 11:38:26 -0600 Subject: [PATCH 14/20] -Cleanup --- src/Juicer.cpp | 413 +++++-------------------------------------------- src/Juicer.h | 1 - 2 files changed, 35 insertions(+), 379 deletions(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 5294b30c..6a2212c0 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -404,7 +404,6 @@ int Juicer::readCUList(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Error &error) } return_value = getDieAndSiblings(elf, dbg, cu_die, 0, nullptr); - // return_value = getDieAndSiblingsNamespaces(elf, dbg, cu_die, 0, nullptr); } if (JUICER_OK != return_value) @@ -636,118 +635,6 @@ int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in Dwarf_Error error = 0; char *name = nullptr; int res = 0; - Namespace ns{}; - - // Need to figure out if this die has already been processed. - - res = dwarf_attr(inDie, DW_AT_name, &attr_struct, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); - } - - if (res == DW_DLV_OK) - { - res = dwarf_formstring(attr_struct, &name, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - } - - std::cout << "Namespace: " << name << std::endl; - } - - bool namespaceExists = false; - std::string strName{name}; - - if (strName == "_4D") - { - printf("break here.....\n"); - } - - std::string currentNamespaceFQN = name; - - if (currentNamespace) - { - currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; - } - - // currentNamespaceFQN = currentNamespace->getFullyQualifiedName(); - - // // check if namespace already exists - // TODO: Need to think about the edge case where the namespace already exists but at a different level, meaning they are not the same namespace. - // I think they way to go might be to use the fully qualified name of the namespace. - for (auto &ns : elf.getNamespaces()) - { - if (currentNamespace != nullptr) - { - std::string nsFQN = ns->getFullyQualifiedName(); - - if (nsFQN == currentNamespaceFQN) - { - return DW_DLV_OK; - namespaceExists = true; - break; - } - else - { - printf("break here.....\n"); - } - } - - else - { - if (ns->getName() == name) - { - return DW_DLV_OK; - namespaceExists = true; - break; - } - } - } - - if (namespaceExists) - { - return DW_DLV_OK; - } - std::unique_ptr nsPtr = std::make_unique(); - - if (res == DW_DLV_OK) - { - ns.setName(name); - // nsPtr->setName(name); - elf.addNamespace(ns); - - if (currentNamespace != nullptr) - { - currentNamespace->addChild(elf.getNamespace(name)); - // currentNamespace->addChild(nsPtr.get()); - } - - else - { - // currentNamespace = elf.getNamespace(name); - // currentNamespace = nsPtr.get(); - } - currentNamespace = elf.getNamespace(name); - - // elf.addNamespace(std::move(nsPtr)); - } - - Dwarf_Die child; - res = dwarf_child(inDie, &child, &error); - - if (res == DW_DLV_ERROR) - { - logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - res = JUICER_ERROR; - } - else if (res == DW_DLV_OK) - { - int res = getDieAndSiblingsNamespaces(elf, dbg, child, in_level + 1, currentNamespace); - } - - currentNamespace = nullptr; return res; } @@ -4428,219 +4315,6 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) return isSupported; } -int Juicer::getDieAndSiblingsNamespaces(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace *currentNamespace) -{ - int res = DW_DLV_ERROR; - Dwarf_Die cur_die = in_die; - Dwarf_Die child = 0; - Dwarf_Error error = 0; - char *dieName; - Dwarf_Attribute attr_struct; - int return_value = JUICER_OK; - - Symbol *outSymbol = nullptr; - - for (;;) - { - Dwarf_Die sib_die = 0; - Dwarf_Half tag = 0; - Dwarf_Off offset = 0; - - res = dwarf_dieoffset(cur_die, &offset, &error); - - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_dieoffset , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - return_value = JUICER_ERROR; - } - - DisplayDie(cur_die, in_level); - - res = dwarf_tag(cur_die, &tag, &error); - - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - return_value = JUICER_ERROR; - } - - if (DW_DLV_OK == res) - { - bool isDwarfSupported = isDWARFVersionSupported(cur_die); - - if (isDwarfSupported == false) - { - logger.logWarning("This DWARF version is not supported for this die. At the moment only DWARF Version 4 is supported."); - } - } - - switch (tag) - { - // case DW_TAG_base_type: - // { - // process_DW_TAG_base_type(elf, dbg, cur_die); - - // break; - // } - - // case DW_TAG_typedef: - // { - // process_DW_TAG_typedef(elf, dbg, cur_die); - - // break; - // } - - // case DW_TAG_structure_type: - // { - // res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); - // if (res == DW_DLV_OK) - // { - // res = dwarf_formstring(attr_struct, &dieName, &error); - // if (res != DW_DLV_OK) - // { - // logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - // } - // else - // { - // Dwarf_Unsigned byteSize; - // unsigned long long file_path_numbr = 0; - // res = dwarf_bytesize(cur_die, &byteSize, &error); - // std::string sDieName{dieName}; - - // res = dwarf_attr(cur_die, DW_AT_decl_file, &attr_struct, &error); - - // if (DW_DLV_OK == res) - // { - // unsigned long long pathIndex = 0; - // res = dwarf_formudata(attr_struct, &pathIndex, &error); - - // /** - // * According to 6.2 Line Number Information in DWARF 4: - // * Line number information generated for a compilation unit is represented in the .debug_line - // * section of an object file and is referenced by a corresponding compilation unit debugging - // * information entry (see Section 3.1.1) in the .debug_info section. - // * This is why we are using dwarf_siblingof_b instead of dwarf_siblingof and setting - // * the is_info to true. - // * - // * We are using a new Dwarf_Die because if we use cur_die, we segfault. - // * - // * My theory on this is that even though when we initially call dwarf_siblingof on - // * cur_die and as we read different kinds of tags/attributes(in particular type-related), - // * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. - // * - // * Notice that in - // * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 - // * - // * This is just a a theory, however. In the future we may revisit this - // * to figure out the root cause of this. - // * - // */ - - // if (pathIndex != 0) - // { - // /** - // * Why we are checking against 0 as per DWARF section 2.14: - // * - // * The value of the DW_AT_decl_file attribute corresponds to a file number from the line number - // * information table for the compilation unit containing the debugging information entry and - // * represents the source file in which the declaration appeared (see Section 6.2 ). The value 0 - // * indicates that no source file has been specified. - // * - // */ - // Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; - // std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); - // newArtifact.setMD5(checkSum); - // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); - // } - // else - // { - // Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; - // std::string checkSum{}; - // newArtifact.setMD5(checkSum); - // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); - // } - // } - // else - // { - // Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; - // std::string checkSum{}; - // newArtifact.setMD5(checkSum); - // outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); - // } - - // process_DW_TAG_structure_type(elf, *outSymbol, dbg, cur_die); - // } - // } - - // break; - // } - // case DW_TAG_array_type: - // { - // Symbol s{elf}; - - // res = process_DW_TAG_array_type(elf, s, dbg, cur_die); - - // break; - // } - - // case DW_TAG_variable: - // { - // if (extras) - // { - // process_DW_TAG_variable_type(elf, dbg, cur_die); - // } - // break; - // } - - case DW_TAG_namespace: - { - res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); - break; - } - } - - // iterate through all children at this level - - // res = dwarf_child(cur_die, &child, &error); - // if (res == DW_DLV_ERROR) - // { - // logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // return_value = JUICER_ERROR; - // } - // else if (res == DW_DLV_OK) - // { - // // getDieAndSiblings(elf, dbg, child, in_level + 1, currentNamespace); - // } - - // currentNamespace = nullptr; - - /* res == DW_DLV_NO_ENTRY */ - res = dwarf_siblingof(dbg, cur_die, &sib_die, &error); - if (res == DW_DLV_ERROR) - { - logger.logError("Error in dwarf_siblingof , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - return_value = JUICER_ERROR; - } - - if (res == DW_DLV_NO_ENTRY) - { - /* Done at this level. */ - break; - } - - /* res == DW_DLV_OK */ - if (cur_die != in_die) - { - dwarf_dealloc(dbg, cur_die, DW_DLA_DIE); - } - - cur_die = sib_die; - } - - // currentNamespace = nullptr; - - return return_value; -} /** * @brief Inspects the data on the die and its own children recursively. @@ -4819,16 +4493,17 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i case DW_TAG_namespace: { // res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); - // getDieAndSiblingsNamespaces(elf, dbg, cur_die, in_level, currentNamespace); Dwarf_Attribute attr_struct; Dwarf_Error error = 0; char *name = nullptr; int res = 0; Namespace ns{}; + bool namespaceExists = false; + // Need to figure out if this die has already been processed. - res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); if (res != DW_DLV_OK) { logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); @@ -4842,69 +4517,51 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); } - std::cout << "Namespace: " << name << std::endl; - } - - bool namespaceExists = false; - namespaceName = name; - - if (namespaceName == "Universe") - { - printf("break here.....\n"); - } + namespaceName = name; - std::string currentNamespaceFQN = name; + std::string currentNamespaceFQN = name; - if (currentNamespace) - { - currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; - } - // // check if namespace already exists - // TODO: Need to think about the edge case where the namespace already exists but at a different level, meaning they are not the same namespace. - // I think they way to go might be to use the fully qualified name of the namespace. - for (auto &ns : elf.getNamespaces()) - { - if (currentNamespace != nullptr) + if (currentNamespace) { - std::string nsFQN = ns->getFullyQualifiedName(); - - if (nsFQN == currentNamespaceFQN) + currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; + } + // check if namespace already exists + for (auto &ns : elf.getNamespaces()) + { + if (currentNamespace != nullptr) { - // return DW_DLV_OK; - namespaceExists = true; - break; + std::string nsFQN = ns->getFullyQualifiedName(); + + if (nsFQN == currentNamespaceFQN) + { + namespaceExists = true; + break; + } } + else { - printf("break here.....\n"); + if (ns->getName() == name) + { + namespaceExists = true; + break; + } } } - else + if (!namespaceExists) { - if (ns->getName() == name) + if (res == DW_DLV_OK) { - // return DW_DLV_OK; - namespaceExists = true; - break; - } - } - } - - if (!namespaceExists) - { - std::unique_ptr nsPtr = std::make_unique(); + ns.setName(name); + ns.setParent(currentNamespace); + elf.addNamespace(ns); + newParentNamespace = elf.getNamespace(ns.getFullyQualifiedName()); - if (res == DW_DLV_OK) - { - ns.setName(name); - ns.setParent(currentNamespace); - elf.addNamespace(ns); - newParentNamespace = elf.getNamespace(ns.getFullyQualifiedName()); - - if (currentNamespace != nullptr) - { - currentNamespace->addChild(elf.getNamespace(ns.getFullyQualifiedName())); + if (currentNamespace != nullptr) + { + currentNamespace->addChild(elf.getNamespace(ns.getFullyQualifiedName())); + } } } } diff --git a/src/Juicer.h b/src/Juicer.h index 625f9131..b4078825 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -113,7 +113,6 @@ class Juicer Dwarf_Ptr errarg = 0; int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); - int getDieAndSiblingsNamespaces(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); From 8df859ab8b1a105646c9e0c689a74ecc56d616b9 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 10 Jan 2025 11:43:24 -0600 Subject: [PATCH 15/20] -Cleanup --- src/Juicer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 6a2212c0..fbb358f2 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -4315,7 +4315,6 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) return isSupported; } - /** * @brief Inspects the data on the die and its own children recursively. * @param in_die the die entry that has the dwarf data. From 8a308e55be08d714c65a4191e17d2613e6dab424 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 10 Jan 2025 11:54:35 -0600 Subject: [PATCH 16/20] -Refactor and cleanup process_DW_TAG_namespace --- src/Juicer.cpp | 155 +++++++++++++++++++++++++------------------------ src/Juicer.h | 2 +- 2 files changed, 80 insertions(+), 77 deletions(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index fbb358f2..86490f28 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -629,14 +629,90 @@ char *Juicer::getFirstAncestorName(Dwarf_Die inDie) return outName; } -int Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace *currentNamespace) +/** + * @brief Add new namespace to elf, if it does not exist. + * + * @return The new namespace that was added. Not that this namespace may be null if it already exists. + */ +Namespace *Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace *currentNamespace) { Dwarf_Attribute attr_struct; Dwarf_Error error = 0; char *name = nullptr; int res = 0; + Namespace ns{}; + std::string namespaceName{}; - return res; + Namespace *newParentNamespace = nullptr; + + bool namespaceExists = false; + + // Need to figure out if this die has already been processed. + + res = dwarf_attr(inDie, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + namespaceName = name; + + std::string currentNamespaceFQN = name; + + if (currentNamespace) + { + currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; + } + // check if namespace already exists + for (auto &ns : elf.getNamespaces()) + { + if (currentNamespace != nullptr) + { + std::string nsFQN = ns->getFullyQualifiedName(); + + if (nsFQN == currentNamespaceFQN) + { + namespaceExists = true; + break; + } + } + + else + { + if (ns->getName() == name) + { + namespaceExists = true; + break; + } + } + } + + if (!namespaceExists) + { + if (res == DW_DLV_OK) + { + ns.setName(name); + ns.setParent(currentNamespace); + elf.addNamespace(ns); + newParentNamespace = elf.getNamespace(ns.getFullyQualifiedName()); + + if (currentNamespace != nullptr) + { + currentNamespace->addChild(elf.getNamespace(ns.getFullyQualifiedName())); + } + } + } + } + + return newParentNamespace; } Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) @@ -4491,80 +4567,7 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i case DW_TAG_namespace: { - // res = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); - Dwarf_Attribute attr_struct; - Dwarf_Error error = 0; - char *name = nullptr; - int res = 0; - Namespace ns{}; - - bool namespaceExists = false; - - // Need to figure out if this die has already been processed. - - res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); - } - - if (res == DW_DLV_OK) - { - res = dwarf_formstring(attr_struct, &name, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - } - - namespaceName = name; - - std::string currentNamespaceFQN = name; - - if (currentNamespace) - { - currentNamespaceFQN = currentNamespace->getFullyQualifiedName() + "::" + name; - } - // check if namespace already exists - for (auto &ns : elf.getNamespaces()) - { - if (currentNamespace != nullptr) - { - std::string nsFQN = ns->getFullyQualifiedName(); - - if (nsFQN == currentNamespaceFQN) - { - namespaceExists = true; - break; - } - } - - else - { - if (ns->getName() == name) - { - namespaceExists = true; - break; - } - } - } - - if (!namespaceExists) - { - if (res == DW_DLV_OK) - { - ns.setName(name); - ns.setParent(currentNamespace); - elf.addNamespace(ns); - newParentNamespace = elf.getNamespace(ns.getFullyQualifiedName()); - - if (currentNamespace != nullptr) - { - currentNamespace->addChild(elf.getNamespace(ns.getFullyQualifiedName())); - } - } - } - } - + newParentNamespace = process_DW_TAG_namespace(elf, dbg, cur_die, in_level, currentNamespace); break; } } diff --git a/src/Juicer.h b/src/Juicer.h index b4078825..9d67d7a3 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -121,7 +121,7 @@ class Juicer void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - int process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); + Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); char* getFirstAncestorName(Dwarf_Die inDie); int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); char* dwarfStringToChar(char* dwarfString); From b2f6c14ce426a24091e1da11e9a03cdf075c4998 Mon Sep 17 00:00:00 2001 From: lgomez Date: Fri, 10 Jan 2025 17:33:21 -0600 Subject: [PATCH 17/20] -Link namespaces to symbols. WIP. -Add unit testing for namespacing. WIP. --- src/ElfFile.cpp | 5 +- src/ElfFile.h | 38 +++--- src/Juicer.cpp | 92 +++++++------- src/Juicer.h | 16 +-- src/SQLiteDB.cpp | 59 +++++++-- src/SQLiteDB.h | 2 + src/Symbol.h | 7 ++ unit-test/main_test.cpp | 220 +++++++++++++++++++++++++++++++++- unit-test/namespaces_test.cpp | 47 +++++++- 9 files changed, 395 insertions(+), 91 deletions(-) diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index 2f5c9ebf..b1415eb0 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -85,7 +85,7 @@ Symbol* ElfFile::getSymbol(std::string& name) return returnSymbol; } -Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact, Symbol* targetSymbol) +Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact, Symbol* targetSymbol, Namespace* symbolNamepace) { Symbol* symbol = getSymbol(inName); @@ -102,13 +102,14 @@ Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact ne return symbol; } -Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact) +Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact, Namespace* symbolNamepace) { Symbol* symbol = getSymbol(inName); if (symbol == nullptr) { std::unique_ptr newSymbol = std::make_unique(*this, inName, inByteSize, newArtifact); + newSymbol->setNamespace(symbolNamepace); symbols.push_back(std::move(newSymbol)); diff --git a/src/ElfFile.h b/src/ElfFile.h index 3907fdf3..dc8c259e 100644 --- a/src/ElfFile.h +++ b/src/ElfFile.h @@ -48,25 +48,25 @@ class ElfFile public: ElfFile(std::string &name); virtual ~ElfFile(); - std::vector> &getSymbols(); - - std::string getName() const; - uint32_t getId(void) const; - void setId(uint32_t newId); - Symbol *addSymbol(std::string &name, uint32_t byte_size, Artifact newArtifact); - Symbol *addSymbol(std::string &inName, uint32_t inByteSize, Artifact newArtifact, Symbol *targetSymbol); - std::vector getFields(); - std::vector getEnumerations(); - Symbol *getSymbol(std::string &name); - const std::string &getDate() const; - void setDate(const std::string &date); - bool isLittleEndian() const; - void isLittleEndian(bool littleEndian); - void setMD5(std::string newID); - std::string getMD5() const; - void addDefineMacro(DefineMacro newMacro); - - const std::vector &getDefineMacros() const; + std::vector> &getSymbols(); + + std::string getName() const; + uint32_t getId(void) const; + void setId(uint32_t newId); + Symbol *addSymbol(std::string &name, uint32_t byte_size, Artifact newArtifact, Namespace *symbolNamepace); + Symbol *addSymbol(std::string &inName, uint32_t inByteSize, Artifact newArtifact, Symbol *targetSymbol, Namespace *symbolNamepace); + std::vector getFields(); + std::vector getEnumerations(); + Symbol *getSymbol(std::string &name); + const std::string &getDate() const; + void setDate(const std::string &date); + bool isLittleEndian() const; + void isLittleEndian(bool littleEndian); + void setMD5(std::string newID); + std::string getMD5() const; + void addDefineMacro(DefineMacro newMacro); + + const std::vector &getDefineMacros() const; const std::map> &getInitializedSymbolData() const; diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 86490f28..a2e9e654 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -449,7 +449,7 @@ char *Juicer::dwarfStringToChar(char *dwarfString) * it does NOT mean that no array was found. There are cases where an array is found on the die, * however, because it has no name we decide to not add it to the elf at all. */ -int Juicer::process_DW_TAG_array_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie) +int Juicer::process_DW_TAG_array_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { Dwarf_Die dieSubrangeType; Dwarf_Unsigned dwfUpperBound = 0; @@ -538,7 +538,7 @@ int Juicer::process_DW_TAG_array_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug */ std::string stdString{arrayName}; - Symbol *arraySymbol = getBaseTypeSymbol(elf, inDie, dimList); + Symbol *arraySymbol = getBaseTypeSymbol(elf, inDie, dimList, currentNamespace); if (nullptr == arraySymbol) { @@ -715,7 +715,7 @@ Namespace *Juicer::process_DW_TAG_namespace(ElfFile &elf, Dwarf_Debug dbg, Dwarf return newParentNamespace; } -Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) +Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { Symbol *outSymbol = 0; Dwarf_Attribute attr_struct = nullptr; @@ -786,7 +786,7 @@ Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(voidType, byteSize, newArtifact); + outSymbol = elf.addSymbol(voidType, byteSize, newArtifact, nullptr); } else { @@ -795,7 +795,7 @@ Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf Artifact newArtifact{elf, "NOT_FOUND:" + voidType}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(voidType, byteSize, newArtifact); + outSymbol = elf.addSymbol(voidType, byteSize, newArtifact, nullptr); } } } @@ -863,14 +863,14 @@ Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf Artifact newArtifact{elf, "NOT_FOUND:" + name}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(name, byteSize, newArtifact); + outSymbol = elf.addSymbol(name, byteSize, newArtifact, currentNamespace); } } return outSymbol; } -Symbol *Juicer::process_DW_TAG_variable_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) +Symbol *Juicer::process_DW_TAG_variable_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { Symbol *outSymbol = 0; Dwarf_Attribute attr_struct = nullptr; @@ -960,7 +960,7 @@ Symbol *Juicer::process_DW_TAG_variable_type(ElfFile &elf, Dwarf_Debug dbg, Dwar DimensionList dimList{}; // TODO:Really don't like the pattern of passing an empty object to getBaseTypeSymbol... - Symbol *s = getBaseTypeSymbol(elf, inDie, dimList); + Symbol *s = getBaseTypeSymbol(elf, inDie, dimList, currentNamespace); if (s != nullptr) { @@ -990,7 +990,7 @@ Symbol *Juicer::process_DW_TAG_variable_type(ElfFile &elf, Dwarf_Debug dbg, Dwar return outSymbol; } -Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList &dimList) +Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList &dimList, Namespace *currentNamespace) { int res = DW_DLV_OK; Dwarf_Attribute attr_struct; @@ -1047,7 +1047,7 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & { case DW_TAG_pointer_type: { - outSymbol = process_DW_TAG_pointer_type(elf, dbg, typeDie); + outSymbol = process_DW_TAG_pointer_type(elf, dbg, typeDie, currentNamespace); break; } @@ -1175,20 +1175,20 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } } if (nullptr != outSymbol) { - process_DW_TAG_structure_type(elf, *outSymbol, dbg, typeDie); + process_DW_TAG_structure_type(elf, *outSymbol, dbg, typeDie, currentNamespace); } } else @@ -1199,20 +1199,20 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } break; } case DW_TAG_base_type: { - outSymbol = process_DW_TAG_base_type(elf, dbg, typeDie); + outSymbol = process_DW_TAG_base_type(elf, dbg, typeDie, currentNamespace); break; } case DW_TAG_typedef: { - outSymbol = process_DW_TAG_typedef(elf, dbg, typeDie); + outSymbol = process_DW_TAG_typedef(elf, dbg, typeDie, currentNamespace); break; } @@ -1348,14 +1348,14 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } } @@ -1364,7 +1364,7 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } process_DW_TAG_enumeration_type(elf, *outSymbol, dbg, typeDie); @@ -1376,7 +1376,7 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & { /* First get the base type itself. */ - outSymbol = getBaseTypeSymbol(elf, typeDie, dimList); + outSymbol = getBaseTypeSymbol(elf, typeDie, dimList, currentNamespace); /* Set the multiplicity argument. */ if (res == DW_DLV_OK) @@ -1399,7 +1399,7 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & /* Get the type attribute. */ res = dwarf_attr(inDie, DW_AT_type, &attr_struct, &error); - getBaseTypeSymbol(elf, typeDie, dimList); + getBaseTypeSymbol(elf, typeDie, dimList, currentNamespace); break; } @@ -1513,20 +1513,20 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } } if (nullptr != outSymbol) { - process_DW_TAG_union_type(elf, *outSymbol, dbg, typeDie); + process_DW_TAG_union_type(elf, *outSymbol, dbg, typeDie, currentNamespace); } } @@ -3308,7 +3308,7 @@ void Juicer::DisplayDie(Dwarf_Die inDie, uint32_t level) // } } -Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) +Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { int res = DW_DLV_OK; Dwarf_Unsigned byteSize = 0; @@ -3434,14 +3434,14 @@ Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Di Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, currentNamespace); } } @@ -3453,7 +3453,7 @@ Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Di Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact); + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } } } @@ -3624,7 +3624,7 @@ void Juicer::process_DW_TAG_enumeration_type(ElfFile &elf, Symbol &symbol, Dwarf * @return 0 if the die, its children and siblings are scanned successfully. * 1 if there is a problem with dies or any of its children. */ -Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) +Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { int res = DW_DLV_OK; uint32_t byteSize = 0; @@ -3658,7 +3658,7 @@ Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die { DimensionList dimensionList{}; - baseTypeSymbol = getBaseTypeSymbol(elf, inDie, dimensionList); + baseTypeSymbol = getBaseTypeSymbol(elf, inDie, dimensionList, currentNamespace); if (baseTypeSymbol == 0) { @@ -3724,14 +3724,14 @@ Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, baseTypeSymbol); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, baseTypeSymbol, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, baseTypeSymbol); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, baseTypeSymbol, currentNamespace); } } } @@ -3746,7 +3746,7 @@ Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die * @return 0 if the die, its children and siblings are scanned successfully. * 1 if there is a problem with dies or any of its children. */ -void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie) +void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { int res = DW_DLV_OK; Dwarf_Attribute attr_struct = nullptr; @@ -3978,7 +3978,7 @@ void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_D /* Get the base type die. */ if (res == DW_DLV_OK) { - memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList); + memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); if (memberBaseTypeSymbol == 0) { @@ -4048,7 +4048,7 @@ void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_D * @return 0 if the die, its children and siblings are scanned successfully. * 1 if there is a problem with dies or any of its children. */ -void Juicer::process_DW_TAG_union_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie) +void Juicer::process_DW_TAG_union_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace *currentNamespace) { int res = DW_DLV_OK; Dwarf_Attribute attr_struct = nullptr; @@ -4137,7 +4137,7 @@ void Juicer::process_DW_TAG_union_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug /* Get the base type die. */ if (res == DW_DLV_OK) { - memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList); + memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); if (memberBaseTypeSymbol == 0) { @@ -4253,7 +4253,7 @@ void Juicer::addPaddingToStruct(Symbol &symbol) std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - paddingSymbol = symbol.getElf().addSymbol(paddingType, paddingSize, newArtifact); + paddingSymbol = symbol.getElf().addSymbol(paddingType, paddingSize, newArtifact, nullptr); } auto &&fields = symbol.getFields(); @@ -4315,7 +4315,7 @@ void Juicer::addPaddingEndToStruct(Symbol &symbol) Artifact newArtifact{symbol.getElf(), symbol.getArtifact().getFilePath()}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - paddingSymbol = symbol.getElf().addSymbol(paddingType, sizeDelta, newArtifact); + paddingSymbol = symbol.getElf().addSymbol(paddingType, sizeDelta, newArtifact, (Namespace *)nullptr); } uint32_t newFieldByteOffset = symbol.getFields().back()->getByteOffset().value() + symbol.getFields().back()->getType().getByteSize(); @@ -4451,14 +4451,14 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i { case DW_TAG_base_type: { - process_DW_TAG_base_type(elf, dbg, cur_die); + process_DW_TAG_base_type(elf, dbg, cur_die, currentNamespace); break; } case DW_TAG_typedef: { - process_DW_TAG_typedef(elf, dbg, cur_die); + process_DW_TAG_typedef(elf, dbg, cur_die, currentNamespace); break; } @@ -4523,14 +4523,14 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, currentNamespace); } } else @@ -4538,10 +4538,10 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i Artifact newArtifact{elf, "NOT_FOUND:" + sDieName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact); + outSymbol = elf.addSymbol(sDieName, byteSize, newArtifact, currentNamespace); } - process_DW_TAG_structure_type(elf, *outSymbol, dbg, cur_die); + process_DW_TAG_structure_type(elf, *outSymbol, dbg, cur_die, currentNamespace); } } @@ -4551,7 +4551,7 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i { Symbol s{elf}; - res = process_DW_TAG_array_type(elf, s, dbg, cur_die); + res = process_DW_TAG_array_type(elf, s, dbg, cur_die, currentNamespace); break; } @@ -4560,7 +4560,7 @@ int Juicer::getDieAndSiblings(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die in_die, i { if (extras) { - process_DW_TAG_variable_type(elf, dbg, cur_die); + process_DW_TAG_variable_type(elf, dbg, cur_die, currentNamespace); } break; } diff --git a/src/Juicer.h b/src/Juicer.h index 9d67d7a3..005648eb 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -113,14 +113,14 @@ class Juicer Dwarf_Ptr errarg = 0; int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); - Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); - Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die); - void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie); - Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie); + Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); + int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); char* getFirstAncestorName(Dwarf_Die inDie); int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); @@ -133,7 +133,7 @@ class Juicer Logger logger; IDataContainer* idc = 0; bool isIDCSet(void); - Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& multiplicity); + Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& dimList, Namespace* currentNamespace); void DisplayDie(Dwarf_Die inDie, uint32_t level); std::vector getChildrenVector(Dwarf_Debug dbg, Dwarf_Die die); diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index 5d3f9db8..b663ac7b 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -315,7 +315,7 @@ int SQLiteDB::write(ElfFile& inElf) else { logger.logDebug( - "There was an error while writing macro entries to the" + "There was an error while writing Artifact entries to the" " database."); rc = SQLITEDB_ERROR; } @@ -333,13 +333,29 @@ int SQLiteDB::write(ElfFile& inElf) if (SQLITEDB_ERROR != rc) { logger.logDebug( - "Variable entries were written to the variables schema " + "Encoding entries were written to the Encodings schema " "with SQLITE_OK status."); + + rc = writeAllNamespacesToDatabase(inElf); + + if (SQLITEDB_ERROR != rc) + { + logger.logDebug( + "Namespace entries were written to the namespaces schema " + "with SQLITE_OK status."); + } + else + { + logger.logDebug( + "There was an error while writing namespace entries to the" + " database."); + rc = SQLITEDB_ERROR; + } } else { logger.logDebug( - "There was an error while writing variable entries to the" + "There was an error while writing Encoding entries to the" " database."); rc = SQLITEDB_ERROR; } @@ -354,14 +370,28 @@ int SQLiteDB::write(ElfFile& inElf) rc = writeFieldsToDatabase(inElf); - writeDimensionsListToDatabase(inElf); - if (SQLITEDB_ERROR != rc) { logger.logDebug( "Field entries were written to the fields schema " "with SQLITE_OK status."); + rc = writeDimensionsListToDatabase(inElf); + + if (SQLITEDB_ERROR != rc) + { + logger.logDebug( + "Field entries were written to the dimension_lists schema " + "with SQLITE_OK status."); + } + else + { + logger.logDebug( + "There was an error while writing dimension_lists entries to the" + " database."); + rc = SQLITEDB_ERROR; + } + rc = writeEnumerationsToDatabase(inElf); if (SQLITEDB_ERROR != rc) @@ -383,7 +413,7 @@ int SQLiteDB::write(ElfFile& inElf) if (SQLITEDB_ERROR != rc) { logger.logDebug( - "Variable entries were written to the variables schema " + "Elf Sections were written to the variables schema " "with SQLITE_OK status."); rc = writeElfSymboltableSymbolsToDatabase(inElf); @@ -391,10 +421,8 @@ int SQLiteDB::write(ElfFile& inElf) if (SQLITEDB_ERROR != rc) { logger.logDebug( - "Variable entries were written to the variables schema " + "Elf Symbol Table Symbols entries were written to the variables schema " "with SQLITE_OK status."); - - rc = writeAllNamespacesToDatabase(inElf); } else { @@ -1184,7 +1212,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) if (!symbol->getEncoding()) { writeSymbolQuery += - "INSERT INTO symbols(elf, name, byte_size, artifact, long_description, short_description) " + "INSERT INTO symbols(elf, name, byte_size, artifact, namespace, long_description, short_description) " "VALUES("; writeSymbolQuery += std::to_string(symbol->getElf().getId()); writeSymbolQuery += ",\""; @@ -1195,6 +1223,17 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += ","; writeSymbolQuery += std::to_string(symbol->getArtifact().getId()); + writeSymbolQuery += ","; + + if (symbol->getNamespace() != nullptr) + { + writeSymbolQuery += std::to_string(symbol->getNamespace()->getId().value()); + } + else + { + writeSymbolQuery += "-1"; + } + writeSymbolQuery += ",\""; writeSymbolQuery += symbol->getLongDescription(); diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index a4216f69..1632abec 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -42,12 +42,14 @@ artifact INTEGER,\ target_symbol INTEGER,\ encoding INTEGER,\ + namespace INTEGER,\ short_description TEXT ,\ long_description TEXT ,\ FOREIGN KEY(elf) REFERENCES elfs(id),\ FOREIGN KEY(artifact) REFERENCES artifacts(id)\ FOREIGN KEY(target_symbol) REFERENCES symbols(id)\ FOREIGN KEY(encoding) REFERENCES encodings(id)\ + FOREIGN KEY(namespace) REFERENCES namespaces(id)\ UNIQUE(name));" #define CREATE_DIMENSION_TABLE \ diff --git a/src/Symbol.h b/src/Symbol.h index 53246be4..327595f7 100644 --- a/src/Symbol.h +++ b/src/Symbol.h @@ -20,6 +20,7 @@ #include "Enumeration.h" #include "Field.h" #include "Logger.h" +#include "Namespace.hpp" class Field; class Enumeration; @@ -73,6 +74,10 @@ class Symbol std::optional getEncoding(); + void setNamespace(Namespace *newNamespace) { namespace_ = newNamespace; } + + Namespace *getNamespace() { return namespace_; } + private: ElfFile &elf; std::string name; @@ -88,6 +93,8 @@ class Symbol std::string long_description; std::optional encoding{std::nullopt}; + + Namespace *namespace_{nullptr}; }; #endif /* SYMBOL_H_ */ diff --git a/unit-test/main_test.cpp b/unit-test/main_test.cpp index e18eab81..f85a68a9 100644 --- a/unit-test/main_test.cpp +++ b/unit-test/main_test.cpp @@ -29,6 +29,8 @@ #define TEST_FILE_4 "ut_obj/macro_test.o" +#define TEST_FILE_5 "ut_obj/namespaces_test.o" + // DO NOT rename this macro to something like SQLITE_NULL as that is a macro that exists in sqlite3 #define TEST_NULL_STR "NULL" @@ -1119,7 +1121,7 @@ TEST_CASE("Test the correctness of the Square struct after Juicer has processed numberOfColumns++; } - REQUIRE(numberOfColumns == 9); + REQUIRE(numberOfColumns == 10); /** * Check the correctness of Square struct. @@ -1565,7 +1567,7 @@ TEST_CASE( numberOfColumns++; } - REQUIRE(numberOfColumns == 9); + REQUIRE(numberOfColumns == 10); /** * Check the correctness of CFE_ES_HousekeepingTlm_Payload_t struct. @@ -2666,7 +2668,7 @@ TEST_CASE("Test 32-bit binary.", "[main_test#10]") numberOfColumns++; } - REQUIRE(numberOfColumns == 9); + REQUIRE(numberOfColumns == 10); /** * Check the correctness of Square struct. @@ -3389,7 +3391,7 @@ TEST_CASE("Test the correctness of bit fields.", "[main_test#20]") numberOfColumns++; } - REQUIRE(numberOfColumns == 9); + REQUIRE(numberOfColumns == 10); REQUIRE(symbolRecords.at(0).at("byte_size") == std::to_string(sizeof(S))); @@ -3497,6 +3499,216 @@ TEST_CASE("Test the correctness of bit fields.", "[main_test#20]") // REQUIRE(fieldsRecords.at(1)["short_description"] == ""); // REQUIRE(fieldsRecords.at(1)["long_description"] == ""); + REQUIRE(remove("./test_db.sqlite") == 0); + delete idc; +} + +TEST_CASE("Test the correctness of namespaces.", "[main_test#21]") +{ + /** + * This assumes that the test_file was compiled on + * gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 or gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0 + * little-endian machine. + */ + + Juicer juicer; + IDataContainer* idc = 0; + Logger logger; + int rc = 0; + char* errorMessage = nullptr; + std::string little_endian = is_little_endian() ? "1" : "0"; + + logger.logWarning("This is just a test."); + std::string inputFile{TEST_FILE_5}; + + idc = IDataContainer::Create(IDC_TYPE_SQLITE, "./test_db.sqlite"); + REQUIRE(idc != nullptr); + logger.logInfo("IDataContainer was constructed successfully for unit test."); + + juicer.setIDC(idc); + + rc = juicer.parse(inputFile); + + REQUIRE((juicer.getDwarfVersion() == 4 || juicer.getDwarfVersion() == 5)); + + REQUIRE(rc == JUICER_OK); + + REQUIRE(rc == JUICER_OK); + + std::string getNamespacesQuery{"SELECT * FROM namespaces;"}; + + /** + *Clean up our database handle and objects in memory. + */ + ((SQLiteDB*)(idc))->close(); + + sqlite3* database; + + rc = sqlite3_open("./test_db.sqlite", &database); + + REQUIRE(rc == SQLITE_OK); + + std::vector> namespaceRecords{}; + + rc = sqlite3_exec(database, getNamespacesQuery.c_str(), selectCallbackUsingColNameAsKey, &namespaceRecords, &errorMessage); + + REQUIRE(rc == SQLITE_OK); + REQUIRE(namespaceRecords.size() == 8); + + uint32_t numberOfColumns = 0; + + for (auto pair : namespaceRecords.at(0)) + { + numberOfColumns++; + } + + REQUIRE(numberOfColumns == 4); + + std::string getUniverse4DNamespaceQuery{"SELECT * FROM namespaces WHERE fully_qualified_name = \"Plane::_4D::Universe\";"}; + + std::vector> namespaceUniverse4DRecords{}; + + rc = sqlite3_exec(database, getUniverse4DNamespaceQuery.c_str(), selectCallbackUsingColNameAsKey, &namespaceUniverse4DRecords, &errorMessage); + + REQUIRE(rc == SQLITE_OK); + REQUIRE(namespaceUniverse4DRecords.size() == 1); + + REQUIRE(namespaceUniverse4DRecords.at(0).at("name") == "Universe"); + REQUIRE(namespaceUniverse4DRecords.at(0).at("parent") != "-1"); + + std::string getUniverse4DParentNamespaceQuery{"SELECT * FROM namespaces WHERE id = " + namespaceUniverse4DRecords.at(0).at("parent") + ";"}; + + std::vector> namespaceUniverse4DParentRecords{}; + + rc = sqlite3_exec(database, getUniverse4DParentNamespaceQuery.c_str(), selectCallbackUsingColNameAsKey, &namespaceUniverse4DParentRecords, &errorMessage); + + REQUIRE(rc == SQLITE_OK); + REQUIRE(namespaceUniverse4DParentRecords.size() == 1); + + REQUIRE(namespaceUniverse4DParentRecords.at(0).at("name") == "_4D"); + REQUIRE(namespaceUniverse4DParentRecords.at(0).at("parent") != "-1"); + REQUIRE(namespaceUniverse4DParentRecords.at(0).at("fully_qualified_name") == "Plane::_4D"); + + std::string getUniverse4DGrandparentNamespaceQuery{"SELECT * FROM namespaces WHERE id = " + namespaceUniverse4DParentRecords.at(0).at("parent") + ";"}; + + std::vector> namespaceUniverse4DGrandparentRecords{}; + + rc = sqlite3_exec(database, getUniverse4DGrandparentNamespaceQuery.c_str(), selectCallbackUsingColNameAsKey, &namespaceUniverse4DGrandparentRecords, + &errorMessage); + + REQUIRE(rc == SQLITE_OK); + REQUIRE(namespaceUniverse4DGrandparentRecords.size() == 1); + + REQUIRE(namespaceUniverse4DGrandparentRecords.at(0).at("name") == "Plane"); + REQUIRE(namespaceUniverse4DGrandparentRecords.at(0).at("parent") == "-1"); + REQUIRE(namespaceUniverse4DGrandparentRecords.at(0).at("fully_qualified_name") == "Plane"); + + // REQUIRE(namespaceRecords.at(0).at("byte_size") == std::to_string(sizeof(S))); + + /** + *Check the fields of the S struct. + */ + + // std::string sId = namespaceRecords.at(0)["id"]; + + // std::string getSFields{"SELECT * FROM fields WHERE symbol = "}; + + // getSFields += sId; + // getSFields += ";"; + + // std::vector> fieldsRecords{}; + + // rc = sqlite3_exec(database, getSFields.c_str(), selectCallbackUsingColNameAsKey, &fieldsRecords, &errorMessage); + + // REQUIRE(rc == SQLITE_OK); + + // // TODO:Incosistent across Ubuntu20 and Ubuntu22. Different compilers will have different padding schemes. + // REQUIRE(fieldsRecords.size() >= 5); + + // // Enforce order of records by offset + // std::sort(fieldsRecords.begin(), fieldsRecords.end(), [](std::map a, std::map b) + // { return std::stoi(a["byte_offset"]) < std::stoi(b["byte_offset"]); }); + + // /** + // * Ensure that we have all of the expected keys in our map; these are the column names. + // * Don't love doing this kind of thing in tests... + // */ + // for (auto record : fieldsRecords) + // { + // REQUIRE(record.find("symbol") != record.end()); + // REQUIRE(record.find("name") != record.end()); + // REQUIRE(record.find("byte_offset") != record.end()); + // REQUIRE(record.find("type") != record.end()); + + // REQUIRE(record.find("little_endian") != record.end()); + // REQUIRE(record.find("bit_size") != record.end()); + // REQUIRE(record.find("bit_offset") != record.end()); + // REQUIRE(record.find("short_description") != record.end()); + // REQUIRE(record.find("long_description") != record.end()); + // } + + // REQUIRE(fieldsRecords.at(0)["name"] == "before"); + /** + *Check the correctness of the fields + */ + + // std::string getBeforeType{"SELECT * FROM symbols where id="}; + + // getBeforeType += fieldsRecords.at(0)["type"]; + // getBeforeType += ";"; + + // std::vector> beforeSymbolRecords{}; + + // rc = sqlite3_exec(database, getBeforeType.c_str(), selectCallbackUsingColNameAsKey, &beforeSymbolRecords, &errorMessage); + + // REQUIRE(rc == SQLITE_OK); + + // REQUIRE(beforeSymbolRecords.size() == 1); + + // std::string beforeType{beforeSymbolRecords.at(0).at("id")}; + + // REQUIRE(fieldsRecords.at(0)["symbol"] == symbolRecords.at(0)["id"]); + // REQUIRE(fieldsRecords.at(0)["name"] == "before"); + // REQUIRE(fieldsRecords.at(0)["byte_offset"] == std::to_string(offsetof(S, before))); + // REQUIRE(fieldsRecords.at(0)["type"] == beforeType); + // REQUIRE(fieldsRecords.at(0)["little_endian"] == little_endian); + // REQUIRE(fieldsRecords.at(0)["bit_size"] == "0"); + // REQUIRE(fieldsRecords.at(0)["bit_offset"] == "0"); + // REQUIRE(fieldsRecords.at(0)["short_description"] == ""); + // REQUIRE(fieldsRecords.at(0)["long_description"] == ""); + + // TODO:Inconsistent across Ubuntu20 and Ubuntu22. Different compilers will have different padding schemes. + + // REQUIRE(fieldsRecords.at(1)["name"] == "j"); + // /** + // *Check the correctness of the fields + // */ + + // std::string getFieldType{"SELECT * FROM symbols where id="}; + + // getFieldType += fieldsRecords.at(1)["type"]; + // getFieldType += ";"; + + // std::vector> fieldSymbolRecords{}; + + // rc = sqlite3_exec(database, getFieldType.c_str(), selectCallbackUsingColNameAsKey, &fieldSymbolRecords, &errorMessage); + + // REQUIRE(rc == SQLITE_OK); + + // REQUIRE(fieldSymbolRecords.size() == 1); + + // std::string fieldType{fieldSymbolRecords.at(0).at("id")}; + + // REQUIRE(fieldsRecords.at(1)["symbol"] == symbolRecords.at(0)["id"]); + // REQUIRE(fieldsRecords.at(1)["name"] == "j"); + // // REQUIRE(fieldsRecords.at(1)["byte_offset"] == std::to_string(offsetof(S, j))); + // REQUIRE(fieldsRecords.at(1)["type"] == fieldType); + // REQUIRE(fieldsRecords.at(1)["little_endian"] == little_endian); + // REQUIRE(fieldsRecords.at(1)["bit_size"] == "5"); + // REQUIRE(fieldsRecords.at(1)["bit_offset"] == "19"); + // REQUIRE(fieldsRecords.at(1)["short_description"] == ""); + // REQUIRE(fieldsRecords.at(1)["long_description"] == ""); + REQUIRE(remove("./test_db.sqlite") == 0); delete idc; } \ No newline at end of file diff --git a/unit-test/namespaces_test.cpp b/unit-test/namespaces_test.cpp index 125ec391..4aee78d9 100644 --- a/unit-test/namespaces_test.cpp +++ b/unit-test/namespaces_test.cpp @@ -1,3 +1,23 @@ +#include "stdint.h" +/** + *The fields padding1 and padding2(as the name implies) are to prevent + *gcc from inserting padding at compile-time and altering the expected results in our tests. + * Tested on Ubuntu 20.04 and Ubuntu 18.04. + */ +typedef struct +{ + int32_t width = 101; + uint16_t stuff; + uint16_t padding1; + int32_t length; + uint16_t more_stuff; + uint16_t padding2; + float floating_stuff; + float matrix3D[2][4][4]; + float matrix1D[2]; + uint8_t extra; +} Square; + namespace Universe { namespace Earth @@ -31,8 +51,27 @@ struct Shape }; } // namespace _3D +namespace _2D +{ +typedef struct +{ + int32_t width = 101; + uint16_t stuff; + uint16_t padding1; + int32_t length; + uint16_t more_stuff; + uint16_t padding2; + float floating_stuff; + float matrix3D[2][4][4]; + float matrix1D[2]; + uint8_t extra; +} Square; +} // namespace _2D + namespace _4D { + +Square s3[6]; namespace Universe { struct Shape @@ -45,8 +84,12 @@ struct Shape } // namespace Plane Universe::Earth::Shape earth{}; -// Universe::Mars::Shape mars{}; +Universe::Mars::Shape mars{}; -// Plane::_3D::Shape Space{}; +Plane::_3D::Shape Space{}; Plane::_4D::Universe::Shape Star{}; + +Square s{}; + +Plane::_2D::Square s2{}; \ No newline at end of file From c2a62cfba4c3e34ebafeb58c832e4c240add73a6 Mon Sep 17 00:00:00 2001 From: lgomez Date: Mon, 13 Jan 2025 18:39:10 -0600 Subject: [PATCH 18/20] -Get fqn from DIE up to root. Needs cleanup. --- src/ElfFile.cpp | 23 ++- src/ElfFile.h | 2 +- src/Juicer.cpp | 403 +++++++++++++++++++++++++++++++++++++++++++++-- src/SQLiteDB.cpp | 391 +++++++-------------------------------------- src/SQLiteDB.h | 8 +- 5 files changed, 470 insertions(+), 357 deletions(-) diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index b1415eb0..2285dcd9 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -70,15 +70,28 @@ std::string ElfFile::getMD5() const { return md5; } *nonetheless. Will re-evaluate. Visit https://en.cppreference.com/w/cpp/utility/optional *and https://en.cppreference.com/w/cpp/utility/tuple for details. */ -Symbol* ElfFile::getSymbol(std::string& name) +Symbol* ElfFile::getSymbol(std::string& name, Namespace* ns) { Symbol* returnSymbol = nullptr; for (auto&& symbol : symbols) { - if (symbol->getName() == name) + if (ns != nullptr && symbol->getNamespace() != nullptr) { - returnSymbol = symbol.get(); + if (symbol->getName() == name && symbol->getNamespace()->getFullyQualifiedName() == ns->getFullyQualifiedName()) + { + returnSymbol = symbol.get(); + } + } + + else if (ns == nullptr && symbol->getNamespace() == nullptr) + { + { + if (symbol->getName() == name) + { + returnSymbol = symbol.get(); + } + } } } @@ -87,7 +100,7 @@ Symbol* ElfFile::getSymbol(std::string& name) Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact, Symbol* targetSymbol, Namespace* symbolNamepace) { - Symbol* symbol = getSymbol(inName); + Symbol* symbol = getSymbol(inName, symbolNamepace); if (symbol == nullptr) { @@ -104,7 +117,7 @@ Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact ne Symbol* ElfFile::addSymbol(std::string& inName, uint32_t inByteSize, Artifact newArtifact, Namespace* symbolNamepace) { - Symbol* symbol = getSymbol(inName); + Symbol* symbol = getSymbol(inName, symbolNamepace); if (symbol == nullptr) { diff --git a/src/ElfFile.h b/src/ElfFile.h index dc8c259e..77260c5b 100644 --- a/src/ElfFile.h +++ b/src/ElfFile.h @@ -57,7 +57,7 @@ class ElfFile Symbol *addSymbol(std::string &inName, uint32_t inByteSize, Artifact newArtifact, Symbol *targetSymbol, Namespace *symbolNamepace); std::vector getFields(); std::vector getEnumerations(); - Symbol *getSymbol(std::string &name); + Symbol *getSymbol(std::string &name, Namespace *ns); const std::string &getDate() const; void setDate(const std::string &date); bool isLittleEndian() const; diff --git a/src/Juicer.cpp b/src/Juicer.cpp index a2e9e654..4a35f4f2 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -59,6 +59,346 @@ #include "Symbol.h" #include "Variable.h" +/* A simple container to hold the path of DIE offsets. */ +typedef struct +{ + Dwarf_Off *array; + size_t size; + size_t capacity; +} OffsetStack; + +/* Push an offset onto the stack */ +static void push_offset(OffsetStack *stack, Dwarf_Off off) +{ + if (stack->size >= stack->capacity) + { + /* Grow the array (very simplistic growth strategy) */ + size_t new_cap = (stack->capacity == 0) ? 16 : stack->capacity * 2; + Dwarf_Off *tmp = (Dwarf_Off *)realloc(stack->array, new_cap * sizeof(Dwarf_Off)); + if (!tmp) + { + fprintf(stderr, "Error: out of memory in push_offset()\n"); + exit(EXIT_FAILURE); + } + stack->array = tmp; + stack->capacity = new_cap; + } + stack->array[stack->size++] = off; +} + +/* Pop the last offset (only call after a successful push) */ +static void pop_offset(OffsetStack *stack) +{ + if (stack->size > 0) + { + stack->size--; + } +} + +/* + * Recursive DFS to locate a DIE with 'target_off' in the subtree + * rooted at 'current_die'. + * + * If found, returns 1 (the path is stored in 'path_stack'). + * If not found, returns 0. + */ +static int find_die_path(Dwarf_Debug dbg, Dwarf_Die current_die, Dwarf_Off target_off, OffsetStack *path_stack) +{ + Dwarf_Error err = 0; + Dwarf_Off cur_off; + + if (dwarf_dieoffset(current_die, &cur_off, &err) != DW_DLV_OK) + { + fprintf(stderr, "Error: dwarf_dieoffset() failed: %s\n", dwarf_errmsg(err)); + return 0; + } + + /* Push current DIE onto the path. */ + push_offset(path_stack, cur_off); + + /* Check if this is our target DIE. */ + if (cur_off == target_off) + { + return 1; /* Found it. The path stack now includes this DIE. */ + } + + /* Traverse the child (if any). */ + { + Dwarf_Die child_die = 0; + int rc = dwarf_child(current_die, &child_die, &err); + if (rc == DW_DLV_ERROR) + { + fprintf(stderr, "Error: dwarf_child() failed: %s\n", dwarf_errmsg(err)); + } + else if (rc == DW_DLV_OK) + { + if (find_die_path(dbg, child_die, target_off, path_stack)) + { + dwarf_dealloc(dbg, child_die, DW_DLA_DIE); + return 1; + } + dwarf_dealloc(dbg, child_die, DW_DLA_DIE); + } + } + + /* + * If not found in the child, traverse siblings. + * We need to keep calling dwarf_siblingof(...) to walk over each sibling. + */ + { + Dwarf_Die sibling_die = 0; + int sres = dwarf_siblingof(dbg, current_die, &sibling_die, &err); + + while (sres == DW_DLV_OK) + { + if (find_die_path(dbg, sibling_die, target_off, path_stack)) + { + dwarf_dealloc(dbg, sibling_die, DW_DLA_DIE); + return 1; + } + + /* Get the next sibling in a loop. */ + { + Dwarf_Die next_sibling = 0; + int nsres = dwarf_siblingof(dbg, sibling_die, &next_sibling, &err); + dwarf_dealloc(dbg, sibling_die, DW_DLA_DIE); + sibling_die = next_sibling; + sres = nsres; + } + } + if (sres == DW_DLV_ERROR) + { + fprintf(stderr, "Error: dwarf_siblingof() failed: %s\n", dwarf_errmsg(err)); + } + } + + /* Not found in this subtree. Pop from path and return 0. */ + pop_offset(path_stack); + return 0; +} + +/* + * Given a target DIE, retrieve all of its ancestor offsets (parents, grandparents). + * + * High-level flow: + * 1) Get offset of 'target_die'. + * 2) For each CU, do a DFS from the CU root to see if we can find that offset. + * 3) If found, the path stack contains [CU_root, ..., parent, target_die]. + * Extract all but the last as "parents". + */ +int get_parents_of_die(Dwarf_Debug dbg, Dwarf_Die target_die, Dwarf_Off **out_parent_list, size_t *out_parent_count) +{ + Dwarf_Error err = 0; + Dwarf_Off target_off = 0; + int found = 0; + + /* 1) Get the target DIE's offset. */ + if (dwarf_dieoffset(target_die, &target_off, &err) != DW_DLV_OK) + { + fprintf(stderr, "Error: dwarf_dieoffset() failed: %s\n", dwarf_errmsg(err)); + return 0; + } + + /* Prepare a stack to store the path (offsets). */ + OffsetStack path_stack; + memset(&path_stack, 0, sizeof(path_stack)); + + /* 2) Iterate over all compilation units to find the one containing the target DIE. */ + Dwarf_Die cu_die = 0; + int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &err); + while (cu_res == DW_DLV_OK) + { + /* + * Attempt to locate the target_off in this CU's hierarchy. + * We reset the path stack each time we check a new CU. + */ + path_stack.size = 0; + + if (find_die_path(dbg, cu_die, target_off, &path_stack)) + { + found = 1; + break; + } + + /* Move to next CU in a loop. */ + Dwarf_Die next_cu = 0; + int next_res = dwarf_siblingof(dbg, cu_die, &next_cu, &err); + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + cu_die = next_cu; + cu_res = next_res; + } + + if (found) + { + /* + * The path stack now contains [CU_root_offset, ..., parent_offset, target_off]. + * We want everything except the final element as the parent chain. + */ + if (path_stack.size > 0) + { + /* Exclude the last offset (the target DIE's offset). */ + size_t parent_count = path_stack.size - 1; + *out_parent_list = (Dwarf_Off *)malloc(parent_count * sizeof(Dwarf_Off)); + if (!*out_parent_list) + { + fprintf(stderr, "Error: out of memory in get_parents_of_die()\n"); + free(path_stack.array); + return 0; + } + memcpy(*out_parent_list, path_stack.array, parent_count * sizeof(Dwarf_Off)); + *out_parent_count = parent_count; + } + else + { + /* Should not happen if found == 1, but just in case. */ + *out_parent_list = NULL; + *out_parent_count = 0; + } + } + else + { + /* Could not locate target_off in any CU. */ + *out_parent_list = NULL; + *out_parent_count = 0; + } + + if (cu_res == DW_DLV_ERROR) + { + fprintf(stderr, "Error iterating compilation units: %s\n", dwarf_errmsg(err)); + } + if (cu_die) + { + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + } + + free(path_stack.array); + return found; +} + +std::string getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die) +{ + /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ + Dwarf_Off *parents = NULL; + size_t parent_count = 0; + std::string fqn{}; + + Dwarf_Error error = 0; + + Dwarf_Half tag = 0; + Dwarf_Off offset = 0; + + int success = get_parents_of_die(dbg, die, &parents, &parent_count); + if (success) + { + printf("Found the DIE's parent chain (length = %zu):\n", parent_count); + // The minus 1 is to exclude the DIE itself. + for (size_t i = 0; i < parent_count - 1; i++) + { + // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); + Dwarf_Die parent_die = 0; + + success = dwarf_offdie(dbg, parents[i], &parent_die, &error); + + if (success != DW_DLV_OK) + { + // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + success = JUICER_ERROR; + } + else + { + success = dwarf_tag(parent_die, &tag, &error); + printf("tag: %d\n", tag); + switch (tag) + { + // case DW_TAG_compile_unit: + // { + // success = dwarf_attrval_unsigned(parent_die, DW_AT_stmt_list, &offset, &error); + // if (success != DW_DLV_OK) + // { + // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // success = JUICER_ERROR; + // } + // else + // { + // fqn += "CU"; + // fqn += "::"; + // } + // break; + // } + case DW_TAG_namespace: + { + char *name = 0; + success = dwarf_diename(parent_die, &name, &error); + if (success != DW_DLV_OK) + { + // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + success = JUICER_ERROR; + } + else + { + std::cout << "Namespace: " << name << "And offset: " << parents[i] << std::endl; + std::string nsName{name}; + fqn += nsName; + fqn += "::"; + } + break; + } + // case DW_TAG_structure_type: + // { + // char *name = 0; + // success = dwarf_diename(parent_die, &name, &error); + // if (success != DW_DLV_OK) + // { + // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // success = JUICER_ERROR; + // } + // else + // { + // fqn += name; + // fqn += "::"; + // } + // break; + // } + // case DW_TAG_typedef: + // { + // char *name = 0; + // success = dwarf_diename(parent_die, &name, &error); + // if (success != DW_DLV_OK) + // { + // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // success = JUICER_ERROR; + // } + // else + // { + // fqn += name; + // fqn += "::"; + // } + // break; + // } + // case DW_TAG_enumeration_type: + // { + // char *name = 0; + // success = dwarf_diename(parent_die, &name, &error); + // if (success != DW_DLV_OK) + // { + // // logger + // } + // } + } + + } + // else + // { + // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); + // } + } + } + + return fqn; + + free(parents); +} + Juicer::Juicer() {} DefineMacro Juicer::getDefineMacroFromString(std::string macro_string) @@ -549,7 +889,7 @@ int Juicer::process_DW_TAG_array_type(ElfFile &elf, Symbol &symbol, Dwarf_Debug else { std::string arrayBaseType{arraySymbol->getName().c_str()}; - outSymbol = elf.getSymbol(arrayBaseType); + outSymbol = elf.getSymbol(arrayBaseType, currentNamespace); outSymbol->addField(stdString, 0, *outSymbol, dimList, elf.isLittleEndian()); } } @@ -1154,7 +1494,8 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & * cur_die and as we read different kinds of tags/attributes(in particular type-related), * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. * - * Notice that in https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 + * Notice that in + * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 * * This is just a theory, however. In the future we may revisit this * to figure out the root cause of this. @@ -1327,7 +1668,8 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & * cur_die and as we read different kinds of tags/attributes(in particular type-related), * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. * - * Notice that in https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 + * Notice that in + * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 * * This is just a theory, however. In the future we may revisit this * to figure out the root cause of this. @@ -1492,7 +1834,8 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & * cur_die and as we read different kinds of tags/attributes(in particular type-related), * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. * - * Notice that in https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 + * Notice that in + * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 * * This is just a theory, however. In the future we may revisit this * to figure out the root cause of this. @@ -3362,7 +3705,7 @@ Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Di } } - outSymbol = elf.getSymbol(cName); + outSymbol = elf.getSymbol(cName, currentNamespace); if (outSymbol == 0) { @@ -3373,7 +3716,7 @@ Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Di { /* See if we already have this symbol. */ cName = dieName; - outSymbol = elf.getSymbol(cName); + outSymbol = elf.getSymbol(cName, currentNamespace); if (outSymbol == 0) { /* No. This is new. Process it. */ @@ -3413,7 +3756,8 @@ Symbol *Juicer::process_DW_TAG_base_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Di * cur_die and as we read different kinds of tags/attributes(in particular type-related), * the libdwarf library is modifying the die when I call dwarf_srcfiles on it. * - * Notice that in https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 + * Notice that in + * https://penguin.windhoverlabs.lan/gitlab/ground-systems/libdwarf/-/blob/main/libdwarf/libdwarf/dwarf_die_deliv.c#L1365 * * This is just a theory, however. In the future we may revisit this * to figure out the root cause of this. @@ -3710,6 +4054,11 @@ Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die * */ + if (sDieName == "Square") + { + printf("Break here...\n"); + } + if (pathIndex != 0) { /** @@ -3978,6 +4327,33 @@ void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_D /* Get the base type die. */ if (res == DW_DLV_OK) { + /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ + Dwarf_Off *parents = NULL; + size_t parent_count = 0; + // int success = get_parents_of_die(dbg, memberDie, &parents, &parent_count); + std::string ns = getFullyQualifiedNameForDIE(dbg, memberDie); + + if (ns.length() > 4) + { + std::cout << "******************ns:" << ns << std::endl; + // printf("******************ns:%s\n", ns.c_str()); + } + + // if (success) + // { + // printf("Found the DIE's parent chain (length = %zu):\n", parent_count); + // for (size_t i = 0; i < parent_count; i++) + // { + // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); + // } + // } + // else + // { + // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); + // } + + // free(parents); + memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); if (memberBaseTypeSymbol == 0) @@ -4245,7 +4621,7 @@ void Juicer::addPaddingToStruct(Symbol &symbol) paddingType += std::to_string(paddingSize * 8); - Symbol *paddingSymbol = symbol.getElf().getSymbol(paddingType); + Symbol *paddingSymbol = symbol.getElf().getSymbol(paddingType, nullptr); if (paddingSymbol == nullptr) { @@ -4308,7 +4684,7 @@ void Juicer::addPaddingEndToStruct(Symbol &symbol) { paddingType += std::to_string(sizeDelta * 8); - Symbol *paddingSymbol = symbol.getElf().getSymbol(paddingType); + Symbol *paddingSymbol = symbol.getElf().getSymbol(paddingType, nullptr); if (paddingSymbol == nullptr) { @@ -4826,7 +5202,8 @@ std::map> Juicer::getObjDataFromElf(ElfFile *e } logger.logInfo( - "Found symbol %s with size: %d, st_value:%u, st_name:%u, st_info:%u, st_other:%u, st_shndx:%u\n", + "Found symbol %s with size: %d, st_value:%u, st_name:%u, st_info:%u, st_other:%u, " + "st_shndx:%u\n", name.c_str(), symbol->st_size, symbol->st_value, symbol->st_name, symbol->st_info, symbol->st_other, symbol->st_shndx); @@ -4839,8 +5216,10 @@ std::map> Juicer::getObjDataFromElf(ElfFile *e if (symbolSectionHeader != nullptr) { - // std::cout << "symbol data section file offset-->" - // << symbolSectionHeader->sh_offset << std::endl; + // std::cout << "symbol data section file + // offset-->" + // << symbolSectionHeader->sh_offset << + // std::endl; symbolSectionFileOffset = symbolSectionHeader->sh_offset; } diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index b663ac7b..647262a5 100644 --- a/src/SQLiteDB.cpp +++ b/src/SQLiteDB.cpp @@ -82,17 +82,27 @@ int SQLiteDB::doesRowExistCallback(void* count, int argc, char** argv, char** az *@note Please note that this function assumes that ALL symbols in our table *are universally unique across all Elf files. */ -bool SQLiteDB::doesSymbolExist(std::string name) +bool SQLiteDB::doesSymbolExist(std::string name, Namespace* ns) { - int32_t row_count = 0; + int32_t row_count = 0; - int rc = SQLITE_OK; + int rc = SQLITE_OK; - char* errorMessage = nullptr; + char* errorMessage = nullptr; + + int namespace_id = -1; + + if (ns != nullptr) + { + namespace_id = ns->getId().value(); + } std::string countRowsQuery{"SELECT COUNT(*) FROM symbols"}; countRowsQuery += " WHERE name=\""; - countRowsQuery += name + "\";"; + countRowsQuery += name + "\""; + countRowsQuery += " AND namespace="; + countRowsQuery += std::to_string(namespace_id); + countRowsQuery += ";"; rc = sqlite3_exec(database, countRowsQuery.c_str(), SQLiteDB::doesRowExistCallback, &row_count, &errorMessage); @@ -1169,7 +1179,12 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) for (auto&& symbol : inElf.getSymbols()) { - bool symbolExists = doesSymbolExist(symbol->getName()); + bool symbolExists = doesSymbolExist(symbol->getName(), symbol->getNamespace()); + + if (symbol->getName() == "Square") + { + printf("Break here...\n"); + } /** *First check if the symbol already exists in the database. @@ -1181,7 +1196,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) { std::map> symbolsMap{}; - std::string getSymbolIdQuery{"SELECT * FROM symbols where name="}; + std::string getSymbolIdQuery{"SELECT id FROM symbols where name="}; getSymbolIdQuery += "\""; getSymbolIdQuery += symbol->getName(); @@ -1244,7 +1259,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += "\""; - writeSymbolQuery += ")"; + writeSymbolQuery += ");"; rc = sqlite3_exec(database, writeSymbolQuery.c_str(), NULL, NULL, &errorMessage); @@ -1272,7 +1287,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) else { writeSymbolQuery += - "INSERT INTO symbols(elf, name, byte_size, encoding, artifact, long_description, short_description) " + "INSERT INTO symbols(elf, name, byte_size, encoding, artifact, namespace, long_description, short_description) " "VALUES("; writeSymbolQuery += std::to_string(symbol->getElf().getId()); writeSymbolQuery += ",\""; @@ -1288,6 +1303,17 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += std::to_string(symbol->getArtifact().getId()); + writeSymbolQuery += ","; + + if (symbol->getNamespace() != nullptr) + { + writeSymbolQuery += std::to_string(symbol->getNamespace()->getId().value()); + } + else + { + writeSymbolQuery += "-1"; + } + writeSymbolQuery += ",\""; writeSymbolQuery += symbol->getLongDescription(); @@ -1298,7 +1324,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += "\""; - writeSymbolQuery += ")"; + writeSymbolQuery += ");"; rc = sqlite3_exec(database, writeSymbolQuery.c_str(), NULL, NULL, &errorMessage); @@ -1933,6 +1959,26 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std if (namespaceExists) { logger.logDebug("Namespace %s already exists in the database.", namespace_->getFullyQualifiedName().c_str()); + + std::map> namespacesMap{}; + + std::string getNamespaceIdQuery{"SELECT id FROM namespaces where fully_qualified_name="}; + getNamespaceIdQuery += "\""; + getNamespaceIdQuery += namespace_->getFullyQualifiedName(); + + getNamespaceIdQuery += "\";"; + rc = sqlite3_exec(database, getNamespaceIdQuery.c_str(), SQLiteDB::selectCallback, &namespacesMap, &errorMessage); + + if (SQLITE_OK == rc) + { + /** + * We know there is only one element in our map, since symbol names are unique. + */ + for (auto pair : namespacesMap) + { + namespace_->setId(std::stoi(pair.first)); + } + } continue; } @@ -1951,68 +1997,6 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std // Bind values to placeholders sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); - // if (namespace_->getParent() != nullptr) - // { - // if (!namespace_->getParent()->getId().has_value()) - // { - // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; - - // sqlite3_stmt* stmt; - - // // Prepare the SQL statement - // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - // rc = sqlite3_bind_text(stmt, 1, namespace_->getParent()->getName().c_str(), -1, SQLITE_STATIC); - - // rc = sqlite3_step(stmt); - - // // Execute the SQL statement - // if (rc != SQLITE_DONE) - // { - // const char* errorMessage = sqlite3_errmsg(database); - // if (SQLITE_OK == rc) - // { - // logger.logDebug( - // "Elf values were written to the encodings schema with " - // "SQLITE_OK status."); - // } - // else - // { - // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - // { - // logger.logDebug("%s.", errorMessage); - // rc = SQLITE_OK; - // } - // else - // { - // logger.logDebug("There was an error while writing data to the encodings table."); - // logger.logDebug("%s.", errorMessage); - // rc = SQLITEDB_ERROR; - // } - // } - // } - - // // Finalize the statement - // rc = sqlite3_finalize(stmt); - // if (rc != SQLITE_OK) - // { - // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - // } - // else - // { - // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - // namespace_->getParent()->setId(lastRowId); - // } - // } - - // sqlite3_bind_int(stmt, 2, namespace_->getParent()->getId().value()); - // } - // else - // { - // sqlite3_bind_int(stmt, 2, -1); - // } - sqlite3_bind_int(stmt, 2, parentID.value_or(-1)); std::string fqn = namespace_->getFullyQualifiedName(); @@ -2063,71 +2047,6 @@ int SQLiteDB::writeNamespacesToDatabase(std::vector& namespaces, std if (namespace_->getChildren().size() > 0) { int lastRowID = writeNamespacesToDatabase(namespace_->getChildren(), namespace_->getId()); - for (auto& child : namespace_->getChildren()) - { - // Parent is the current namespace. So we need to write it to the database first. - // Then we can get the id of the parent (and store it in parentID) and write it to the child. - - // if (!child->getId().has_value()) - // { - // const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; - - // sqlite3_stmt* stmt; - - // // Prepare the SQL statement - // rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - // rc = sqlite3_bind_text(stmt, 1, child->getName().c_str(), -1, SQLITE_STATIC); - - // rc = sqlite3_step(stmt); - - // // Execute the SQL statement - // if (rc != SQLITE_DONE) - // { - // const char* errorMessage = sqlite3_errmsg(database); - // if (SQLITE_OK == rc) - // { - // logger.logDebug( - // "Elf values were written to the encodings schema with " - // "SQLITE_OK status."); - // } - // else - // { - // if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - // { - // logger.logDebug("%s.", errorMessage); - // rc = SQLITE_OK; - // } - // else - // { - // logger.logDebug("There was an error while writing data to the encodings table."); - // logger.logDebug("%s.", errorMessage); - // rc = SQLITEDB_ERROR; - // } - // } - // } - - // // Finalize the statement - // rc = sqlite3_finalize(stmt); - // if (rc != SQLITE_OK) - // { - // logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - // } - // else - // { - // sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - // child->setId(lastRowId); - // } - // } - - // sqlite3_bind_int(stmt, 3, child->getId().value()); - // sqlite3_bind_int(stmt, 3, lastRowID); - } - } - else - { - // sqlite3_bind_int(stmt, 3, -1); } } } @@ -2149,204 +2068,6 @@ int SQLiteDB::writeAllNamespacesToDatabase(ElfFile& inElf) writeNamespacesToDatabase(namespacesPointers, std::nullopt); - for (auto&& namespace_ : inElf.getNamespaces()) - { - // Check if namespace already exists in database - bool namespaceExists = doesNamespaceExistInDB(namespace_->getFullyQualifiedName()); - - if (namespaceExists) - { - logger.logDebug("Namespace %s already exists in the database.", namespace_->getFullyQualifiedName().c_str()); - continue; - } - - std::string writeNamespaceQuery{}; - - sqlite3_stmt* stmt; - const char* sql = "INSERT INTO namespaces (name,parent) VALUES (?,?);"; - - // Prepare the SQL statement - rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - if (rc != SQLITE_OK) - { - std::cerr << "SQL error: " << sqlite3_errmsg(database) << std::endl; - } - else - { - // Bind values to placeholders - sqlite3_bind_text(stmt, 1, namespace_->getName().c_str(), -1, SQLITE_STATIC); - - if (namespace_->getParent() != nullptr) - { - if (!namespace_->getParent()->getId().has_value()) - { - const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; - - sqlite3_stmt* stmt; - - // Prepare the SQL statement - rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - rc = sqlite3_bind_text(stmt, 1, namespace_->getParent()->getName().c_str(), -1, SQLITE_STATIC); - - rc = sqlite3_step(stmt); - - // Execute the SQL statement - if (rc != SQLITE_DONE) - { - const char* errorMessage = sqlite3_errmsg(database); - if (SQLITE_OK == rc) - { - logger.logDebug( - "Elf values were written to the encodings schema with " - "SQLITE_OK status."); - } - else - { - if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - { - logger.logDebug("%s.", errorMessage); - rc = SQLITE_OK; - } - else - { - logger.logDebug("There was an error while writing data to the encodings table."); - logger.logDebug("%s.", errorMessage); - rc = SQLITEDB_ERROR; - } - } - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) - { - logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - } - else - { - sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - namespace_->getParent()->setId(lastRowId); - } - } - - sqlite3_bind_int(stmt, 2, namespace_->getParent()->getId().value()); - } - else - { - sqlite3_bind_int(stmt, 2, -1); - } - - if (namespace_->getChildren().size() > 0) - { - for (auto&& child : namespace_->getChildren()) - { - if (!child->getId().has_value()) - { - const char* sql = "INSERT INTO namespaces (name) VALUES (?);"; - - sqlite3_stmt* stmt; - - // Prepare the SQL statement - rc = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL); - - rc = sqlite3_bind_text(stmt, 1, child->getName().c_str(), -1, SQLITE_STATIC); - - rc = sqlite3_step(stmt); - - // Execute the SQL statement - if (rc != SQLITE_DONE) - { - const char* errorMessage = sqlite3_errmsg(database); - if (SQLITE_OK == rc) - { - logger.logDebug( - "Elf values were written to the encodings schema with " - "SQLITE_OK status."); - } - else - { - if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - { - logger.logDebug("%s.", errorMessage); - rc = SQLITE_OK; - } - else - { - logger.logDebug("There was an error while writing data to the encodings table."); - logger.logDebug("%s.", errorMessage); - rc = SQLITEDB_ERROR; - } - } - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) - { - logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - } - else - { - sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - child->setId(lastRowId); - } - } - - sqlite3_bind_int(stmt, 3, child->getId().value()); - } - } - else - { - sqlite3_bind_int(stmt, 3, -1); - } - - rc = sqlite3_step(stmt); - - // Execute the SQL statement - if (rc != SQLITE_DONE) - { - const char* errorMessage = sqlite3_errmsg(database); - if (SQLITE_OK == rc) - { - logger.logDebug( - "Elf values were written to the encodings schema with " - "SQLITE_OK status."); - } - else - { - if (sqlite3_extended_errcode(database) == SQLITE_CONSTRAINT_UNIQUE) - { - logger.logDebug("%s.", errorMessage); - rc = SQLITE_OK; - } - else - { - logger.logDebug("There was an error while writing data to the encodings table."); - logger.logDebug("%s.", errorMessage); - rc = SQLITEDB_ERROR; - } - } - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) - { - logger.logDebug("There was an error while finalizing the sql statement for encodings table."); - } - else - { - sqlite3_int64 lastRowId = sqlite3_last_insert_rowid(database); - - namespace_->setId(lastRowId); - } - } - } - return rc; } diff --git a/src/SQLiteDB.h b/src/SQLiteDB.h index 1632abec..f0c5bef8 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -37,12 +37,12 @@ "CREATE TABLE IF NOT EXISTS symbols(\ id INTEGER PRIMARY KEY,\ elf INTEGER NOT NULL,\ - name TEXT UNIQUE NOT NULL,\ + name TEXT NOT NULL,\ byte_size INTEGER NOT NULL,\ artifact INTEGER,\ target_symbol INTEGER,\ encoding INTEGER,\ - namespace INTEGER,\ + namespace INTEGER NOT NULL,\ short_description TEXT ,\ long_description TEXT ,\ FOREIGN KEY(elf) REFERENCES elfs(id),\ @@ -50,7 +50,7 @@ FOREIGN KEY(target_symbol) REFERENCES symbols(id)\ FOREIGN KEY(encoding) REFERENCES encodings(id)\ FOREIGN KEY(namespace) REFERENCES namespaces(id)\ - UNIQUE(name));" + UNIQUE(name, namespace));" #define CREATE_DIMENSION_TABLE \ "CREATE TABLE IF NOT EXISTS dimension_lists (\ @@ -220,7 +220,7 @@ class SQLiteDB : public IDataContainer int writeNamespacesToDatabase(std::vector &namespaces, std::optional parentID); int writeAllNamespacesToDatabase(ElfFile &inElf); static int doesRowExistCallback(void *veryUsed, int argc, char **argv, char **azColName); - bool doesSymbolExist(std::string name); + bool doesSymbolExist(std::string name, Namespace *ns); bool doesArtifactExist(std::string name); bool doEncodingsExist(); From fec870235daa9610cf1e450659df6508fd69afb2 Mon Sep 17 00:00:00 2001 From: lgomez Date: Tue, 14 Jan 2025 17:59:33 -0600 Subject: [PATCH 19/20] -Add getPathForTargetDie. Useful for finding the tree path to structs, classes, etc. --- src/Juicer.cpp | 676 +++++++++++++++++++++++++------------------------ src/Juicer.h | 71 +++--- 2 files changed, 386 insertions(+), 361 deletions(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index 4a35f4f2..a5f3e56f 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -59,221 +59,6 @@ #include "Symbol.h" #include "Variable.h" -/* A simple container to hold the path of DIE offsets. */ -typedef struct -{ - Dwarf_Off *array; - size_t size; - size_t capacity; -} OffsetStack; - -/* Push an offset onto the stack */ -static void push_offset(OffsetStack *stack, Dwarf_Off off) -{ - if (stack->size >= stack->capacity) - { - /* Grow the array (very simplistic growth strategy) */ - size_t new_cap = (stack->capacity == 0) ? 16 : stack->capacity * 2; - Dwarf_Off *tmp = (Dwarf_Off *)realloc(stack->array, new_cap * sizeof(Dwarf_Off)); - if (!tmp) - { - fprintf(stderr, "Error: out of memory in push_offset()\n"); - exit(EXIT_FAILURE); - } - stack->array = tmp; - stack->capacity = new_cap; - } - stack->array[stack->size++] = off; -} - -/* Pop the last offset (only call after a successful push) */ -static void pop_offset(OffsetStack *stack) -{ - if (stack->size > 0) - { - stack->size--; - } -} - -/* - * Recursive DFS to locate a DIE with 'target_off' in the subtree - * rooted at 'current_die'. - * - * If found, returns 1 (the path is stored in 'path_stack'). - * If not found, returns 0. - */ -static int find_die_path(Dwarf_Debug dbg, Dwarf_Die current_die, Dwarf_Off target_off, OffsetStack *path_stack) -{ - Dwarf_Error err = 0; - Dwarf_Off cur_off; - - if (dwarf_dieoffset(current_die, &cur_off, &err) != DW_DLV_OK) - { - fprintf(stderr, "Error: dwarf_dieoffset() failed: %s\n", dwarf_errmsg(err)); - return 0; - } - - /* Push current DIE onto the path. */ - push_offset(path_stack, cur_off); - - /* Check if this is our target DIE. */ - if (cur_off == target_off) - { - return 1; /* Found it. The path stack now includes this DIE. */ - } - - /* Traverse the child (if any). */ - { - Dwarf_Die child_die = 0; - int rc = dwarf_child(current_die, &child_die, &err); - if (rc == DW_DLV_ERROR) - { - fprintf(stderr, "Error: dwarf_child() failed: %s\n", dwarf_errmsg(err)); - } - else if (rc == DW_DLV_OK) - { - if (find_die_path(dbg, child_die, target_off, path_stack)) - { - dwarf_dealloc(dbg, child_die, DW_DLA_DIE); - return 1; - } - dwarf_dealloc(dbg, child_die, DW_DLA_DIE); - } - } - - /* - * If not found in the child, traverse siblings. - * We need to keep calling dwarf_siblingof(...) to walk over each sibling. - */ - { - Dwarf_Die sibling_die = 0; - int sres = dwarf_siblingof(dbg, current_die, &sibling_die, &err); - - while (sres == DW_DLV_OK) - { - if (find_die_path(dbg, sibling_die, target_off, path_stack)) - { - dwarf_dealloc(dbg, sibling_die, DW_DLA_DIE); - return 1; - } - - /* Get the next sibling in a loop. */ - { - Dwarf_Die next_sibling = 0; - int nsres = dwarf_siblingof(dbg, sibling_die, &next_sibling, &err); - dwarf_dealloc(dbg, sibling_die, DW_DLA_DIE); - sibling_die = next_sibling; - sres = nsres; - } - } - if (sres == DW_DLV_ERROR) - { - fprintf(stderr, "Error: dwarf_siblingof() failed: %s\n", dwarf_errmsg(err)); - } - } - - /* Not found in this subtree. Pop from path and return 0. */ - pop_offset(path_stack); - return 0; -} - -/* - * Given a target DIE, retrieve all of its ancestor offsets (parents, grandparents). - * - * High-level flow: - * 1) Get offset of 'target_die'. - * 2) For each CU, do a DFS from the CU root to see if we can find that offset. - * 3) If found, the path stack contains [CU_root, ..., parent, target_die]. - * Extract all but the last as "parents". - */ -int get_parents_of_die(Dwarf_Debug dbg, Dwarf_Die target_die, Dwarf_Off **out_parent_list, size_t *out_parent_count) -{ - Dwarf_Error err = 0; - Dwarf_Off target_off = 0; - int found = 0; - - /* 1) Get the target DIE's offset. */ - if (dwarf_dieoffset(target_die, &target_off, &err) != DW_DLV_OK) - { - fprintf(stderr, "Error: dwarf_dieoffset() failed: %s\n", dwarf_errmsg(err)); - return 0; - } - - /* Prepare a stack to store the path (offsets). */ - OffsetStack path_stack; - memset(&path_stack, 0, sizeof(path_stack)); - - /* 2) Iterate over all compilation units to find the one containing the target DIE. */ - Dwarf_Die cu_die = 0; - int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &err); - while (cu_res == DW_DLV_OK) - { - /* - * Attempt to locate the target_off in this CU's hierarchy. - * We reset the path stack each time we check a new CU. - */ - path_stack.size = 0; - - if (find_die_path(dbg, cu_die, target_off, &path_stack)) - { - found = 1; - break; - } - - /* Move to next CU in a loop. */ - Dwarf_Die next_cu = 0; - int next_res = dwarf_siblingof(dbg, cu_die, &next_cu, &err); - dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); - cu_die = next_cu; - cu_res = next_res; - } - - if (found) - { - /* - * The path stack now contains [CU_root_offset, ..., parent_offset, target_off]. - * We want everything except the final element as the parent chain. - */ - if (path_stack.size > 0) - { - /* Exclude the last offset (the target DIE's offset). */ - size_t parent_count = path_stack.size - 1; - *out_parent_list = (Dwarf_Off *)malloc(parent_count * sizeof(Dwarf_Off)); - if (!*out_parent_list) - { - fprintf(stderr, "Error: out of memory in get_parents_of_die()\n"); - free(path_stack.array); - return 0; - } - memcpy(*out_parent_list, path_stack.array, parent_count * sizeof(Dwarf_Off)); - *out_parent_count = parent_count; - } - else - { - /* Should not happen if found == 1, but just in case. */ - *out_parent_list = NULL; - *out_parent_count = 0; - } - } - else - { - /* Could not locate target_off in any CU. */ - *out_parent_list = NULL; - *out_parent_count = 0; - } - - if (cu_res == DW_DLV_ERROR) - { - fprintf(stderr, "Error iterating compilation units: %s\n", dwarf_errmsg(err)); - } - if (cu_die) - { - dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); - } - - free(path_stack.array); - return found; -} std::string getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die) { @@ -286,117 +71,116 @@ std::string getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die) Dwarf_Half tag = 0; Dwarf_Off offset = 0; + // Replace with new code in getPathForTargetDie + // int success = get_parents_of_die(dbg, die, &parents, &parent_count); + // if (success) + // { + // printf("Found the DIE's parent chain (length = %zu):\n", parent_count); + // // The minus 1 is to exclude the DIE itself. + // for (size_t i = 0; i < parent_count; i++) + // { + // // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); + // Dwarf_Die parent_die = 0; - int success = get_parents_of_die(dbg, die, &parents, &parent_count); - if (success) - { - printf("Found the DIE's parent chain (length = %zu):\n", parent_count); - // The minus 1 is to exclude the DIE itself. - for (size_t i = 0; i < parent_count - 1; i++) - { - // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); - Dwarf_Die parent_die = 0; - - success = dwarf_offdie(dbg, parents[i], &parent_die, &error); + // success = dwarf_offdie(dbg, parents[i], &parent_die, &error); - if (success != DW_DLV_OK) - { - // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - success = JUICER_ERROR; - } - else - { - success = dwarf_tag(parent_die, &tag, &error); - printf("tag: %d\n", tag); - switch (tag) - { - // case DW_TAG_compile_unit: - // { - // success = dwarf_attrval_unsigned(parent_die, DW_AT_stmt_list, &offset, &error); - // if (success != DW_DLV_OK) - // { - // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // success = JUICER_ERROR; - // } - // else - // { - // fqn += "CU"; - // fqn += "::"; - // } - // break; - // } - case DW_TAG_namespace: - { - char *name = 0; - success = dwarf_diename(parent_die, &name, &error); - if (success != DW_DLV_OK) - { - // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - success = JUICER_ERROR; - } - else - { - std::cout << "Namespace: " << name << "And offset: " << parents[i] << std::endl; - std::string nsName{name}; - fqn += nsName; - fqn += "::"; - } - break; - } - // case DW_TAG_structure_type: - // { - // char *name = 0; - // success = dwarf_diename(parent_die, &name, &error); - // if (success != DW_DLV_OK) - // { - // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // success = JUICER_ERROR; - // } - // else - // { - // fqn += name; - // fqn += "::"; - // } - // break; - // } - // case DW_TAG_typedef: - // { - // char *name = 0; - // success = dwarf_diename(parent_die, &name, &error); - // if (success != DW_DLV_OK) - // { - // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // success = JUICER_ERROR; - // } - // else - // { - // fqn += name; - // fqn += "::"; - // } - // break; - // } - // case DW_TAG_enumeration_type: - // { - // char *name = 0; - // success = dwarf_diename(parent_die, &name, &error); - // if (success != DW_DLV_OK) - // { - // // logger - // } - // } - } - - } - // else - // { - // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); - // } - } - } + // if (success != DW_DLV_OK) + // { + // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // success = JUICER_ERROR; + // } + // else + // { + // success = dwarf_tag(parent_die, &tag, &error); + // printf("tag: %d\n", tag); + // switch (tag) + // { + // // case DW_TAG_compile_unit: + // // { + // // success = dwarf_attrval_unsigned(parent_die, DW_AT_stmt_list, &offset, &error); + // // if (success != DW_DLV_OK) + // // { + // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // // success = JUICER_ERROR; + // // } + // // else + // // { + // // fqn += "CU"; + // // fqn += "::"; + // // } + // // break; + // // } + // case DW_TAG_namespace: + // { + // char *name = 0; + // success = dwarf_diename(parent_die, &name, &error); + // if (success != DW_DLV_OK) + // { + // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // success = JUICER_ERROR; + // } + // else + // { + // std::cout << "Namespace: " << name << "And offset: " << parents[i] << std::endl; + // std::string nsName{name}; + // fqn += nsName; + // fqn += "::"; + // } + // break; + // } + // // case DW_TAG_structure_type: + // // { + // // char *name = 0; + // // success = dwarf_diename(parent_die, &name, &error); + // // if (success != DW_DLV_OK) + // // { + // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // // success = JUICER_ERROR; + // // } + // // else + // // { + // // fqn += name; + // // fqn += "::"; + // // } + // // break; + // // } + // // case DW_TAG_typedef: + // // { + // // char *name = 0; + // // success = dwarf_diename(parent_die, &name, &error); + // // if (success != DW_DLV_OK) + // // { + // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + // // success = JUICER_ERROR; + // // } + // // else + // // { + // // fqn += name; + // // fqn += "::"; + // // } + // // break; + // // } + // // case DW_TAG_enumeration_type: + // // { + // // char *name = 0; + // // success = dwarf_diename(parent_die, &name, &error); + // // if (success != DW_DLV_OK) + // // { + // // // logger + // // } + // // } + // } + // } + // // else + // // { + // // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); + // // } + // } + // } - return fqn; + // return fqn; - free(parents); + // free(parents); } Juicer::Juicer() {} @@ -1467,6 +1251,88 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & if (dieName != nullptr) { cName = dieName; + + if (cName == "MShape") + { + // std::string ns = getFullyQualifiedNameForDIE(dbg, typeDie); + Dwarf_Die cu_die; + Dwarf_Die sib_die; + int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &error); + + Dwarf_Off targetOffset = 0; + + std::vector dieList{}; + + // std::vector dieList{}; + + for (;;) + { + Dwarf_Die foundDIE = getPathForTargetDie(typeDie, dbg, cu_die, 0, dieList); + + if (foundDIE != 0) + { + break; + } + + /* res == DW_DLV_NO_ENTRY */ + res = dwarf_siblingof(dbg, cu_die, &sib_die, &error); + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_siblingof , level UNKNOWN. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + res = JUICER_ERROR; + } + + if (res == DW_DLV_NO_ENTRY) + { + /* Done at this level. */ + break; + } + + /* res == DW_DLV_OK */ + // if (cu_die != in_die) + // { + // dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + // } + + cu_die = sib_die; + } + + // TODO:Write code to convert the vector of Dwarf_Die's to something like "Universe::MilkyWay::Mars::MShape". Keep in mind DW_TAG_compile_unit is included in the vector. + for (Dwarf_Die d : dieList) + { + Dwarf_Attribute attr_struct; + Dwarf_Error error = 0; + char *name = nullptr; + int res = 0; + // std::unique_ptr ns = std::make_unique(); + std::string namespaceName{}; + + // Need to figure out if this die has already been processed. + + res = dwarf_attr(d, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + // dieList.push_back(name); + } + + namespaceName = name; + + std::cout << "namespaceName#1:" << namespaceName << std::endl; + } + + std::cout << "breakpoint" << std::endl; + } } else { @@ -4327,16 +4193,21 @@ void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_D /* Get the base type die. */ if (res == DW_DLV_OK) { + std::string sMemberName = memberName; /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ Dwarf_Off *parents = NULL; size_t parent_count = 0; // int success = get_parents_of_die(dbg, memberDie, &parents, &parent_count); - std::string ns = getFullyQualifiedNameForDIE(dbg, memberDie); - if (ns.length() > 4) + if (sMemberName == "NestedMars") { - std::cout << "******************ns:" << ns << std::endl; - // printf("******************ns:%s\n", ns.c_str()); + // std::string ns = getFullyQualifiedNameForDIE(dbg, memberDie); + + // if (ns.length() > 4) + // { + // std::cout << "******************ns:" << ns << std::endl; + // // printf("******************ns:%s\n", ns.c_str()); + // } } // if (success) @@ -4767,6 +4638,159 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) return isSupported; } +/** + * @brief Searches for the target die and stores the "path" to it in the dieList. It starts from the in_die and goes through all its children and siblings. + * For example a namespaced die such as Universe::MilkyWay::Mars::MShape will be stored as a vector of Dwarf_Die objects in DieList, including the DW_TAG_compile_unit root node. + * So for our example: + * + * This is only needed because, unfortunately, libdwarf does not provide a way to get the parent of a die. + * This is very useful for finding the namespace of a die (struct, class,). + * + * */ + +Dwarf_Die Juicer::getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, std::vector &dieList) +{ + int res = DW_DLV_ERROR; + Dwarf_Die cur_die = in_die; + Dwarf_Die child = 0; + Dwarf_Die returnedDie = 0; + Dwarf_Error error = 0; + char *dieName; + Dwarf_Attribute attr_struct; + int return_value = JUICER_OK; + + Symbol *outSymbol = nullptr; + + Namespace *newParentNamespace = nullptr; + + Dwarf_Die sib_die = 0; + Dwarf_Half tag = 0; + Dwarf_Off offset = 0; + Dwarf_Off targetOffset = 0; + + res = dwarf_dieoffset(cur_die, &offset, &error); + + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_dieoffset , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + } + + res = dwarf_dieoffset(targetDie, &targetOffset, &error); + + if (targetOffset == offset) + { + // return whether the target die is found or not + dieList.push_back(cur_die); + + std::string namespaceName{}; + char *name = NULL; + + // Need to figure out if this die has already been processed. + + res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + // dieList.push_back(name); + } + + namespaceName = name; + + std::cout << "namespaceName#2:" << namespaceName << std::endl; + + return cur_die; + } + + std::string namespaceName{}; + char *name = NULL; + + // Need to figure out if this die has already been processed. + + res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + + // dieList.push_back(name); + namespaceName = name; + + if ("Universe" == namespaceName) + { + printf("Break here...\n"); + } + } + + // iterate through all children at this level + + res = dwarf_child(cur_die, &child, &error); + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_child , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + } + else if (res == DW_DLV_OK) + { + returnedDie = getPathForTargetDie(targetDie, dbg, child, in_level + 1, dieList); + if (returnedDie != 0) + { + std::cout << "namespaceName#3:" << namespaceName << std::endl; + + dieList.push_back(cur_die); + } + else + { + for (;;) + { + /* res == DW_DLV_NO_ENTRY */ + res = dwarf_siblingof(dbg, child, &sib_die, &error); + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_siblingof , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); + return_value = JUICER_ERROR; + break; + } + + if (res == DW_DLV_NO_ENTRY) + { + /* Done at this level. */ + break; + } + + child = sib_die; + + returnedDie = getPathForTargetDie(targetDie, dbg, child, in_level + 1, dieList); + if (returnedDie != 0) + { + dieList.push_back(cur_die); + break; + } + } + } + } + + return returnedDie; +} + /** * @brief Inspects the data on the die and its own children recursively. * @param in_die the die entry that has the dwarf data. diff --git a/src/Juicer.h b/src/Juicer.h index 005648eb..2fb0f507 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -107,41 +107,42 @@ class Juicer unsigned int getDwarfVersion(); private: - Dwarf_Debug dbg = 0; - int res = DW_DLV_ERROR; - Dwarf_Handler errhand; - Dwarf_Ptr errarg = 0; - int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); - int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); - Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); - Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); - void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); - char* getFirstAncestorName(Dwarf_Die inDie); - int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); - char* dwarfStringToChar(char* dwarfString); - void addBitFields(Dwarf_Die dataMemberDie, Field& dataMemberField); - void addPaddingToStruct(Symbol& symbol); - void addPaddingEndToStruct(Symbol& symbol); - bool isDWARFVersionSupported(Dwarf_Die); - int elfFile = 0; - Logger logger; - IDataContainer* idc = 0; - bool isIDCSet(void); - Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& dimList, Namespace* currentNamespace); - void DisplayDie(Dwarf_Die inDie, uint32_t level); - - std::vector getChildrenVector(Dwarf_Debug dbg, Dwarf_Die die); - int getNumberOfSiblingsForDie(Dwarf_Debug dbg, Dwarf_Die die); - - uint32_t calcArraySizeForDimension(Dwarf_Debug dbg, Dwarf_Die die); - - DimensionList getDimList(Dwarf_Debug dbg, Dwarf_Die die); + Dwarf_Debug dbg = 0; + int res = DW_DLV_ERROR; + Dwarf_Handler errhand; + Dwarf_Ptr errarg = 0; + int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); + int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); + Dwarf_Die getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, std::vector& dieList); + Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); + int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); + char* getFirstAncestorName(Dwarf_Die inDie); + int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); + char* dwarfStringToChar(char* dwarfString); + void addBitFields(Dwarf_Die dataMemberDie, Field& dataMemberField); + void addPaddingToStruct(Symbol& symbol); + void addPaddingEndToStruct(Symbol& symbol); + bool isDWARFVersionSupported(Dwarf_Die); + int elfFile = 0; + Logger logger; + IDataContainer* idc = 0; + bool isIDCSet(void); + Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& dimList, Namespace* currentNamespace); + void DisplayDie(Dwarf_Die inDie, uint32_t level); + + std::vector getChildrenVector(Dwarf_Debug dbg, Dwarf_Die die); + int getNumberOfSiblingsForDie(Dwarf_Debug dbg, Dwarf_Die die); + + uint32_t calcArraySizeForDimension(Dwarf_Debug dbg, Dwarf_Die die); + + DimensionList getDimList(Dwarf_Debug dbg, Dwarf_Die die); std::vector dbgSourceFiles{}; From bb35ffaa261376e167a8e451b1a50495d20fa889 Mon Sep 17 00:00:00 2001 From: lgomez Date: Wed, 15 Jan 2025 15:51:53 -0600 Subject: [PATCH 20/20] -Minimally functional implementation of namespaces. Needs to be documented. --- src/Juicer.cpp | 422 ++++++++++++++++++------------------------------- src/Juicer.h | 73 ++++----- 2 files changed, 194 insertions(+), 301 deletions(-) diff --git a/src/Juicer.cpp b/src/Juicer.cpp index a5f3e56f..f65e2286 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -59,128 +59,118 @@ #include "Symbol.h" #include "Variable.h" - -std::string getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die) +/** + * Useful for determining in which namespace a given DIE is located. + * @param die The DIE for which we want to determine the namespace. + * @param dbg The dwarf debug entry. + * @return The fully qualified name of the DIE. e.g. DIE for a struct whose fully qualified name is Universe::MilkyWay::Mars::MShape + * (assuming the struct is named MShape and Universe::MilkyWay::Mars are namespaces) + */ +std::optional Juicer::getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die) { - /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ - Dwarf_Off *parents = NULL; - size_t parent_count = 0; - std::string fqn{}; - - Dwarf_Error error = 0; - - Dwarf_Half tag = 0; - Dwarf_Off offset = 0; - // Replace with new code in getPathForTargetDie - // int success = get_parents_of_die(dbg, die, &parents, &parent_count); - // if (success) - // { - // printf("Found the DIE's parent chain (length = %zu):\n", parent_count); - // // The minus 1 is to exclude the DIE itself. - // for (size_t i = 0; i < parent_count; i++) - // { - // // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); - // Dwarf_Die parent_die = 0; + Dwarf_Error error = 0; + Dwarf_Die cu_die; + Dwarf_Die sib_die; + int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &error); - // success = dwarf_offdie(dbg, parents[i], &parent_die, &error); + Dwarf_Off targetOffset = 0; - // if (success != DW_DLV_OK) - // { - // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // success = JUICER_ERROR; - // } - // else - // { - // success = dwarf_tag(parent_die, &tag, &error); - // printf("tag: %d\n", tag); - // switch (tag) - // { - // // case DW_TAG_compile_unit: - // // { - // // success = dwarf_attrval_unsigned(parent_die, DW_AT_stmt_list, &offset, &error); - // // if (success != DW_DLV_OK) - // // { - // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // // success = JUICER_ERROR; - // // } - // // else - // // { - // // fqn += "CU"; - // // fqn += "::"; - // // } - // // break; - // // } - // case DW_TAG_namespace: - // { - // char *name = 0; - // success = dwarf_diename(parent_die, &name, &error); - // if (success != DW_DLV_OK) - // { - // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // success = JUICER_ERROR; - // } - // else - // { - // std::cout << "Namespace: " << name << "And offset: " << parents[i] << std::endl; - // std::string nsName{name}; - // fqn += nsName; - // fqn += "::"; - // } - // break; - // } - // // case DW_TAG_structure_type: - // // { - // // char *name = 0; - // // success = dwarf_diename(parent_die, &name, &error); - // // if (success != DW_DLV_OK) - // // { - // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // // success = JUICER_ERROR; - // // } - // // else - // // { - // // fqn += name; - // // fqn += "::"; - // // } - // // break; - // // } - // // case DW_TAG_typedef: - // // { - // // char *name = 0; - // // success = dwarf_diename(parent_die, &name, &error); - // // if (success != DW_DLV_OK) - // // { - // // // logger.logError("Error in dwarf_tag , level %d. errno=%u %s", in_level, dwarf_errno(error), dwarf_errmsg(error)); - // // success = JUICER_ERROR; - // // } - // // else - // // { - // // fqn += name; - // // fqn += "::"; - // // } - // // break; - // // } - // // case DW_TAG_enumeration_type: - // // { - // // char *name = 0; - // // success = dwarf_diename(parent_die, &name, &error); - // // if (success != DW_DLV_OK) - // // { - // // // logger - // // } - // // } - // } - // } - // // else - // // { - // // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); - // // } - // } - // } + Dwarf_Die foundDIE = 0; + + std::vector dieList{}; + + std::optional fullyQualifiedName{std::nullopt}; + + for (;;) + { + foundDIE = getPathForTargetDie(die, dbg, cu_die, 0, dieList); + + if (foundDIE != 0) + { + break; + } + + /* res == DW_DLV_NO_ENTRY */ + res = dwarf_siblingof(dbg, cu_die, &sib_die, &error); + if (res == DW_DLV_ERROR) + { + logger.logError("Error in dwarf_siblingof , level UNKNOWN. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + res = JUICER_ERROR; + } + + if (res == DW_DLV_NO_ENTRY) + { + /* Done at this level. */ + break; + } + + /* res == DW_DLV_OK */ + // if (cu_die != in_die) + // { + // dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + // } + + cu_die = sib_die; + } + + if (foundDIE) + { + std::string fqn{}; + + std::vector namespaces{}; + + for (Dwarf_Die d : dieList) + { + Dwarf_Attribute attr_struct; + Dwarf_Error error = 0; + char *name = nullptr; + int res = 0; + std::string namespaceName{}; + Dwarf_Half tag = 0; - // return fqn; + int success = dwarf_tag(d, &tag, &error); - // free(parents); + switch (tag) + { + case DW_TAG_namespace: + { + res = dwarf_attr(d, DW_AT_name, &attr_struct, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + } + + if (res == DW_DLV_OK) + { + res = dwarf_formstring(attr_struct, &name, &error); + if (res != DW_DLV_OK) + { + logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + } + } + + namespaceName = name; + namespaces.push_back(namespaceName); + break; + } + } + } + + std::reverse(std::begin(namespaces), std::end(namespaces)); + + for (std::string ns : namespaces) + { + fqn += ns + "::"; + } + if (!fqn.empty()) + { + fqn.pop_back(); + fqn.pop_back(); + fullyQualifiedName = fqn; + } + } + + return fullyQualifiedName; } Juicer::Juicer() {} @@ -1247,92 +1237,13 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & if (res == DW_DLV_OK) { - std::string cName{""}; + std::optional fqn; + std::string cName{""}; if (dieName != nullptr) { cName = dieName; - if (cName == "MShape") - { - // std::string ns = getFullyQualifiedNameForDIE(dbg, typeDie); - Dwarf_Die cu_die; - Dwarf_Die sib_die; - int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &error); - - Dwarf_Off targetOffset = 0; - - std::vector dieList{}; - - // std::vector dieList{}; - - for (;;) - { - Dwarf_Die foundDIE = getPathForTargetDie(typeDie, dbg, cu_die, 0, dieList); - - if (foundDIE != 0) - { - break; - } - - /* res == DW_DLV_NO_ENTRY */ - res = dwarf_siblingof(dbg, cu_die, &sib_die, &error); - if (res == DW_DLV_ERROR) - { - logger.logError("Error in dwarf_siblingof , level UNKNOWN. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - res = JUICER_ERROR; - } - - if (res == DW_DLV_NO_ENTRY) - { - /* Done at this level. */ - break; - } - - /* res == DW_DLV_OK */ - // if (cu_die != in_die) - // { - // dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); - // } - - cu_die = sib_die; - } - - // TODO:Write code to convert the vector of Dwarf_Die's to something like "Universe::MilkyWay::Mars::MShape". Keep in mind DW_TAG_compile_unit is included in the vector. - for (Dwarf_Die d : dieList) - { - Dwarf_Attribute attr_struct; - Dwarf_Error error = 0; - char *name = nullptr; - int res = 0; - // std::unique_ptr ns = std::make_unique(); - std::string namespaceName{}; - - // Need to figure out if this die has already been processed. - - res = dwarf_attr(d, DW_AT_name, &attr_struct, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); - } - - if (res == DW_DLV_OK) - { - res = dwarf_formstring(attr_struct, &name, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - } - - // dieList.push_back(name); - } - - namespaceName = name; - - std::cout << "namespaceName#1:" << namespaceName << std::endl; - } - - std::cout << "breakpoint" << std::endl; - } + fqn = getFullyQualifiedNameForDIE(dbg, typeDie); } else { @@ -1382,14 +1293,35 @@ Symbol *Juicer::getBaseTypeSymbol(ElfFile &elf, Dwarf_Die inDie, DimensionList & Artifact newArtifact{elf, getdbgSourceFile(elf, pathIndex).value_or(std::string{"NOT_FOUND:"})}; std::string checkSum = generateMD5SumForFile(newArtifact.getFilePath()); newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); + if (cName == "MShape") + { + std::cout << "break here"; + } + if (fqn.has_value()) + { + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, elf.getNamespace(fqn.value())); + } + else + { + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); + } + // outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } else { Artifact newArtifact{elf, "NOT_FOUND:" + cName}; std::string checkSum{}; newArtifact.setMD5(checkSum); - outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); + if (fqn.has_value()) + { + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, elf.getNamespace(fqn.value())); + } + else + { + outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); + } + + // outSymbol = elf.addSymbol(cName, byteSize, newArtifact, currentNamespace); } } @@ -3920,11 +3852,6 @@ Symbol *Juicer::process_DW_TAG_typedef(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die * */ - if (sDieName == "Square") - { - printf("Break here...\n"); - } - if (pathIndex != 0) { /** @@ -4193,39 +4120,10 @@ void Juicer::process_DW_TAG_structure_type(ElfFile &elf, Symbol &symbol, Dwarf_D /* Get the base type die. */ if (res == DW_DLV_OK) { - std::string sMemberName = memberName; + std::string sMemberName = memberName; /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ - Dwarf_Off *parents = NULL; - size_t parent_count = 0; - // int success = get_parents_of_die(dbg, memberDie, &parents, &parent_count); - - if (sMemberName == "NestedMars") - { - // std::string ns = getFullyQualifiedNameForDIE(dbg, memberDie); - - // if (ns.length() > 4) - // { - // std::cout << "******************ns:" << ns << std::endl; - // // printf("******************ns:%s\n", ns.c_str()); - // } - } - - // if (success) - // { - // printf("Found the DIE's parent chain (length = %zu):\n", parent_count); - // for (size_t i = 0; i < parent_count; i++) - // { - // printf(" Parent offset: 0x%lx\n", (unsigned long)parents[i]); - // } - // } - // else - // { - // printf("Could not find the DIE's parents (or DIE not found in any CU).\n"); - // } - - // free(parents); - - memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); + Dwarf_Off *parents = NULL; + memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); if (memberBaseTypeSymbol == 0) { @@ -4640,8 +4538,8 @@ bool Juicer::isDWARFVersionSupported(Dwarf_Die inDie) /** * @brief Searches for the target die and stores the "path" to it in the dieList. It starts from the in_die and goes through all its children and siblings. - * For example a namespaced die such as Universe::MilkyWay::Mars::MShape will be stored as a vector of Dwarf_Die objects in DieList, including the DW_TAG_compile_unit root node. - * So for our example: + * For example a namespaced die such as Universe::MilkyWay::Mars::MShape will be stored as a vector of Dwarf_Die objects in DieList, including the + * DW_TAG_compile_unit root node. So for our example: * * This is only needed because, unfortunately, libdwarf does not provide a way to get the parent of a die. * This is very useful for finding the namespace of a die (struct, class,). @@ -4683,31 +4581,31 @@ Dwarf_Die Juicer::getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwar // return whether the target die is found or not dieList.push_back(cur_die); - std::string namespaceName{}; - char *name = NULL; + // std::string namespaceName{}; + // char *name = NULL; - // Need to figure out if this die has already been processed. + // // Need to figure out if this die has already been processed. - res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); - } + // res = dwarf_attr(cur_die, DW_AT_name, &attr_struct, &error); + // if (res != DW_DLV_OK) + // { + // logger.logError("Error in dwarf_attr(DW_AT_name). %u errno=%u %s", __LINE__, dwarf_errno(error), dwarf_errmsg(error)); + // } - if (res == DW_DLV_OK) - { - res = dwarf_formstring(attr_struct, &name, &error); - if (res != DW_DLV_OK) - { - logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); - } + // if (res == DW_DLV_OK) + // { + // res = dwarf_formstring(attr_struct, &name, &error); + // if (res != DW_DLV_OK) + // { + // logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); + // } - // dieList.push_back(name); - } + // // dieList.push_back(name); + // } - namespaceName = name; + // namespaceName = name; - std::cout << "namespaceName#2:" << namespaceName << std::endl; + // std::cout << "namespaceName#2:" << namespaceName << std::endl; return cur_die; } @@ -4731,13 +4629,7 @@ Dwarf_Die Juicer::getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwar logger.logError("Error in dwarf_formstring. errno=%u %s", dwarf_errno(error), dwarf_errmsg(error)); } - // dieList.push_back(name); namespaceName = name; - - if ("Universe" == namespaceName) - { - printf("Break here...\n"); - } } // iterate through all children at this level diff --git a/src/Juicer.h b/src/Juicer.h index 2fb0f507..5064cee1 100644 --- a/src/Juicer.h +++ b/src/Juicer.h @@ -107,42 +107,43 @@ class Juicer unsigned int getDwarfVersion(); private: - Dwarf_Debug dbg = 0; - int res = DW_DLV_ERROR; - Dwarf_Handler errhand; - Dwarf_Ptr errarg = 0; - int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); - int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); - Dwarf_Die getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, std::vector& dieList); - Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); - Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); - void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); - int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); - Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); - char* getFirstAncestorName(Dwarf_Die inDie); - int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); - char* dwarfStringToChar(char* dwarfString); - void addBitFields(Dwarf_Die dataMemberDie, Field& dataMemberField); - void addPaddingToStruct(Symbol& symbol); - void addPaddingEndToStruct(Symbol& symbol); - bool isDWARFVersionSupported(Dwarf_Die); - int elfFile = 0; - Logger logger; - IDataContainer* idc = 0; - bool isIDCSet(void); - Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& dimList, Namespace* currentNamespace); - void DisplayDie(Dwarf_Die inDie, uint32_t level); - - std::vector getChildrenVector(Dwarf_Debug dbg, Dwarf_Die die); - int getNumberOfSiblingsForDie(Dwarf_Debug dbg, Dwarf_Die die); - - uint32_t calcArraySizeForDimension(Dwarf_Debug dbg, Dwarf_Die die); - - DimensionList getDimList(Dwarf_Debug dbg, Dwarf_Die die); + Dwarf_Debug dbg = 0; + int res = DW_DLV_ERROR; + Dwarf_Handler errhand; + Dwarf_Ptr errarg = 0; + int readCUList(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Error& error); + int getDieAndSiblings(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, Namespace* currentNamespace); + Dwarf_Die getPathForTargetDie(Dwarf_Die targetDie, Dwarf_Debug dbg, Dwarf_Die in_die, int in_level, std::vector& dieList); + std::optional getFullyQualifiedNameForDIE(Dwarf_Debug dbg, Dwarf_Die die); + Symbol* process_DW_TAG_typedef(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + Symbol* process_DW_TAG_base_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die in_die, Namespace* currentNamespace); + void process_DW_TAG_structure_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_pointer_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Symbol* process_DW_TAG_variable_type(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + void process_DW_TAG_enumeration_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie); + int process_DW_TAG_array_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + void process_DW_TAG_union_type(ElfFile& elf, Symbol& symbol, Dwarf_Debug dbg, Dwarf_Die inDie, Namespace* currentNamespace); + Namespace* process_DW_TAG_namespace(ElfFile& elf, Dwarf_Debug dbg, Dwarf_Die inDie, int in_level, Namespace* currentNamespace); + char* getFirstAncestorName(Dwarf_Die inDie); + int printDieData(Dwarf_Debug dbg, Dwarf_Die print_me, uint32_t level); + char* dwarfStringToChar(char* dwarfString); + void addBitFields(Dwarf_Die dataMemberDie, Field& dataMemberField); + void addPaddingToStruct(Symbol& symbol); + void addPaddingEndToStruct(Symbol& symbol); + bool isDWARFVersionSupported(Dwarf_Die); + int elfFile = 0; + Logger logger; + IDataContainer* idc = 0; + bool isIDCSet(void); + Symbol* getBaseTypeSymbol(ElfFile& elf, Dwarf_Die inDie, DimensionList& dimList, Namespace* currentNamespace); + void DisplayDie(Dwarf_Die inDie, uint32_t level); + + std::vector getChildrenVector(Dwarf_Debug dbg, Dwarf_Die die); + int getNumberOfSiblingsForDie(Dwarf_Debug dbg, Dwarf_Die die); + + uint32_t calcArraySizeForDimension(Dwarf_Debug dbg, Dwarf_Die die); + + DimensionList getDimList(Dwarf_Debug dbg, Dwarf_Die die); std::vector dbgSourceFiles{};