Skip to content

Commit

Permalink
todo
Browse files Browse the repository at this point in the history
  • Loading branch information
jpoimboe committed May 11, 2018
1 parent 9477a04 commit 8a67f2e
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 120 deletions.
54 changes: 22 additions & 32 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2984,11 +2984,11 @@ static void kpatch_build_strings_section_data(struct kpatch_elf *kelf)
}

struct arguments {
char *args[6];
char *args[7];
int debug;
};

static char args_doc[] = "original.o patched.o kernel-object output.o Module.symvers patch-module-name";
static char args_doc[] = "original.o patched.o parent-name parent-symtab Module.symvers patch-module-name output.o";

static struct argp_option options[] = {
{"debug", 'd', NULL, 0, "Show debug output" },
Expand All @@ -3007,13 +3007,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 >= 6)
if (state->arg_num >= 7)
/* Too many arguments. */
argp_usage (state);
arguments->args[state->arg_num] = arg;
break;
case ARGP_KEY_END:
if (state->arg_num < 6)
if (state->arg_num < 7)
/* Not enough arguments. */
argp_usage (state);
break;
Expand All @@ -3033,8 +3033,8 @@ int main(int argc, char *argv[])
struct lookup_table *lookup;
struct section *sec, *symtab;
struct symbol *sym;
char *hint = NULL, *objname, *pos;
char *mod_symvers_path, *pmod_name;
char *hint = NULL, *orig_obj, *patched_obj, *parent_name;
char *parent_symtab, *mod_symvers, *patch_name, *output_obj;
struct sym_compare_type *base_locals;

arguments.debug = 0;
Expand All @@ -3044,13 +3044,18 @@ int main(int argc, char *argv[])

elf_version(EV_CURRENT);

childobj = basename(arguments.args[0]);
orig_obj = arguments.args[0];
patched_obj = arguments.args[1];
parent_name = arguments.args[2];
parent_symtab = arguments.args[3];
mod_symvers = arguments.args[4];
patch_name = arguments.args[5];
output_obj = arguments.args[6];

mod_symvers_path = arguments.args[4];
pmod_name = arguments.args[5];
childobj = basename(orig_obj);

kelf_base = kpatch_elf_open(arguments.args[0]);
kelf_patched = kpatch_elf_open(arguments.args[1]);
kelf_base = kpatch_elf_open(orig_obj);
kelf_patched = kpatch_elf_open(patched_obj);

kpatch_bundle_symbols(kelf_base);
kpatch_bundle_symbols(kelf_patched);
Expand All @@ -3070,7 +3075,7 @@ int main(int argc, char *argv[])

/* create symbol lookup table */
base_locals = kpatch_elf_locals(kelf_base);
lookup = lookup_open(arguments.args[2], mod_symvers_path, hint, base_locals);
lookup = lookup_open(parent_symtab, mod_symvers, hint, base_locals);
free(base_locals);

kpatch_mark_grouped_sections(kelf_patched);
Expand Down Expand Up @@ -3128,27 +3133,12 @@ int main(int argc, char *argv[])
*/
kpatch_elf_teardown(kelf_patched);

/* extract module name (destructive to arguments.modulefile) */
objname = basename(arguments.args[2]);
if (!strncmp(objname, "vmlinux-", 8))
objname = "vmlinux";
else {
pos = strchr(objname,'.');
if (pos) {
/* kernel module */
*pos = '\0';
pos = objname;
while ((pos = strchr(pos, '-')))
*pos++ = '_';
}
}

/* create strings, patches, and dynrelas sections */
kpatch_create_strings_elements(kelf_out);
kpatch_create_patches_sections(kelf_out, lookup, objname);
kpatch_create_intermediate_sections(kelf_out, lookup, objname, pmod_name);
kpatch_create_kpatch_arch_section(kelf_out, objname);
kpatch_create_callbacks_objname_rela(kelf_out, objname);
kpatch_create_patches_sections(kelf_out, lookup, parent_name);
kpatch_create_intermediate_sections(kelf_out, lookup, parent_name, patch_name);
kpatch_create_kpatch_arch_section(kelf_out, parent_name);
kpatch_create_callbacks_objname_rela(kelf_out, parent_name);
kpatch_build_strings_section_data(kelf_out);

kpatch_create_mcount_sections(kelf_out);
Expand Down Expand Up @@ -3182,7 +3172,7 @@ int main(int argc, char *argv[])
kpatch_create_strtab(kelf_out);
kpatch_create_symtab(kelf_out);
kpatch_dump_kelf(kelf_out);
kpatch_write_output_elf(kelf_out, kelf_patched->elf, arguments.args[3]);
kpatch_write_output_elf(kelf_out, kelf_patched->elf, output_obj);

