diff --git a/libcextract/ArgvParser.cpp b/libcextract/ArgvParser.cpp index c428aca..1686a6b 100644 --- a/libcextract/ArgvParser.cpp +++ b/libcextract/ArgvParser.cpp @@ -74,7 +74,7 @@ ArgvParser::ArgvParser(int argc, char **argv) Ibt(false), AllowLateExternalization(false), PatchObject(""), - DebuginfoPath(nullptr), + Debuginfos(), IpaclonesPath(nullptr), SymversPath(nullptr), DescOutputPath(nullptr), @@ -89,6 +89,11 @@ ArgvParser::ArgvParser(int argc, char **argv) Insert_Required_Parameters(); + const char *DebuginfoPath = nullptr; + if (Debuginfos.size() > 0) { + DebuginfoPath = Debuginfos[0].c_str(); + } + /* For kernel, check if the object patch is not the same as DebugInfo. If they * are not the same, it means that the module from PatchObject is builtin, so * assign vmlinux to PatchObject. */ @@ -252,7 +257,7 @@ bool ArgvParser::Handle_Clang_Extract_Arg(const char *str) return true; } if (prefix("-DCE_DEBUGINFO_PATH=", str)) { - DebuginfoPath = Extract_Single_Arg_C(str); + Debuginfos = Extract_Args(str); return true; } diff --git a/libcextract/ArgvParser.hh b/libcextract/ArgvParser.hh index 77546b5..c0a85eb 100644 --- a/libcextract/ArgvParser.hh +++ b/libcextract/ArgvParser.hh @@ -94,9 +94,9 @@ class ArgvParser return PatchObject; } - inline const char *Get_Debuginfo_Path(void) + inline std::vector &Get_Debuginfo_Path(void) { - return DebuginfoPath; + return Debuginfos; } inline const char *Get_Ipaclones_Path(void) @@ -163,7 +163,8 @@ class ArgvParser bool AllowLateExternalization; std::string PatchObject; - const char *DebuginfoPath; + std::vector Debuginfos; + const char *IpaclonesPath; const char *SymversPath; diff --git a/libcextract/ElfCXX.cpp b/libcextract/ElfCXX.cpp index a5a1223..d3c7f4c 100644 --- a/libcextract/ElfCXX.cpp +++ b/libcextract/ElfCXX.cpp @@ -335,19 +335,30 @@ void ElfSymbolCache::Insert_Symbols_Into_Hash(SymbolTableHash &map, ElfSection & } ElfSymbolCache::ElfSymbolCache(ElfObject &eo) - : EO(eo) + : ElfSymbolCache() +{ + Analyze_ELF(eo); +} + +void ElfSymbolCache::Analyze_ELF(ElfObject &eo) { /* Look for dynsym and symtab sections. */ - for (auto it = EO.section_begin(); it != EO.section_end(); ++it) + for (auto it = eo.section_begin(); it != eo.section_end(); ++it) { ElfSection §ion = *it; switch (section.Get_Section_Type()) { case SHT_DYNSYM: Insert_Symbols_Into_Hash(DynsymMap, section); + + assert(ObjectPath == "" && "Multiple libraries passed as debuginfo?"); + ObjectPath = eo.Get_Path(); break; case SHT_SYMTAB: Insert_Symbols_Into_Hash(SymtabMap, section); + + /* We can also have symtab in the .so library. */ + DebuginfoPath = eo.Get_Path(); break; case SHT_PROGBITS: diff --git a/libcextract/ElfCXX.hh b/libcextract/ElfCXX.hh index 35dbbdc..422a503 100644 --- a/libcextract/ElfCXX.hh +++ b/libcextract/ElfCXX.hh @@ -346,6 +346,18 @@ class ElfSymbolCache /** Build cache from ElfObject). */ ElfSymbolCache(ElfObject &eo); + /** Build empty cache to be filled later. */ + ElfSymbolCache(void) + : DynsymMap(), + SymtabMap(), + Mod(""), + DebuginfoPath(""), + ObjectPath("") + {}; + + /** Analyze ELF object. */ + void Analyze_ELF(ElfObject &eo); + /* Get symbol if available in the Dynsym table. Or 0 if not available. */ inline unsigned char Get_Symbol_Info_Dynsym(const std::string &sym) { @@ -377,6 +389,16 @@ class ElfSymbolCache std::vector Get_All_Symbols(void); + inline const std::string &Get_Debuginfo_Path(void) const + { + return DebuginfoPath; + } + + inline const std::string &Get_Object_Path(void) const + { + return ObjectPath; + } + /** Dump for debugging reasons. */ void Dump_Cache(void); @@ -394,6 +416,9 @@ class ElfSymbolCache /** Kernel module name, if .modinfo section is present. */ std::string Mod; - /** Reference to the ElfObject used to build this object. */ - ElfObject &EO; + /** Path to the debuginfo object (contains .symtab section). */ + std::string DebuginfoPath; + + /** Path to the .so file object (contains .dynsym section). */ + std::string ObjectPath; }; diff --git a/libcextract/InlineAnalysis.cpp b/libcextract/InlineAnalysis.cpp index 06a2c7f..6067734 100644 --- a/libcextract/InlineAnalysis.cpp +++ b/libcextract/InlineAnalysis.cpp @@ -22,10 +22,10 @@ #include #include -InlineAnalysis::InlineAnalysis(const char *elf_path, const char *ipaclones_path, - const char *symvers_path, bool is_kernel) - : ElfObj(nullptr), - ElfCache(nullptr), +InlineAnalysis::InlineAnalysis(const std::vector &elfs_path, + const char *ipaclones_path, + const char *symvers_path, bool is_kernel) + : ElfCache(nullptr), Ipa(nullptr), Symv(nullptr), Kernel(is_kernel) @@ -33,9 +33,16 @@ InlineAnalysis::InlineAnalysis(const char *elf_path, const char *ipaclones_path, try { /* Debuginfo information is not needed for inline analysis. But is desired for better precision. That is why whe declare those objects dynamically. */ - if (elf_path) { - ElfObj = new ElfObject(elf_path); - ElfCache = new ElfSymbolCache(*ElfObj); + if (elfs_path.size() > 0) { + /* Only create an ElfSymbolCache if we received elfs from command line. */ + ElfCache = new ElfSymbolCache(); + } + + /* Initialize the SymbolCache. */ + for (auto it = elfs_path.begin(); it != elfs_path.end(); ++it) { + const std::string &path = *it; + ElfObject elf(path); + ElfCache->Analyze_ELF(elf); } if (ipaclones_path) { @@ -62,8 +69,6 @@ InlineAnalysis::~InlineAnalysis(void) { if (ElfCache) delete ElfCache; - if (ElfObj) - delete ElfObj; if (Ipa) delete Ipa; if (Symv) diff --git a/libcextract/InlineAnalysis.hh b/libcextract/InlineAnalysis.hh index c3aeb71..2076040 100644 --- a/libcextract/InlineAnalysis.hh +++ b/libcextract/InlineAnalysis.hh @@ -48,7 +48,15 @@ class InlineAnalysis available, and ipaclone_path can be a directory full of many ipa-clones generated through LTO or not. Symvers can be NULL is we are creating a userspace livepatch */ - InlineAnalysis(const char *elf_path, const char *ipaclone_path, const char *symvers_path, bool is_kernel); + InlineAnalysis(const std::vector &elfs_path, + const char *ipaclone_path, const char *symvers_path, + bool is_kernel); + + InlineAnalysis(const char *elf_path, const char *ipaclone_path, + const char *symvers_path, bool is_kernel) + : InlineAnalysis(std::vector({elf_path}), + ipaclone_path, symvers_path, is_kernel) + {} ~InlineAnalysis(void); @@ -93,12 +101,27 @@ class InlineAnalysis /** True if this class was built with debuginfo enabled. */ inline bool Have_Debuginfo(void) { - return ElfObj && ElfCache; + return ElfCache; } inline const std::string &Get_Debuginfo_Path(void) { - return ElfObj->Get_Path(); + if (ElfCache) { + return ElfCache->Get_Debuginfo_Path(); + } + + static const std::string empty; + return empty; + } + + inline const std::string &Get_Object_Path(void) + { + if (ElfCache) { + return ElfCache->Get_Object_Path(); + } + + static const std::string empty; + return empty; } /** Check if we have Ipa-clones information. */ @@ -143,7 +166,6 @@ class InlineAnalysis /** Put color information in the graphviz .DOT file. */ void Print_Node_Colors(const std::set &set, FILE *fp); - ElfObject *ElfObj; ElfSymbolCache *ElfCache; IpaClones *Ipa; Symvers *Symv; diff --git a/libcextract/Passes.hh b/libcextract/Passes.hh index 4f2a295..0e52fbc 100644 --- a/libcextract/Passes.hh +++ b/libcextract/Passes.hh @@ -58,7 +58,7 @@ class PassManager { PatchObject(args.Get_PatchObject()), HeadersToExpand(args.Get_Headers_To_Expand()), ClangArgs(args.Get_Args_To_Clang()), - DebuginfoPath(args.Get_Debuginfo_Path()), + Debuginfos(args.Get_Debuginfo_Path()), IpaclonesPath(args.Get_Ipaclones_Path()), SymversPath(args.Get_Symvers_Path()), DscOutputPath(args.Get_Dsc_Output_Path()), @@ -67,7 +67,7 @@ class PassManager { args.Get_Include_Expansion_Policy(), Kernel)), NamesLog(), PassNum(0), - IA(DebuginfoPath, IpaclonesPath, SymversPath, args.Is_Kernel()) + IA(Debuginfos, IpaclonesPath, SymversPath, args.Is_Kernel()) { } @@ -121,7 +121,7 @@ class PassManager { std::vector &ClangArgs; /* Path to Debuginfo, if exists. */ - const char *DebuginfoPath; + std::vector &Debuginfos; /* Path to Ipaclones, if exists. */ const char *IpaclonesPath;