Skip to content

Commit

Permalink
Add option to pass two debuginfos
Browse files Browse the repository at this point in the history
SUSE packages contain the stripped .so file with .dynsym and the
debuginfo (.debug) provided in -debuginfo packages.  We need both
of them in Userspace Livepatching since 15.5 for proper analysis.
This commit patches the ElfCache and InlineAnalysis so it can use
both of them.

For kernel we expect it to only use one ELF file for now (the
first one).

Signed-off-by: Giuliano Belinassi <[email protected]>
  • Loading branch information
giulianobelinassi committed Aug 23, 2024
1 parent 0f79f7e commit 4c858e7
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 25 deletions.
9 changes: 7 additions & 2 deletions libcextract/ArgvParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ ArgvParser::ArgvParser(int argc, char **argv)
Ibt(false),
AllowLateExternalization(false),
PatchObject(""),
DebuginfoPath(nullptr),
Debuginfos(),
IpaclonesPath(nullptr),
SymversPath(nullptr),
DescOutputPath(nullptr),
Expand All @@ -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. */
Expand Down Expand Up @@ -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;
}
Expand Down
7 changes: 4 additions & 3 deletions libcextract/ArgvParser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ class ArgvParser
return PatchObject;
}

inline const char *Get_Debuginfo_Path(void)
inline std::vector<std::string> &Get_Debuginfo_Path(void)
{
return DebuginfoPath;
return Debuginfos;
}

inline const char *Get_Ipaclones_Path(void)
Expand Down Expand Up @@ -163,7 +163,8 @@ class ArgvParser
bool AllowLateExternalization;
std::string PatchObject;

const char *DebuginfoPath;
std::vector<std::string> Debuginfos;

const char *IpaclonesPath;
const char *SymversPath;

Expand Down
15 changes: 13 additions & 2 deletions libcextract/ElfCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 &section = *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:
Expand Down
29 changes: 27 additions & 2 deletions libcextract/ElfCXX.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -377,6 +389,16 @@ class ElfSymbolCache

std::vector<std::string> 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);

Expand All @@ -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;
};
23 changes: 14 additions & 9 deletions libcextract/InlineAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,27 @@
#include <cxxabi.h>
#include <stdexcept>

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<std::string> &elfs_path,
const char *ipaclones_path,
const char *symvers_path, bool is_kernel)
: ElfCache(nullptr),
Ipa(nullptr),
Symv(nullptr),
Kernel(is_kernel)
{
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) {
Expand All @@ -62,8 +69,6 @@ InlineAnalysis::~InlineAnalysis(void)
{
if (ElfCache)
delete ElfCache;
if (ElfObj)
delete ElfObj;
if (Ipa)
delete Ipa;
if (Symv)
Expand Down
30 changes: 26 additions & 4 deletions libcextract/InlineAnalysis.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> &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<std::string>({elf_path}),
ipaclone_path, symvers_path, is_kernel)
{}

~InlineAnalysis(void);

Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -143,7 +166,6 @@ class InlineAnalysis
/** Put color information in the graphviz .DOT file. */
void Print_Node_Colors(const std::set<IpaCloneNode *> &set, FILE *fp);

ElfObject *ElfObj;
ElfSymbolCache *ElfCache;
IpaClones *Ipa;
Symvers *Symv;
Expand Down
6 changes: 3 additions & 3 deletions libcextract/Passes.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand All @@ -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())
{
}

Expand Down Expand Up @@ -121,7 +121,7 @@ class PassManager {
std::vector<const char *> &ClangArgs;

/* Path to Debuginfo, if exists. */
const char *DebuginfoPath;
std::vector<std::string> &Debuginfos;

/* Path to Ipaclones, if exists. */
const char *IpaclonesPath;
Expand Down

0 comments on commit 4c858e7

Please sign in to comment.