kpatch_elf_free(kelf_patched);
kpatch_elf_teardown(kelf_out);
Expand Down
24 changes: 15 additions & 9 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -773,16 +773,22 @@ for i in $FILES; do
mkdir -p "output/$(dirname "$i")"
cd "$SRCDIR" || die
find_kobj "$i"
if [[ "$KOBJFILE" = vmlinux ]]; then
KOBJFILE="$VMLINUX"
else
KOBJFILE="$TEMPDIR/module/$KOBJFILE"
fi
cd "$TEMPDIR" || die
if [[ -e "orig/$i" ]]; then
# create-diff-object orig.o patched.o kernel-object output.o Module.symvers patch-mod-name
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE" \
"output/$i" "$SRCDIR/Module.symvers" "${MODNAME//-/_}" 2>&1 | logger 1
if [[ "$KOBJFILE" = vmlinux ]]; then
KOBJFILE_NAME=vmlinux
KOBJFILE_PATH="$VMLINUX"
else
KOBJFILE_NAME="${KOBJFILE%.ko}"
KOBJFILE_NAME="${KOBJFILE_NAME/-/_}"
KOBJFILE_PATH="module/$KOBJFILE"
fi
eu-readelf -s "$KOBJFILE_PATH" > "$KOBJFILE.symtab"
# create-diff-object orig.o patched.o parent-name parent-symtab
# Module.symvers patch-mod-name output.o
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE_NAME" \
"KOBJFILE.symtab" "$SRCDIR/Module.symvers" "${MODNAME//-/_}" \
"output/$i" 2>&1 | logger 1
check_pipe_status create-diff-object
# create-diff-object returns 3 if no functional change is found
[[ "$rc" -eq 0 ]] || [[ "$rc" -eq 3 ]] || ERROR="$((ERROR + 1))"
Expand All @@ -808,7 +814,7 @@ fi
echo -n "Patched objects:"
for i in $(echo "${objnames[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')
do
echo -n " $(basename "$i")"
echo -n "$i"
done
echo

Expand Down
143 changes: 69 additions & 74 deletions kpatch-build/lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct object_symbol {
unsigned long value;
unsigned long size;
char *name;
int type, bind, skip;
int type, bind;
};

struct export_symbol {
Expand Down Expand Up @@ -111,8 +111,9 @@ static int locals_match(struct lookup_table *table, int idx,
}
}

if (!found)
if (!found) {
return 0;
}
}

for (child = child_locals; child->name; child++) {
Expand Down Expand Up @@ -174,84 +175,81 @@ static void find_local_syms(struct lookup_table *table, char *hint,
ERROR("find_local_syms for %s: found_none", hint);
}

static void obj_read(struct lookup_table *table, char *path)
/* parses the output of 'eu-readelf -s objfile' */
static void symtab_read(struct lookup_table *table, char *path)
{
Elf *elf;
int fd, i, len;
Elf_Scn *scn;
GElf_Shdr sh;
GElf_Sym sym;
Elf_Data *data;
char *name;
struct object_symbol *mysym;
size_t shstrndx;

if ((fd = open(path, O_RDONLY, 0)) < 0)
ERROR("open");

elf_version(EV_CURRENT);

elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
if (!elf) {
printf("%s\n", elf_errmsg(-1));
ERROR("elf_begin");
}

if (elf_getshdrstrndx(elf, &shstrndx))
ERROR("elf_getshdrstrndx");
FILE *file;
char line[256], type[16], bind[16], name[128];
unsigned long value, size;
int i;

scn = NULL;
while ((scn = elf_nextscn(elf, scn))) {
if (!gelf_getshdr(scn, &sh))
ERROR("gelf_getshdr");
if ((file = fopen(path, "r")) == NULL)
ERROR("can't open %s", path);

name = elf_strptr(elf, shstrndx, sh.sh_name);
if (!name)
ERROR("elf_strptr scn");
/* Skip the header and NULL symbol (first 5 lines) */
//FIXME
for (i = 0; i < 5; i++)
fgets(line, 256, file);

if (!strcmp(name, ".symtab"))
break;
while (fgets(line, 256, file)) {
if (!strstr(line, "SECTION"))
table->obj_nr++;
}

if (!scn)
ERROR(".symtab section not found");

data = elf_getdata(scn, NULL);
if (!data)
ERROR("elf_getdata");

len = sh.sh_size / sh.sh_entsize;

table->obj_syms = malloc(len * sizeof(*table->obj_syms));
table->obj_syms = malloc(table->obj_nr * 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;
memset(table->obj_syms, 0, table->obj_nr * sizeof(*table->obj_syms));

for_each_obj_symbol(i, mysym, table) {
if (!gelf_getsym(data, i, &sym))
ERROR("gelf_getsym");
rewind(file);

/* Skip the header and NULL symbol (first 5 lines) */
//FIXME
for (i = 0; i < 5; i++)
fgets(line, 256, file);

if (sym.st_shndx == SHN_UNDEF) {
mysym->skip = 1;
i = 0;
while (fgets(line, 256, file)) {
if (strstr(line, "SECTION"))
continue;
}

name = elf_strptr(elf, sh.sh_link, sym.st_name);
if(!name)
ERROR("elf_strptr sym");

mysym->value = sym.st_value;
mysym->size = sym.st_size;
mysym->type = GELF_ST_TYPE(sym.st_info);
mysym->bind = GELF_ST_BIND(sym.st_info);
mysym->name = strdup(name);
if (!mysym->name)
ERROR("strdup");
if (sscanf(line, "%*s %lx %lu %s %s %*s %*s %s\n",
&value, &size, type, bind, name) == EOF)
ERROR("fscanf: %s", line);

table->obj_syms[i].value = value;
table->obj_syms[i].size = size;

if (!strcmp(type, "FILE"))
table->obj_syms[i].type = STT_FILE;
else if (!strcmp(type, "FUNC"))
table->obj_syms[i].type = STT_FUNC;
else if (!strcmp(type, "OBJECT"))
table->obj_syms[i].type = STT_OBJECT;
else if (!strcmp(type, "NOTYPE"))
table->obj_syms[i].type = STT_NOTYPE;
else
ERROR("unknown symbol type %s", type);

if (!strcmp(bind, "LOCAL"))
table->obj_syms[i].bind = STB_LOCAL;
else if (!strcmp(bind, "GLOBAL"))
table->obj_syms[i].bind = STB_GLOBAL;
else if (!strcmp(bind, "WEAK"))
table->obj_syms[i].bind = STB_WEAK;
else
ERROR("unknown symbol bind %s", bind);

table->obj_syms[i].name = strdup(name);
if (!table->obj_syms[i].name)
ERROR("name %s strdup", name);
if (strlen(name) == 0)
ERROR("name strlen 0: %s", line);

i++;
}

close(fd);
elf_end(elf);
fclose(file);
}

/* Strip the path and replace '-' with '_' */
Expand Down Expand Up @@ -279,8 +277,8 @@ static void symvers_read(struct lookup_table *table, char *path)
char name[256], mod[256], export[256];
char *objname, *symname;

if ((file = fopen(path, "r")) < 0)
ERROR("fopen");
if ((file = fopen(path, "r")) == NULL)
ERROR("can't open %s", path);

while (fscanf(file, "%x %s %s %s\n",
&crc, name, mod, export) != EOF)
Expand Down Expand Up @@ -314,7 +312,7 @@ static void symvers_read(struct lookup_table *table, char *path)
fclose(file);
}

struct lookup_table *lookup_open(char *obj_path, char *symvers_path,
struct lookup_table *lookup_open(char *symtab_path, char *symvers_path,
char *hint, struct sym_compare_type *locals)
{
struct lookup_table *table;
Expand All @@ -324,7 +322,7 @@ struct lookup_table *lookup_open(char *obj_path, char *symvers_path,
ERROR("malloc table");
memset(table, 0, sizeof(*table));

obj_read(table, obj_path);
symtab_read(table, symtab_path);
symvers_read(table, symvers_path);
find_local_syms(table, hint, locals);

Expand All @@ -350,9 +348,6 @@ int lookup_local_symbol(struct lookup_table *table, char *name,

memset(result, 0, sizeof(*result));
for_each_obj_symbol(i, sym, table) {
if (sym->skip)
continue;

if (sym->bind == STB_LOCAL && !strcmp(sym->name, name))
pos++;

Expand Down Expand Up @@ -390,7 +385,7 @@ int lookup_global_symbol(struct lookup_table *table, char *name,

memset(result, 0, sizeof(*result));
for_each_obj_symbol(i, sym, table) {
if (!sym->skip && (sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) &&
if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) &&
!strcmp(sym->name, name)) {
result->value = sym->value;
result->size = sym->size;
Expand Down
2 changes: 1 addition & 1 deletion kpatch-build/lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct sym_compare_type {
int type;
};

struct lookup_table *lookup_open(char *obj_path, char *symvers_path,
struct lookup_table *lookup_open(char *symtab_path, char *symvers_path,
char *hint, struct sym_compare_type *locals);
void lookup_close(struct lookup_table *table);
int lookup_local_symbol(struct lookup_table *table, char *name,
Expand Down
8 changes: 4 additions & 4 deletions test/unit/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ clean:
@echo "BUILD $(TNAME)"
$(call check_all,$(TNAME).$(EXT_ORIG))
$(call check_all,$(TNAME).$(EXT_PATCHED))
$(CDO_ENV) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_PATCHED) \
$(TNAME).$(EXT_ORIG) $@ /dev/null test_$(TNAME) $(MUTE_PASS)
$(CDO_ENV) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_PATCHED) vmlinux \
vmlinux.symtab Module.symvers test_$(TNAME) $@ $(MUTE_PASS)

%.$(EXT_OUTPUT): %.$(EXT_ORIG) %.$(EXT_FAIL) $(CDO)
@echo "BUILD $(TNAME)-FAIL"
$(call check_all,$(TNAME).$(EXT_ORIG))
$(call check_all,$(TNAME).$(EXT_FAIL))
! $(CDO_ENV) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_FAIL) \
$(TNAME).$(EXT_ORIG) $@ /dev/null test_$(TNAME) $(MUTE_FAIL)
! $(CDO_ENV) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_FAIL) vmlinux \
vmlinux.symtab Module.symvers test_$(TNAME) $@ $(MUTE_FAIL)
# Expecting to fail, thus create output file manually so we won't rerun the
# test without clean
@touch $@

0 comments on commit 8a67f2e

Please sign in to comment.