Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marcosps ibt support #35

Merged
merged 6 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions libcextract/ArgvParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ ArgvParser::ArgvParser(int argc, char **argv)
DumpPasses(false),
RenameSymbols(false),
Kernel(false),
Ibt(false),
DebuginfoPath(nullptr),
IpaclonesPath(nullptr),
SymversPath(nullptr),
Expand Down Expand Up @@ -166,6 +167,20 @@ bool ArgvParser::Handle_Clang_Extract_Arg(const char *str)
return false;
}

if (!strcmp("-D__USE_IBT__", str)) {
Ibt = true;
return false;
}

if (prefix("-DKBUILD_MODNAME=", str)) {
/* Avoid storing double quotes */
PatchObject = Extract_Single_Arg(str);
PatchObject.erase(std::remove(PatchObject.begin(), PatchObject.end(), '\"' ),
PatchObject.end());

return false;
}

if (prefix("-DCE_EXTRACT_FUNCTIONS=", str)) {
FunctionsToExtract = Extract_Args(str);

Expand Down
13 changes: 13 additions & 0 deletions libcextract/ArgvParser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ class ArgvParser
return Kernel;
}

inline bool Has_Ibt(void)
{
return Ibt;
}

inline std::string Get_PatchObject(void)
{
return PatchObject;
}

