diff --git a/src/ElfFile.cpp b/src/ElfFile.cpp index c78c42cd..2285dcd9 100644 --- a/src/ElfFile.cpp +++ b/src/ElfFile.cpp @@ -70,24 +70,37 @@ 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(); + } + } } } 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); + Symbol* symbol = getSymbol(inName, symbolNamepace); if (symbol == nullptr) { @@ -102,13 +115,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); + Symbol* symbol = getSymbol(inName, symbolNamepace); if (symbol == nullptr) { std::unique_ptr newSymbol = std::make_unique(*this, inName, inByteSize, newArtifact); + newSymbol->setNamespace(symbolNamepace); symbols.push_back(std::move(newSymbol)); @@ -238,4 +252,47 @@ void ElfFile::setElfClass(int newelfClass) } } -int ElfFile::getElfClass() { return elfClass; } +int ElfFile::getElfClass() { return elfClass; } + +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) +{ + for (auto&& namespace_ : namespaces) + { + if (namespace_->getFullyQualifiedName() == name) + { + return namespace_.get(); + } + } + + return nullptr; +} + +std::vector>& ElfFile::getNamespaces() { return namespaces; } diff --git a/src/ElfFile.h b/src/ElfFile.h index c6e236ac..77260c5b 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. @@ -46,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, Namespace *ns); + 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; @@ -91,6 +93,11 @@ class ElfFile void setElfClass(int newelfClass); + void addNamespace(Namespace newNamespace); + void addNamespace(std::unique_ptr newNamespace); + std::vector> &getNamespaces(); + Namespace *getNamespace(std::string name); + private: std::string md5; /** @@ -155,7 +162,7 @@ class ElfFile }; - Encoding &getDWARFEncoding(); + Encoding &getDWARFEncoding(); /** * @brief elfClass @@ -164,7 +171,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..f65e2286 100644 --- a/src/Juicer.cpp +++ b/src/Juicer.cpp @@ -55,19 +55,123 @@ #include "Enumeration.h" #include "Field.h" #include "IDataContainer.h" +#include "Namespace.hpp" #include "Symbol.h" #include "Variable.h" -struct macro_counts_s +/** + * 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) { - long mc_start_file; - long mc_end_file; - long mc_define; - long mc_undef; - long mc_extension; - long mc_code_zero; - long mc_unknown; -}; + Dwarf_Error error = 0; + Dwarf_Die cu_die; + Dwarf_Die sib_die; + int cu_res = dwarf_siblingof(dbg, NULL, &cu_die, &error); + + Dwarf_Off targetOffset = 0; + + 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; + + int success = dwarf_tag(d, &tag, &error); + + 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() {} @@ -413,7 +517,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) @@ -459,7 +563,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; @@ -548,7 +652,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) { @@ -559,7 +663,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()); } } @@ -639,7 +743,93 @@ char *Juicer::getFirstAncestorName(Dwarf_Die inDie) return outName; } -Symbol *Juicer::process_DW_TAG_pointer_type(ElfFile &elf, Dwarf_Debug dbg, Dwarf_Die inDie) +/** + * @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{}; + + 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, Namespace *currentNamespace) { Symbol *outSymbol = 0; Dwarf_Attribute attr_struct = nullptr; @@ -710,7 +900,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 { @@ -719,7 +909,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); } } } @@ -787,14 +977,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; @@ -884,7 +1074,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) { @@ -914,7 +1104,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; @@ -971,7 +1161,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; } @@ -1047,10 +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; + + fqn = getFullyQualifiedNameForDIE(dbg, typeDie); } else { @@ -1078,7 +1271,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. @@ -1099,20 +1293,41 @@ 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); + 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); + 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); } } if (nullptr != outSymbol) { - process_DW_TAG_structure_type(elf, *outSymbol, dbg, typeDie); + process_DW_TAG_structure_type(elf, *outSymbol, dbg, typeDie, currentNamespace); } } else @@ -1123,20 +1338,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; } @@ -1251,7 +1466,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. @@ -1272,14 +1488,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); } } @@ -1288,7 +1504,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); @@ -1300,7 +1516,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) @@ -1323,7 +1539,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; } @@ -1416,7 +1632,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. @@ -1437,20 +1654,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); } } @@ -3232,7 +3449,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; @@ -3286,7 +3503,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) { @@ -3297,7 +3514,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. */ @@ -3337,7 +3554,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. @@ -3358,14 +3576,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); } } @@ -3377,7 +3595,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); } } } @@ -3548,7 +3766,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; @@ -3582,7 +3800,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) { @@ -3648,14 +3866,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); } } } @@ -3670,7 +3888,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; @@ -3902,7 +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) { - memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList); + std::string sMemberName = memberName; + /* Actually retrieve that DIE's parents (which, ironically, may be empty if it's a CU). */ + Dwarf_Off *parents = NULL; + memberBaseTypeSymbol = getBaseTypeSymbol(elf, memberDie, dimensionList, currentNamespace); if (memberBaseTypeSymbol == 0) { @@ -3972,7 +4193,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; @@ -4061,7 +4282,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) { @@ -4169,7 +4390,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) { @@ -4177,7 +4398,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(); @@ -4232,14 +4453,14 @@ 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) { 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(); @@ -4315,6 +4536,153 @@ 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)); + } + + namespaceName = name; + } + + // 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. @@ -4322,7 +4690,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; @@ -4334,6 +4702,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; @@ -4372,14 +4743,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; } @@ -4444,14 +4815,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 @@ -4459,10 +4830,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); } } @@ -4472,7 +4843,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; } @@ -4481,12 +4852,20 @@ 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; } + + case DW_TAG_namespace: + { + newParentNamespace = 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) { @@ -4495,7 +4874,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, newParentNamespace); } /* res == DW_DLV_NO_ENTRY */ @@ -4739,7 +5118,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); @@ -4752,8 +5132,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/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/Juicer.h b/src/Juicer.h index 61353c0c..5064cee1 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,15 +112,18 @@ 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); - 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); + 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); - 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); char* dwarfStringToChar(char* dwarfString); @@ -131,7 +135,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/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 new file mode 100644 index 00000000..d761bbb1 --- /dev/null +++ b/src/Namespace.cpp @@ -0,0 +1,68 @@ +#include "Namespace.hpp" + +Namespace::Namespace() {} +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; } + +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; } + +std::optional Namespace::getId() { return id; } +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); +} + +std::string Namespace::getFullyQualifiedName() +{ + // Ensure we don't set the member parent to nullptr + Namespace* tmpParent = parent; + fullyQualifiedName = name; + while (tmpParent != nullptr) + { + fullyQualifiedName = tmpParent->getName() + separator + fullyQualifiedName; + tmpParent = tmpParent->getParent(); + } + return fullyQualifiedName; +} + +std::vector& Namespace::getChildren() { return children; } diff --git a/src/Namespace.hpp b/src/Namespace.hpp new file mode 100644 index 00000000..c699e710 --- /dev/null +++ b/src/Namespace.hpp @@ -0,0 +1,43 @@ +#ifndef NAMESPACE_HPP +#define NAMESPACE_HPP + +#include +#include + +#include "Symbol.h" + +class Namespace +{ + public: + Namespace(); + Namespace(std::string name); + 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(); + void setParent(Namespace* parent); + + 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}; + // std::vector symbols; +}; + +#endif // NAMESPACE_HPP \ No newline at end of file diff --git a/src/SQLiteDB.cpp b/src/SQLiteDB.cpp index bd6f8e60..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); @@ -315,7 +325,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 +343,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 +380,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 +423,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,7 +431,7 @@ 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."); } else @@ -1139,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. @@ -1151,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(); @@ -1182,7 +1227,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 += ",\""; @@ -1193,6 +1238,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(); @@ -1203,7 +1259,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += "\""; - writeSymbolQuery += ")"; + writeSymbolQuery += ");"; rc = sqlite3_exec(database, writeSymbolQuery.c_str(), NULL, NULL, &errorMessage); @@ -1231,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 += ",\""; @@ -1247,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(); @@ -1257,7 +1324,7 @@ int SQLiteDB::writeSymbolsToDatabase(ElfFile& inElf) writeSymbolQuery += "\""; - writeSymbolQuery += ")"; + writeSymbolQuery += ");"; rc = sqlite3_exec(database, writeSymbolQuery.c_str(), NULL, NULL, &errorMessage); @@ -1848,6 +1915,162 @@ int SQLiteDB::writeEncodingsToDatabase(ElfFile& inElf) return rc; } +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()); + + 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; + } + + 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); + + 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()); + } + } + } + + 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); + + return rc; +} + /** *@brief This method creates all of the schemas that will be needed to store *the DWARF and ELF data. @@ -1939,6 +2162,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 +2596,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..f0c5bef8 100644 --- a/src/SQLiteDB.h +++ b/src/SQLiteDB.h @@ -37,18 +37,20 @@ "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 NOT NULL,\ 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)\ - UNIQUE(name));" + FOREIGN KEY(namespace) REFERENCES namespaces(id)\ + UNIQUE(name, namespace));" #define CREATE_DIMENSION_TABLE \ "CREATE TABLE IF NOT EXISTS dimension_lists (\ @@ -156,6 +158,15 @@ encoding TEXT NOT NULL,\ UNIQUE (encoding));" +#define CREATE_NAMESPACES_TABLE \ + "CREATE TABLE IF NOT EXISTS namespaces(\ + id INTEGER PRIMARY KEY,\ + name TEXT NOT NULL,\ + parent INTEGER ,\ + fully_qualified_name TEXT NOT NULL,\ + FOREIGN KEY (parent) REFERENCES namespaces(id),\ + UNIQUE (fully_qualified_name)); " + //#define CREATE_DATA_OBJECTS_TABLE \ // "CREATE TABLE IF NOT EXISTS data_objects(\ // id INTEGER PRIMARY KEY,\ @@ -194,6 +205,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,11 +217,14 @@ 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 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(); + bool doesNamespaceExistInDB(const std::string &fullyqualifiedName); public: SQLiteDB(); 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 new file mode 100644 index 00000000..4aee78d9 --- /dev/null +++ b/unit-test/namespaces_test.cpp @@ -0,0 +1,95 @@ +#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 +{ +struct Shape +{ + int width; + int length; +}; + +} // namespace Earth + +namespace Mars +{ +struct Shape +{ + int width; + int length; +}; +} // namespace Mars +} // namespace Universe + +namespace Plane +{ +namespace _3D +{ +struct Shape +{ + int width; + int length; +}; +} // 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 +{ + int width; + int length; +}; +} // namespace Universe +} // namespace _4D + +} // namespace Plane +Universe::Earth::Shape earth{}; +Universe::Mars::Shape mars{}; + +Plane::_3D::Shape Space{}; + +Plane::_4D::Universe::Shape Star{}; + +Square s{}; + +Plane::_2D::Square s2{}; \ No newline at end of file