mirror of https://github.com/dynup/kpatch
lookup: parse Module.symvers in lookup_open()
Have lookup_open() also parse Module.symvers and add the resulting symbols
and their objnames to the lookup table. This code was essentially
cherry-picked from Josh Poimboeuf's lookup code found here:
8cdca59c88
That patch was modified to fix a bug in obj_read() (calling elf_end()
without strdup'ing the symbol name strings, which was causing null
dereferences) and to fix up the module name after reading it from
Module.symvers (replacing '-' with '_' and stripping the path prefixes).
Also, add lookup_exported_symbol_objname(), which looks up the objname of
an exported symbol by making use of the objname information obtained from
Module.symvers.
This commit is contained in:
parent
b6a15f3dd6
commit
58de46cb9e
|
@ -2246,11 +2246,11 @@ static void kpatch_build_strings_section_data(struct kpatch_elf *kelf)
|
|||
}
|
||||
|
||||
struct arguments {
|
||||
char *args[4];
|
||||
char *args[5];
|
||||
int debug;
|
||||
};
|
||||
|
||||
static char args_doc[] = "original.o patched.o kernel-object output.o";
|
||||
static char args_doc[] = "original.o patched.o kernel-object output.o Module.symvers";
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{"debug", 'd', NULL, 0, "Show debug output" },
|
||||
|
@ -2269,13 +2269,13 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
|
|||
arguments->debug = 1;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 4)
|
||||
if (state->arg_num >= 5)
|
||||
/* Too many arguments. */
|
||||
argp_usage (state);
|
||||
arguments->args[state->arg_num] = arg;
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if (state->arg_num < 4)
|
||||
if (state->arg_num < 5)
|
||||
/* Not enough arguments. */
|
||||
argp_usage (state);
|
||||
break;
|
||||
|
@ -2296,6 +2296,7 @@ int main(int argc, char *argv[])
|
|||
struct section *sec, *symtab;
|
||||
struct symbol *sym;
|
||||
char *hint = NULL, *objname, *pos;
|
||||
char *mod_symvers_path;
|
||||
|
||||
arguments.debug = 0;
|
||||
argp_parse (&argp, argc, argv, 0, NULL, &arguments);
|
||||
|
@ -2306,6 +2307,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
childobj = basename(arguments.args[0]);
|
||||
|
||||
mod_symvers_path = arguments.args[4];
|
||||
|
||||
kelf_base = kpatch_elf_open(arguments.args[0]);
|
||||
kelf_patched = kpatch_elf_open(arguments.args[1]);
|
||||
|
||||
|
@ -2378,7 +2381,7 @@ int main(int argc, char *argv[])
|
|||
ERROR("FILE symbol not found in output. Stripped?\n");
|
||||
|
||||
/* create symbol lookup table */
|
||||
lookup = lookup_open(arguments.args[2]);
|
||||
lookup = lookup_open(arguments.args[2], mod_symvers_path);
|
||||
|
||||
/* extract module name (destructive to arguments.modulefile) */
|
||||
objname = basename(arguments.args[2]);
|
||||
|
|
|
@ -557,7 +557,7 @@ for i in $FILES; do
|
|||
fi
|
||||
cd $TEMPDIR
|
||||
if [[ -e "orig/$i" ]]; then
|
||||
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE" "output/$i" 2>&1 |tee -a "$LOGFILE"
|
||||
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE" "output/$i" "$OBJDIR/Module.symvers" 2>&1 |tee -a "$LOGFILE"
|
||||
rc="${PIPESTATUS[0]}"
|
||||
if [[ $rc = 139 ]]; then
|
||||
warn "create-diff-object SIGSEGV"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* the symbol table of an ELF object.
|
||||
*
|
||||
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
|
||||
* Copyright (C) 2014 Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -24,6 +25,8 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -31,29 +34,38 @@
|
|||
#include <error.h>
|
||||
#include <gelf.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "lookup.h"
|
||||
|
||||
#define ERROR(format, ...) \
|
||||
error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
struct symbol {
|
||||
struct object_symbol {
|
||||
unsigned long value;
|
||||
unsigned long size;
|
||||
char *name;
|
||||
int type, bind, skip;
|
||||
};
|
||||
|
||||
struct lookup_table {
|
||||
int fd, nr;
|
||||
Elf *elf;
|
||||
struct symbol *syms;
|
||||
struct export_symbol {
|
||||
char *name;
|
||||
char *objname;
|
||||
};
|
||||
|
||||
#define for_each_symbol(ndx, iter, table) \
|
||||
for (ndx = 0, iter = table->syms; ndx < table->nr; ndx++, iter++)
|
||||
struct lookup_table {
|
||||
int obj_nr, exp_nr;
|
||||
struct object_symbol *obj_syms;
|
||||
struct export_symbol *exp_syms;
|
||||
};
|
||||
|
||||
struct lookup_table *lookup_open(char *path)
|
||||
#define for_each_obj_symbol(ndx, iter, table) \
|
||||
for (ndx = 0, iter = table->obj_syms; ndx < table->obj_nr; ndx++, iter++)
|
||||
|
||||
#define for_each_exp_symbol(ndx, iter, table) \
|
||||
for (ndx = 0, iter = table->exp_syms; ndx < table->exp_nr; ndx++, iter++)
|
||||
|
||||
static void obj_read(struct lookup_table *table, char *path)
|
||||
{
|
||||
Elf *elf;
|
||||
int fd, i, len;
|
||||
|
@ -62,8 +74,7 @@ struct lookup_table *lookup_open(char *path)
|
|||
GElf_Sym sym;
|
||||
Elf_Data *data;
|
||||
char *name;
|
||||
struct lookup_table *table;
|
||||
struct symbol *mysym;
|
||||
struct object_symbol *mysym;
|
||||
size_t shstrndx;
|
||||
|
||||
if ((fd = open(path, O_RDONLY, 0)) < 0)
|
||||
|
@ -102,18 +113,13 @@ struct lookup_table *lookup_open(char *path)
|
|||
|
||||
len = sh.sh_size / sh.sh_entsize;
|
||||
|
||||
table = malloc(sizeof(*table));
|
||||
if (!table)
|
||||
ERROR("malloc table");
|
||||
table->syms = malloc(len * sizeof(struct symbol));
|
||||
if (!table->syms)
|
||||
ERROR("malloc table.syms");
|
||||
memset(table->syms, 0, len * sizeof(struct symbol));
|
||||
table->nr = len;
|
||||
table->fd = fd;
|
||||
table->elf = elf;
|
||||
table->obj_syms = malloc(len * sizeof(*table->obj_syms));
|
||||
if (!table->obj_syms)
|
||||
ERROR("malloc table.obj_syms");
|
||||
memset(table->obj_syms, 0, len * sizeof(*table->obj_syms));
|
||||
table->obj_nr = len;
|
||||
|
||||
for_each_symbol(i, mysym, table) {
|
||||
for_each_obj_symbol(i, mysym, table) {
|
||||
if (!gelf_getsym(data, i, &sym))
|
||||
ERROR("gelf_getsym");
|
||||
|
||||
|
@ -130,29 +136,107 @@ struct lookup_table *lookup_open(char *path)
|
|||
mysym->size = sym.st_size;
|
||||
mysym->type = GELF_ST_TYPE(sym.st_info);
|
||||
mysym->bind = GELF_ST_BIND(sym.st_info);
|
||||
mysym->name = name;
|
||||
mysym->name = strdup(name);
|
||||
if (!mysym->name)
|
||||
ERROR("strdup");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
elf_end(elf);
|
||||
}
|
||||
|
||||
/* Strip the path and replace '-' with '_' */
|
||||
static char *make_modname(char *modname)
|
||||
{
|
||||
char *cur;
|
||||
|
||||
if (!modname)
|
||||
return NULL;
|
||||
|
||||
cur = modname;
|
||||
while (*cur != '\0') {
|
||||
if (*cur == '-')
|
||||
*cur = '_';
|
||||
cur++;
|
||||
}
|
||||
|
||||
return basename(modname);
|
||||
}
|
||||
|
||||
static void symvers_read(struct lookup_table *table, char *path)
|
||||
{
|
||||
FILE *file;
|
||||
unsigned int crc, i = 0;
|
||||
char name[256], mod[256], export[256];
|
||||
char *objname, *symname;
|
||||
|
||||
if ((file = fopen(path, "r")) < 0)
|
||||
ERROR("fopen");
|
||||
|
||||
while (fscanf(file, "%x %s %s %s\n",
|
||||
&crc, name, mod, export) != EOF)
|
||||
table->exp_nr++;
|
||||
|
||||
table->exp_syms = malloc(table->exp_nr * sizeof(*table->exp_syms));
|
||||
if (!table->exp_syms)
|
||||
ERROR("malloc table.exp_syms");
|
||||
memset(table->exp_syms, 0,
|
||||
table->exp_nr * sizeof(*table->exp_syms));
|
||||
|
||||
rewind(file);
|
||||
|
||||
while (fscanf(file, "%x %s %s %s\n",
|
||||
&crc, name, mod, export) != EOF) {
|
||||
symname = strdup(name);
|
||||
if (!symname)
|
||||
perror("strdup");
|
||||
|
||||
objname = strdup(mod);
|
||||
if (!objname)
|
||||
perror("strdup");
|
||||
/* Modifies objname in-place */
|
||||
objname = make_modname(objname);
|
||||
|
||||
table->exp_syms[i].name = symname;
|
||||
table->exp_syms[i].objname = objname;
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
struct lookup_table *lookup_open(char *obj_path, char *symvers_path)
|
||||
{
|
||||
struct lookup_table *table;
|
||||
|
||||
table = malloc(sizeof(*table));
|
||||
if (!table)
|
||||
ERROR("malloc table");
|
||||
memset(table, 0, sizeof(*table));
|
||||
|
||||
obj_read(table, obj_path);
|
||||
symvers_read(table, symvers_path);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void lookup_close(struct lookup_table *table)
|
||||
{
|
||||
elf_end(table->elf);
|
||||
close(table->fd);
|
||||
free(table->obj_syms);
|
||||
free(table->exp_syms);
|
||||
free(table);
|
||||
}
|
||||
|
||||
int lookup_local_symbol(struct lookup_table *table, char *name, char *hint,
|
||||
struct lookup_result *result)
|
||||
{
|
||||
struct symbol *sym, *match = NULL;
|
||||
struct object_symbol *sym, *match = NULL;
|
||||
int i;
|
||||
unsigned long pos = 0;
|
||||
char *curfile = NULL;
|
||||
|
||||
memset(result, 0, sizeof(*result));
|
||||
for_each_symbol(i, sym, table) {
|
||||
for_each_obj_symbol(i, sym, table) {
|
||||
if (sym->type == STT_FILE) {
|
||||
if (!strcmp(sym->name, hint)) {
|
||||
curfile = sym->name;
|
||||
|
@ -192,11 +276,11 @@ int lookup_local_symbol(struct lookup_table *table, char *name, char *hint,
|
|||
int lookup_global_symbol(struct lookup_table *table, char *name,
|
||||
struct lookup_result *result)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct object_symbol *sym;
|
||||
int i;
|
||||
|
||||
memset(result, 0, sizeof(*result));
|
||||
for_each_symbol(i, sym, table)
|
||||
for_each_obj_symbol(i, sym, table) {
|
||||
if (!sym->skip && (sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) &&
|
||||
!strcmp(sym->name, name)) {
|
||||
result->value = sym->value;
|
||||
|
@ -204,25 +288,50 @@ int lookup_global_symbol(struct lookup_table *table, char *name,
|
|||
result->pos = 0; /* always 0 for global symbols */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lookup_is_exported_symbol(struct lookup_table *table, char *name)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct export_symbol *sym, *match = NULL;
|
||||
int i;
|
||||
char export[255] = "__ksymtab_";
|
||||
|
||||
strncat(export, name, 254);
|
||||
for_each_exp_symbol(i, sym, table) {
|
||||
if (!strcmp(sym->name, name)) {
|
||||
if (match)
|
||||
ERROR("duplicate exported symbol found for %s", name);
|
||||
match = sym;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_symbol(i, sym, table)
|
||||
if (!sym->skip && !strcmp(sym->name, export))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return !!match;
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup_exported_symbol_objname - find the object/module an exported
|
||||
* symbol belongs to.
|
||||
*/
|
||||
char *lookup_exported_symbol_objname(struct lookup_table *table, char *name)
|
||||
{
|
||||
struct export_symbol *sym, *match = NULL;
|
||||
int i;
|
||||
|
||||
for_each_exp_symbol(i, sym, table) {
|
||||
if (!strcmp(sym->name, name)) {
|
||||
if (match)
|
||||
ERROR("duplicate exported symbol found for %s", name);
|
||||
match = sym;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
return match->objname;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 /* for local testing */
|
||||
static void find_this(struct lookup_table *table, char *sym, char *hint)
|
||||
{
|
||||
|
|
|
@ -9,12 +9,13 @@ struct lookup_result {
|
|||
unsigned long pos;
|
||||
};
|
||||
|
||||
struct lookup_table *lookup_open(char *path);
|
||||
struct lookup_table *lookup_open(char *obj_path, char *symvers_path);
|
||||
void lookup_close(struct lookup_table *table);
|
||||
int lookup_local_symbol(struct lookup_table *table, char *name, char *hint,
|
||||
struct lookup_result *result);
|
||||
int lookup_global_symbol(struct lookup_table *table, char *name,
|
||||
struct lookup_result *result);
|
||||
int lookup_is_exported_symbol(struct lookup_table *table, char *name);
|
||||
char *lookup_exported_symbol_objname(struct lookup_table *table, char *name);
|
||||
|
||||
#endif /* _LOOKUP_H_ */
|
||||
|
|
Loading…
Reference in New Issue