inline const char *Get_Debuginfo_Path(void)
{
return DebuginfoPath;
Expand Down Expand Up @@ -140,6 +150,9 @@ class ArgvParser
bool DumpPasses;
bool RenameSymbols;
bool Kernel;
/* If the file was compiled with IBT support */
bool Ibt;
std::string PatchObject;

const char *DebuginfoPath;
const char *IpaclonesPath;
Expand Down
2 changes: 1 addition & 1 deletion libcextract/Passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ class FunctionExternalizerPass : public Pass
virtual bool Run_Pass(PassManager::Context *ctx)
{
/* Issue externalization. */
SymbolExternalizer externalizer(ctx->AST.get(), ctx->IA, ctx->DumpPasses);
SymbolExternalizer externalizer(ctx->AST.get(), ctx->IA, ctx->Ibt, ctx->PatchObject, ctx->DumpPasses);
externalizer.Externalize_Symbols(ctx->Externalize);
if (ctx->RenameSymbols) {
/* The FuncExtractNames will be modified, as the function will be
Expand Down
8 changes: 8 additions & 0 deletions libcextract/Passes.hh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class PassManager {
DumpPasses(args.Should_Dump_Passes()),
RenameSymbols(args.Should_Rename_Symbols()),
Kernel(args.Is_Kernel()),
Ibt(args.Has_Ibt()),
PatchObject(args.Get_PatchObject()),
HeadersToExpand(args.Get_Headers_To_Expand()),
ClangArgs(args.Get_Args_To_Clang()),
DebuginfoPath(args.Get_Debuginfo_Path()),
Expand Down Expand Up @@ -102,6 +104,12 @@ class PassManager {
/** If the source code comes from Linux Kernel */
bool Kernel;

/** If the code was compiled with IBT support */
bool Ibt;

/** Object that will be patched. */
std::string PatchObject;

/** Which includes we must expand? */
std::vector<std::string> HeadersToExpand;

Expand Down
61 changes: 56 additions & 5 deletions libcextract/SymbolExternalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,19 @@ void TextModifications::Commit(void)

/* Insert into the list of FileIDs. */
const FileEntry *fentry = SM.getFileEntryForID(begin_id);

/* There are some cases where the fentry is known to return NULL. Check if
those are the cases we already acknownledged. */
if (fentry == nullptr) {
PresumedLoc ploc = SM.getPresumedLoc(a.ToChange.getBegin());
if (ploc.getFilename() == StringRef("<command line>")) {
/* Locations comming from the command line can be ignored. */
continue;
}

/* Crash with assertion. */
assert(fentry && "FileEntry is NULL on a non-acknowledged case");
}
/* Insert the FileEntry if we don't have one. */
if (FileEntryMap.find(fentry) == FileEntryMap.end()) {
/* Insert it. */
Expand Down Expand Up @@ -520,6 +533,11 @@ void SymbolExternalizer::Remove_Text(const SourceRange &range, int prio)
Replace_Text(range, "", prio);
}

void SymbolExternalizer::Insert_Text(const SourceRange &range, StringRef text, int prio)
{
Replace_Text(range, text, prio);
}

VarDecl *SymbolExternalizer::Create_Externalized_Var(DeclaratorDecl *decl, const std::string &name)
{
/* Hack a new Variable Declaration node in which holds the address of our
Expand Down Expand Up @@ -548,6 +566,10 @@ VarDecl *SymbolExternalizer::Create_Externalized_Var(DeclaratorDecl *decl, const
/* Create a type that is a pointer to the externalized object's type. */
QualType pointer_to = astctx.getPointerType(decl->getType());

/* For IBT, create an extern variable with the same type from the original */
if (Ibt)
pointer_to = decl->getType();

/* Get context of decl. */
DeclContext *decl_ctx;

Expand All @@ -558,13 +580,22 @@ VarDecl *SymbolExternalizer::Create_Externalized_Var(DeclaratorDecl *decl, const
decl_ctx = decl->getDeclContext();
}

/*
* For normal externalization, create a static variable. When dealing with IBT
* restrictions, create an extern variable that will be sorted out later by
* the code that is using it, like Linux for example.
*/
StorageClass sc = SC_Static;
if (Ibt)
sc = SC_Extern;

VarDecl *ret = VarDecl::Create(astctx, decl_ctx,
decl->getBeginLoc(),
decl->getEndLoc(),
id,
pointer_to,
nullptr,
SC_Static
sc
);

/* return node. */
Expand Down Expand Up @@ -748,7 +779,7 @@ bool SymbolExternalizer::_Externalize_Symbol(const std::string &to_externalize,
TypeUpdaterVisitor(*this, new_decl, to_externalize, wrap)
.TraverseDecl(decl);

FunctionUpdater(*this, new_decl, to_externalize, wrap)
FunctionUpdater(*this, new_decl, to_externalize, wrap || Ibt)
.Update_References_To_Symbol(decl);
}

Expand All @@ -758,25 +789,37 @@ bool SymbolExternalizer::_Externalize_Symbol(const std::string &to_externalize,
/* If we found the first instance of the function we want to externalize,
then proceed to create and replace the function declaration node with
a variable declaration node of proper type. */
std::string new_name = EXTERNALIZED_PREFIX + decl->getName().str();
std::string old_name = decl->getName().str();
std::string new_name = EXTERNALIZED_PREFIX + old_name;
new_decl = Create_Externalized_Var(decl, new_name);
Log.push_back({.OldName = decl->getName().str(),
Log.push_back({.OldName = old_name,
.NewName = new_name,
.Type = ExternalizationType::STRONG});

/* Create a string with the new variable type and name. */
std::string o;
llvm::raw_string_ostream outstr(o);
new_decl->print(outstr, AST->getLangOpts());
if (Ibt) {
outstr << " \\\n" << "\tKLP_RELOC_SYMBOL(" << PatchObject << ", " <<
IA.Get_Symbol_Module(old_name) << ", " << old_name << ")";
}
outstr << ";\n";

Replace_Text(decl->getSourceRange(), outstr.str(), 1000);

must_update = true;
wrap = false;

/* Update any macros that may reference the symbol. */
std::string replacement = "(*" + new_decl->getName().str() + ")";
/*
* IBT uses extern variables, so we need to use the same type from the
* private symbol.
*/
if (Ibt)
replacement = new_decl->getName().str();

/* Update any macros that may reference the symbol. */
Rewrite_Macros(to_externalize, replacement);

/* Slaps the new node into the position of where was the function
Expand Down Expand Up @@ -892,6 +935,14 @@ void SymbolExternalizer::Externalize_Symbol(const std::string &to_externalize)

void SymbolExternalizer::Externalize_Symbols(std::vector<std::string> const &to_externalize_array)
{
if (Ibt) {
SourceManager &sm = AST->getSourceManager();
FileID fi = sm.getMainFileID();
SourceLocation sl = sm.getLocForStartOfFile(fi);
SourceRange sr(sl, sl);
Insert_Text(sr, "#include <linux/livepatch.h>\n", 1000);
}

for (const std::string &to_externalize : to_externalize_array) {
Externalize_Symbol(to_externalize);
}
Expand Down
13 changes: 11 additions & 2 deletions libcextract/SymbolExternalizer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,13 @@ class TextModifications
class SymbolExternalizer
{
public:
SymbolExternalizer(ASTUnit *ast, InlineAnalysis &ia, bool dump = false)
SymbolExternalizer(ASTUnit *ast, InlineAnalysis &ia, bool ibt, std::string patch_object, bool dump = false)
: AST(ast),
MW(ast->getPreprocessor()),
TM(ast, dump),
IA(ia)
IA(ia),
Ibt(ibt),
PatchObject(patch_object)
{
}

Expand Down Expand Up @@ -269,6 +271,7 @@ class SymbolExternalizer
used in case that there are two replacements to the same piece of text. */
void Replace_Text(const SourceRange &range, StringRef new_name, int priority);
void Remove_Text(const SourceRange &range, int priority);
void Insert_Text(const SourceRange &range, StringRef text, int priority);

/** AST in analysis. */
ASTUnit *AST;
Expand All @@ -284,4 +287,10 @@ class SymbolExternalizer

/** Log of changed names. */
std::vector<ExternalizerLogEntry> Log;

/** Defines the method that a private symbol will be searched. */
bool Ibt;

/* Name of the object that will be patched. */
std::string PatchObject;
};
1 change: 1 addition & 0 deletions testsuite/linux/Modules.symvers
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x00000000 crc32c lib/libcrc32c EXPORT_SYMBOL
19 changes: 19 additions & 0 deletions testsuite/linux/ibt-1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_SYMVERS_PATH=../testsuite/linux/Modules.symvers -DCE_RENAME_SYMBOLS -nostdinc -I../testsuite/linux -DKBUILD_MODNAME=libcrc32c -D__USE_IBT__ -D__KERNEL__ -DCE_KEEP_INCLUDES" } */

typedef unsigned int u32;

u32 crc32c(u32 crc, const void *address, unsigned int length);

int f(void)
{
u32 lcrc = 0;
void *addr = 0;
unsigned int len = 0;

(void)crc32c(lcrc, addr, len);
return 0;
}

/* { dg-final { scan-tree-dump "u32 klpe_crc32c|u32 \(klpe_crc32c\)" } } */
/* { dg-final { scan-tree-dump "KLP_RELOC_SYMBOL\(libcrc32c, libcrc32c, crc32c\)" } } */
/* { dg-final { scan-tree-dump-not "\(\*klpe_crc32c\)" } } */
23 changes: 23 additions & 0 deletions testsuite/linux/ibt-2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_SYMVERS_PATH=../testsuite/linux/Modules.symvers -DCE_RENAME_SYMBOLS -nostdinc -I../testsuite/linux -DKBUILD_MODNAME=libcrc32c -D__USE_IBT__ -D__KERNEL__ -DCE_KEEP_INCLUDES" } */

/* Check why the include is not being output. */
/* { dg-xfail }*/

typedef unsigned int u32;

u32 crc32c(u32 crc, const void *address, unsigned int length);

int f(void)
{
u32 lcrc = 0;
void *addr = 0;
unsigned int len = 0;

(void)crc32c(lcrc, addr, len);
return 0;
}

/* { dg-final { scan-tree-dump "#include <linux/livepatch.h>" } } */
/* { dg-final { scan-tree-dump "u32 klpe_crc32c|u32 \(klpe_crc32c\)" } } */
/* { dg-final { scan-tree-dump "KLP_RELOC_SYMBOL\(libcrc32c, libcrc32c, crc32c\)" } } */
/* { dg-final { scan-tree-dump-not "\(\*klpe_crc32c\)" } } */
22 changes: 22 additions & 0 deletions testsuite/linux/ibt-3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_SYMVERS_PATH=../testsuite/linux/Modules.symvers -DCE_RENAME_SYMBOLS -nostdinc -I../testsuite/linux -DKBUILD_MODNAME=libcrc32c -D__USE_IBT__ -D__KERNEL__ -DCE_KEEP_INCLUDES" } */
/* { dg-xfail } */

/* Check why parenthesis are being output in the redeclaration. */

typedef unsigned int u32;

u32 crc32c(u32 crc, const void *address, unsigned int length);

int f(void)
{
u32 lcrc = 0;
void *addr = 0;
unsigned int len = 0;

(void)crc32c(lcrc, addr, len);
return 0;
}

/* { dg-final { scan-tree-dump "u32 klpe_crc32c" } } */
/* { dg-final { scan-tree-dump "KLP_RELOC_SYMBOL\(libcrc32c, libcrc32c, crc32c\)" } } */
/* { dg-final { scan-tree-dump-not "\(\*klpe_crc32c\)" } } */
18 changes: 18 additions & 0 deletions testsuite/linux/linux/livepatch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* KLP_RELOC_SYMBOL_POS - define relocation for external symbols
*
* @LP_OBJ_NAME: name of the livepatched object where the symbol is needed
* @SYM_OBJ_NAME: name of the object where the symbol exists
* @SYM_NAME: symbol name
* @SYM_POS: position of the symbol in SYM_OBJ when there are more
* symbols of the same name.
*
* Use for annotating external symbols used in livepatches which are
* not exported in vmlinux or are in livepatched modules, see
* Documentation/livepatch/module-elf-format.rst
*/
#define KLP_RELOC_SYMBOL_POS(LP_OBJ_NAME, SYM_OBJ_NAME, SYM_NAME, SYM_POS) \
asm("\".klp.sym.rela." #LP_OBJ_NAME "." #SYM_OBJ_NAME "." #SYM_NAME "," #SYM_POS "\"")

#define KLP_RELOC_SYMBOL(LP_OBJ_NAME, SYM_OBJ_NAME, SYM_NAME) \
KLP_RELOC_SYMBOL_POS(LP_OBJ_NAME, SYM_OBJ_NAME, SYM_NAME, 0)
Empty file added testsuite/linux/meson.build
Empty file.
2 changes: 1 addition & 1 deletion testsuite/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# Author: Giuliano Belinassi

runtest = find_program('lib/runtest.py')
ordinary_test_dirs = [ 'small/', 'includes/', 'ccp/' ]
ordinary_test_dirs = [ 'small/', 'includes/', 'ccp/', 'linux' ]

returncode_to_bool = [ true, false ]

Expand Down
Loading