mirror of
https://github.com/dynup/kpatch
synced 2025-02-18 18:56:58 +00:00
refactor and fix multiple issues
- Fixup debug messages - Remove dead code - No more DEPENDENCY state - Reachability test is now the "Inclusion tree" for determining which syms/sections will be included in the output - 'reachable' field is now and 'include' and is the sole consideration in including sections/symbols (no more complex conditional checks) - Order LOCAL before GLOBAL in the symbol table. Apparently, after a FILE sym, all LOCAL symbols should precede GLOBAL syms or readelf shows <corrupt> - Handle __ksymtab_strings section and __ksymtab_* syms Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
parent
5145520695
commit
f6efd53541
@ -15,19 +15,6 @@
|
||||
* various rules are applied to determine any object local sections that
|
||||
* are dependencies of the changed section and also need to be included in
|
||||
* the output object.
|
||||
*
|
||||
* After all the sections for the output object have been selected, a
|
||||
* reachability test is performed to ensure that every included section
|
||||
* is reachable from a changed function symbol. If there is a section that
|
||||
* is not reachable from a changed function, this means that the source-level
|
||||
* change can not be captured by employing ftrace and therefore can not be
|
||||
* dynamically patched by kpatch. Changes to static data structures are an
|
||||
* example.
|
||||
*
|
||||
* If the reachability test succeeds
|
||||
* - Changed text sections are copied into the output object
|
||||
* - Changed rela sections have there symbol indexes fixed up
|
||||
* - shstrtab, strtab, and symtab are all rebuilt from scratch
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -61,8 +48,7 @@ struct rela;
|
||||
enum status {
|
||||
NEW,
|
||||
CHANGED,
|
||||
SAME,
|
||||
DEPENDENCY
|
||||
SAME
|
||||
};
|
||||
|
||||
struct table {
|
||||
@ -77,7 +63,7 @@ struct section {
|
||||
char *name;
|
||||
int index;
|
||||
enum status status;
|
||||
int reachable;
|
||||
int include;
|
||||
union {
|
||||
struct { /* if (is_rela_section()) */
|
||||
struct section *base;
|
||||
@ -85,7 +71,7 @@ struct section {
|
||||
};
|
||||
struct { /* else */
|
||||
struct section *rela;
|
||||
struct symbol *sym;
|
||||
struct symbol *secsym, *sym;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -98,7 +84,7 @@ struct symbol {
|
||||
int index;
|
||||
unsigned char bind, type;
|
||||
enum status status;
|
||||
int reachable;
|
||||
int include;
|
||||
};
|
||||
|
||||
struct rela {
|
||||
@ -141,8 +127,6 @@ char *status_str(enum status status)
|
||||
return "CHANGED";
|
||||
case SAME:
|
||||
return "SAME";
|
||||
case DEPENDENCY:
|
||||
return "DEPENDENCY";
|
||||
default:
|
||||
ERROR("status_str");
|
||||
}
|
||||
@ -357,31 +341,30 @@ void kpatch_create_symbol_table(struct kpatch_elf *kelf)
|
||||
sym->type = GELF_ST_TYPE(sym->sym.st_info);
|
||||
sym->bind = GELF_ST_BIND(sym->sym.st_info);
|
||||
|
||||
if (sym->sym.st_shndx != SHN_UNDEF &&
|
||||
sym->sym.st_shndx != SHN_ABS) {
|
||||
if (sym->sym.st_shndx > SHN_UNDEF &&
|
||||
sym->sym.st_shndx < SHN_LORESERVE) {
|
||||
sym->sec = find_section_by_index(&kelf->sections,
|
||||
sym->sym.st_shndx);
|
||||
if (!sym->sec)
|
||||
ERROR("couldn't find section for symbol %s\n",
|
||||
sym->name);
|
||||
|
||||
/* create reverse link from local sec to local sym */
|
||||
if (GELF_ST_TYPE(sym->sym.st_info) != STT_NOTYPE) {
|
||||
if (sym->sym.st_value)
|
||||
ERROR("local symbol starts at section offset %d, expected 0",
|
||||
sym->sym.st_value);
|
||||
if ((sym->type == STT_FUNC ||
|
||||
sym->type == STT_OBJECT) &&
|
||||
sym->sym.st_value == 0 &&
|
||||
strcmp(sym->sec->name, "__ksymtab_strings")) {
|
||||
sym->sec->sym = sym;
|
||||
}
|
||||
|
||||
if (sym->type == STT_SECTION)
|
||||
} else if (sym->type == STT_SECTION) {
|
||||
sym->sec->secsym = sym;
|
||||
/* use the section name as the symbol name */
|
||||
sym->name = sym->sec->name;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
#if DEBUG
|
||||
printf("sym %02d, type %d, bind %d, ndx %02d, name %s",
|
||||
sym->index, sym->type, sym->bind, sym->sym.st_shndx,
|
||||
sym->name);
|
||||
if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT))
|
||||
if (sym->sec)
|
||||
printf(" -> %s", sym->sec->name);
|
||||
printf("\n");
|
||||
#endif
|
||||
@ -425,7 +408,7 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
|
||||
return kelf;
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_section(struct section *sec)
|
||||
void kpatch_compare_correlated_nonrela_section(struct section *sec)
|
||||
{
|
||||
struct section *sec1 = sec, *sec2 = sec->twin;
|
||||
enum status status;
|
||||
@ -446,31 +429,29 @@ void kpatch_compare_correlated_section(struct section *sec)
|
||||
sec1->status = CHANGED;
|
||||
else
|
||||
sec1->status = SAME;
|
||||
|
||||
if (!is_rela_section(sec1)) {
|
||||
/* Sync section symbol status */
|
||||
if (sec1->sym)
|
||||
sec1->sym->status = sec1->status;
|
||||
/* Sync rela section status */
|
||||
if (sec1->rela)
|
||||
sec1->rela->status = sec1->status;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("section %s is %s\n", sec1->name, status_str(sec1->status));
|
||||
#endif
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_sections(struct table *table)
|
||||
void kpatch_compare_correlated_nonrela_sections(struct table *table)
|
||||
{
|
||||
struct section *sec;
|
||||
int i;
|
||||
|
||||
for_each_section(i, sec, table)
|
||||
for_each_section(i, sec, table) {
|
||||
if (is_rela_section(sec))
|
||||
continue;
|
||||
if (sec->twin)
|
||||
kpatch_compare_correlated_section(sec);
|
||||
kpatch_compare_correlated_nonrela_section(sec);
|
||||
else
|
||||
sec->status = NEW;
|
||||
|
||||
/* sync any rela section and associated symbols */
|
||||
if (sec->sym)
|
||||
sec->sym->status = sec->status;
|
||||
if (sec->secsym)
|
||||
sec->secsym->status = sec->status;
|
||||
if (sec->rela)
|
||||
sec->rela->status = sec->status;
|
||||
}
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_symbol(struct symbol *sym)
|
||||
@ -491,17 +472,6 @@ void kpatch_compare_correlated_symbol(struct symbol *sym)
|
||||
if (sym1->sym.st_shndx == SHN_UNDEF ||
|
||||
sym1->sym.st_shndx == SHN_ABS)
|
||||
sym1->status = SAME;
|
||||
else if (sym1->sec)
|
||||
sym1->status = sym1->sec->status;
|
||||
else if (sym1->status != CHANGED)
|
||||
sym1->status = SAME;
|
||||
|
||||
/* special case for type FILE */
|
||||
if (sym1->type == STT_FILE)
|
||||
sym1->status = DEPENDENCY;
|
||||
#if DEBUG
|
||||
printf("symbol %s is %s\n", sym->name, status_str(sym->status));
|
||||
#endif
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_symbols(struct table *table)
|
||||
@ -516,34 +486,12 @@ void kpatch_compare_correlated_symbols(struct table *table)
|
||||
kpatch_compare_correlated_symbol(sym);
|
||||
else
|
||||
sym->status = NEW;
|
||||
#if DEBUG
|
||||
printf("symbol %s is %s\n", sym->name, status_str(sym->status));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_rela(struct rela *rela)
|
||||
{
|
||||
struct rela *rela1 = rela, *rela2 = rela->twin;
|
||||
|
||||
/*
|
||||
* rela entry status is either SAME or NEW. All correlated entries
|
||||
* are SAME because the criteria used to correlate them is sufficient
|
||||
* to consider them unchanged.
|
||||
*/
|
||||
rela->status = SAME;
|
||||
}
|
||||
|
||||
void kpatch_compare_correlated_relas(struct table *table)
|
||||
{
|
||||
struct rela *rela;
|
||||
int i;
|
||||
|
||||
for_each_rela(i, rela, table)
|
||||
if (rela->twin)
|
||||
kpatch_compare_correlated_rela(rela);
|
||||
else
|
||||
rela->status = NEW;
|
||||
}
|
||||
|
||||
|
||||
void kpatch_correlate_sections(struct table *table1, struct table *table2)
|
||||
{
|
||||
struct section *sec1, *sec2;
|
||||
@ -556,6 +504,8 @@ void kpatch_correlate_sections(struct table *table1, struct table *table2)
|
||||
continue;
|
||||
sec1->twin = sec2;
|
||||
sec2->twin = sec1;
|
||||
/* set initial status, might change */
|
||||
sec1->status = sec2->status = SAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -575,12 +525,34 @@ void kpatch_correlate_symbols(struct table *table1, struct table *table2)
|
||||
if (!strcmp(sym1->name, sym2->name)) {
|
||||
sym1->twin = sym2;
|
||||
sym2->twin = sym1;
|
||||
/* set initial status, might change */
|
||||
sym1->status = sym2->status = SAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rela_equal(struct rela *rela1, struct rela *rela2)
|
||||
{
|
||||
if (rela1->type != rela2->type ||
|
||||
rela1->offset != rela2->offset)
|
||||
return 0;
|
||||
|
||||
if (rela1->string) {
|
||||
if (rela2->string &&
|
||||
!strcmp(rela1->string, rela2->string))
|
||||
return 1;
|
||||
} else {
|
||||
if (strcmp(rela1->sym->name, rela2->sym->name))
|
||||
return 0;
|
||||
if (rela1->addend == rela2->addend)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kpatch_correlate_relas(struct section *sec)
|
||||
{
|
||||
struct rela *rela1, *rela2;
|
||||
@ -588,14 +560,10 @@ void kpatch_correlate_relas(struct section *sec)
|
||||
|
||||
for_each_rela(i, rela1, &sec->relas) {
|
||||
for_each_rela(j, rela2, &sec->twin->relas) {
|
||||
if (rela1->type == rela2->type &&
|
||||
(rela1->addend == rela2->addend ||
|
||||
(rela1->string && rela2->string &&
|
||||
!strcmp(rela1->string, rela2->string))) &&
|
||||
!strcmp(rela1->sym->name, rela2->sym->name) &&
|
||||
rela1->offset == rela2->offset) {
|
||||
if (rela_equal(rela1, rela2)) {
|
||||
rela1->twin = rela2;
|
||||
rela2->twin = rela1;
|
||||
rela1->status = rela2->status = SAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -623,9 +591,6 @@ void kpatch_compare_elf_headers(Elf *elf1, Elf *elf2)
|
||||
eh1.e_phentsize != eh2.e_phentsize ||
|
||||
eh1.e_shentsize != eh2.e_shentsize)
|
||||
DIFF_FATAL("ELF headers differ");
|
||||
#if DEBUG
|
||||
printf("kpatch_compare_elf_headers passed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void kpatch_check_program_headers(Elf *elf)
|
||||
@ -637,12 +602,9 @@ void kpatch_check_program_headers(Elf *elf)
|
||||
|
||||
if (ph_nr != 0)
|
||||
DIFF_FATAL("ELF contains program header");
|
||||
#if DEBUG
|
||||
printf("kpatch_check_program_headers passed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void kpatch_verify_rela_section_status(struct section *sec)
|
||||
void kpatch_set_rela_section_status(struct section *sec)
|
||||
{
|
||||
struct rela *rela;
|
||||
int i;
|
||||
@ -650,10 +612,16 @@ void kpatch_verify_rela_section_status(struct section *sec)
|
||||
for_each_rela(i, rela, &sec->relas)
|
||||
if (rela->status == NEW) {
|
||||
/*
|
||||
* This rela section really is different. Make
|
||||
* sure the base section comes along too.
|
||||
* This rela section is different. Make
|
||||
* sure the text section and any associated
|
||||
* symbols come along too.
|
||||
*/
|
||||
sec->status = CHANGED;
|
||||
sec->base->status = CHANGED;
|
||||
if (sec->base->sym)
|
||||
sec->base->sym->status = CHANGED;
|
||||
if (sec->base->secsym)
|
||||
sec->base->secsym->status = CHANGED;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -685,48 +653,33 @@ void kpatch_compare_correlated_elements(struct kpatch_elf *kelf)
|
||||
int i, j;
|
||||
|
||||
/* tables are already correlated at this point */
|
||||
kpatch_compare_correlated_sections(&kelf->sections);
|
||||
kpatch_compare_correlated_nonrela_sections(&kelf->sections);
|
||||
kpatch_compare_correlated_symbols(&kelf->symbols);
|
||||
|
||||
for_each_section(i, sec, &kelf->sections)
|
||||
if (is_rela_section(sec))
|
||||
kpatch_compare_correlated_relas(&sec->relas);
|
||||
if (is_rela_section(sec) && sec->status == SAME)
|
||||
kpatch_set_rela_section_status(sec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for false positives on changed rela sections
|
||||
* caused by symbol renumeration.
|
||||
*/
|
||||
for_each_section(i, sec, &kelf->sections)
|
||||
if (is_rela_section(sec) && sec->status == CHANGED)
|
||||
kpatch_verify_rela_section_status(sec);
|
||||
void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct section *sec;
|
||||
struct rela *rela;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* Find unchanged sections/symbols that are dependencies of
|
||||
* changed sections
|
||||
*/
|
||||
for_each_section(i, sec, &kelf->sections) {
|
||||
if (!is_rela_section(sec) || sec->status != CHANGED)
|
||||
if (!is_rela_section(sec))
|
||||
continue;
|
||||
|
||||
for_each_rela(j, rela, &sec->relas) {
|
||||
/*
|
||||
* Nuts, I know. Determine if the section of the symbol referenced by
|
||||
* the rela entry is associated with a symbol of type STT_SECTION. This
|
||||
* is to avoid including unchanged local functions or objects that are
|
||||
* called by a changed function.
|
||||
*/
|
||||
if (rela->sym->sym.st_shndx != SHN_UNDEF &&
|
||||
rela->sym->sym.st_shndx != SHN_ABS &&
|
||||
rela->sym->status != CHANGED &&
|
||||
rela->sym->sec->sym->type == STT_SECTION) {
|
||||
rela->sym->status = DEPENDENCY;
|
||||
rela->sym->sec->status = DEPENDENCY;
|
||||
}
|
||||
/*
|
||||
* All symbols referenced by entries in a changed rela section are
|
||||
* dependencies.
|
||||
*/
|
||||
if (rela->sym->status == SAME)
|
||||
rela->sym->status = DEPENDENCY;
|
||||
if (rela->sym->type != STT_SECTION ||
|
||||
!rela->sym->sec || !rela->sym->sec->sym)
|
||||
continue;
|
||||
#if DEBUG
|
||||
printf("replacing %s with %s\n",
|
||||
rela->sym->name, rela->sym->sec->sym->name);
|
||||
#endif
|
||||
rela->sym = rela->sym->sec->sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -756,6 +709,8 @@ void kpatch_dump_kelf(struct kpatch_elf *kelf)
|
||||
} else {
|
||||
if (sec->sym)
|
||||
printf(", sym-> %s", sec->sym->name);
|
||||
if (sec->secsym)
|
||||
printf(", secsym-> %s", sec->secsym->name);
|
||||
if (sec->rela)
|
||||
printf(", rela-> %s", sec->rela->name);
|
||||
}
|
||||
@ -766,8 +721,8 @@ void kpatch_dump_kelf(struct kpatch_elf *kelf)
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (i == 0) /* ugh */
|
||||
continue;
|
||||
printf("sym %02d, type %d=%d, bind %d=%d, ndx %02d, name %s (%s)",
|
||||
sym->index, sym->type, GELF_ST_TYPE(sym->sym.st_info), sym->bind, GELF_ST_BIND(sym->sym.st_info), sym->sym.st_shndx,
|
||||
printf("sym %02d, type %d, bind %d, ndx %02d, name %s (%s)",
|
||||
sym->index, sym->type, sym->bind, sym->sym.st_shndx,
|
||||
sym->name, status_str(sym->status));
|
||||
if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT))
|
||||
printf(" -> %s", sym->sec->name);
|
||||
@ -795,62 +750,70 @@ int kpatch_find_changed_functions(struct kpatch_elf *kelf)
|
||||
return changed;
|
||||
}
|
||||
|
||||
void kpatch_reachable_symbol(struct symbol *sym)
|
||||
#if DEBUG
|
||||
#define inc_printf(fmt, ...) \
|
||||
printf("%*s" fmt, recurselevel, "", ##__VA_ARGS__);
|
||||
#else
|
||||
#define inc_printf(fmt, ...);
|
||||
#endif
|
||||
|
||||
void kpatch_include_symbol(struct symbol *sym, int recurselevel)
|
||||
{
|
||||
struct rela *rela;
|
||||
struct section *sec;
|
||||
int i;
|
||||
|
||||
sym->reachable = 1;
|
||||
#if DEBUG
|
||||
printf("symbol %s is reachable\n", sym->name);
|
||||
#endif
|
||||
if (!sym->sec)
|
||||
return;
|
||||
inc_printf("start include_symbol(%s)\n", sym->name);
|
||||
sym->include = 1;
|
||||
inc_printf("symbol %s is included\n", sym->name);
|
||||
/*
|
||||
* Check if sym is a non-local symbol (sym->sec is NULL) or
|
||||
* if an unchanged local symbol. This a base case for the
|
||||
* inclusion recursion.
|
||||
*/
|
||||
if (!sym->sec || (sym->type != STT_SECTION && sym->status == SAME))
|
||||
goto out;
|
||||
sec = sym->sec;
|
||||
sec->reachable = 1;
|
||||
#if DEBUG
|
||||
printf("section %s is reachable\n", sec->name);
|
||||
#endif
|
||||
if (sec->sym)
|
||||
sec->sym->reachable = 1;
|
||||
#if DEBUG
|
||||
printf("symbol %s is reachable\n", sym->sec->name);
|
||||
#endif
|
||||
if (!sec->rela)
|
||||
return;
|
||||
sec->rela->reachable = 1;
|
||||
#if DEBUG
|
||||
printf("section %s is reachable\n", sec->rela->name);
|
||||
#endif
|
||||
for_each_rela(i, rela, &sec->rela->relas) {
|
||||
if (rela->sym->status == SAME ||
|
||||
rela->sym->reachable)
|
||||
continue;
|
||||
kpatch_reachable_symbol(rela->sym);
|
||||
sec->include = 1;
|
||||
inc_printf("section %s is included\n", sec->name);
|
||||
if (sec->secsym == sym)
|
||||
goto out;
|
||||
if (sec->secsym) {
|
||||
sec->secsym->include = 1;
|
||||
inc_printf("section symbol %s is included\n", sec->secsym->name);
|
||||
}
|
||||
if (!sec->rela)
|
||||
goto out;
|
||||
sec->rela->include = 1;
|
||||
inc_printf("section %s is included\n", sec->rela->name);
|
||||
for_each_rela(i, rela, &sec->rela->relas) {
|
||||
if (rela->sym->include)
|
||||
continue;
|
||||
kpatch_include_symbol(rela->sym, recurselevel+1);
|
||||
}
|
||||
out:
|
||||
inc_printf("end include_symbol(%s)\n", sym->name);
|
||||
return;
|
||||
}
|
||||
|
||||
void kpatch_validate_reachability(struct kpatch_elf *kelf)
|
||||
void kpatch_include_changed_functions(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct section *sec;
|
||||
int i;
|
||||
|
||||
for_each_symbol(i, sym, &kelf->symbols)
|
||||
if (!sym->reachable && sym->status != SAME &&
|
||||
sym->type == STT_FUNC)
|
||||
kpatch_reachable_symbol(sym);
|
||||
#if DEBUG
|
||||
printf("\n=== Inclusion Tree ===\n");
|
||||
#endif
|
||||
|
||||
for_each_section(i, sec, &kelf->sections)
|
||||
if (sec->status != SAME && !sec->reachable &&
|
||||
strcmp(sec->name, ".shstrtab") &&
|
||||
strcmp(sec->name, ".symtab") &&
|
||||
strcmp(sec->name, ".strtab"))
|
||||
DIFF_FATAL("unreachable changed section %s",
|
||||
sec->name);
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (sym->status == CHANGED &&
|
||||
sym->type == STT_FUNC &&
|
||||
!sym->include)
|
||||
kpatch_include_symbol(sym, 0);
|
||||
|
||||
printf("All changed sections are reachable\n");
|
||||
if (sym->type == STT_FILE)
|
||||
sym->include = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout)
|
||||
@ -863,13 +826,12 @@ void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout
|
||||
/* count output sections */
|
||||
for_each_section(i, sec, &kelf->sections) {
|
||||
/* include these sections even if they haven't changed */
|
||||
if (sec->status == SAME &&
|
||||
(!strcmp(sec->name, ".shstrtab") ||
|
||||
if (!strcmp(sec->name, ".shstrtab") ||
|
||||
!strcmp(sec->name, ".strtab") ||
|
||||
!strcmp(sec->name, ".symtab")))
|
||||
sec->status = DEPENDENCY;
|
||||
!strcmp(sec->name, ".symtab"))
|
||||
sec->include = 1;
|
||||
|
||||
if (sec->status != SAME)
|
||||
if (sec->include)
|
||||
sections_nr++;
|
||||
}
|
||||
|
||||
@ -879,7 +841,7 @@ void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout
|
||||
|
||||
/* count output symbols */
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (i == 0 || sym->status != SAME)
|
||||
if (i == 0 || sym->include)
|
||||
symbols_nr++;
|
||||
}
|
||||
#if DEBUG
|
||||
@ -899,7 +861,7 @@ void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout
|
||||
/* copy to output kelf sections, link to kelf, and reindex */
|
||||
index = 0;
|
||||
for_each_section(i, sec, &kelf->sections) {
|
||||
if (sec->status == SAME)
|
||||
if (!sec->include)
|
||||
continue;
|
||||
|
||||
secout = &((struct section *)(out->sections.data))[index];
|
||||
@ -909,10 +871,31 @@ void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout
|
||||
sec->twino = secout;
|
||||
}
|
||||
|
||||
/* copy to output kelf symbols, link to kelf, and reindex */
|
||||
/*
|
||||
* Search symbol table for local functions whose sections are
|
||||
* not included, and modify them to be non-local.
|
||||
*/
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
if ((sym->type == STT_OBJECT ||
|
||||
sym->type == STT_FUNC) &&
|
||||
!sym->sec->include) {
|
||||
sym->type = STT_NOTYPE;
|
||||
sym->bind = STB_GLOBAL;
|
||||
sym->sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
|
||||
sym->sym.st_shndx = SHN_UNDEF;
|
||||
sym->sym.st_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy local syms to output kelf symbols, link to kelf, and reindex */
|
||||
index = 0;
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (i != 0 && sym->status == SAME)
|
||||
if (i != 0 && !sym->include)
|
||||
continue;
|
||||
|
||||
if (sym->bind == STB_GLOBAL)
|
||||
continue;
|
||||
|
||||
symout = &((struct symbol *)(out->symbols.data))[index];
|
||||
@ -923,28 +906,30 @@ void kpatch_generate_output(struct kpatch_elf *kelf, struct kpatch_elf **kelfout
|
||||
index++;
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
if (sym->sec && sym->sec->twino)
|
||||
symout->sym.st_shndx = SHN_UNDEF;
|
||||
else if (sym->sec && sym->sec->twino)
|
||||
symout->sym.st_shndx = sym->sec->twino->index;
|
||||
}
|
||||
|
||||
for_each_symbol(i, sym, &out->symbols) {
|
||||
if (i == 0)
|
||||
/* copy global syms to output kelf symbols, link to kelf, and reindex */
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (i != 0 && !sym->include)
|
||||
continue;
|
||||
/*
|
||||
* Search symbol table for local functions whose sections are
|
||||
* not included, and modify them to be non-local.
|
||||
*/
|
||||
if ((sym->type == STT_OBJECT ||
|
||||
sym->type == STT_FUNC) &&
|
||||
sym->status == DEPENDENCY) {
|
||||
sym->type = STT_NOTYPE;
|
||||
sym->bind = STB_GLOBAL;
|
||||
sym->sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
|
||||
sym->sym.st_shndx = SHN_UNDEF;
|
||||
sym->sym.st_size = 0;
|
||||
}
|
||||
|
||||
if (sym->bind == STB_LOCAL)
|
||||
continue;
|
||||
|
||||
symout = &((struct symbol *)(out->symbols.data))[index];
|
||||
*symout = *sym;
|
||||
symout->index = index;
|
||||
symout->twino = sym;
|
||||
sym->twino = symout;
|
||||
index++;
|
||||
|
||||
if (i == 0)
|
||||
symout->sym.st_shndx = SHN_UNDEF;
|
||||
else if (sym->sec && sym->sec->twino)
|
||||
symout->sym.st_shndx = sym->sec->twino->index;
|
||||
}
|
||||
|
||||
*kelfout = out;
|
||||
@ -1154,42 +1139,6 @@ void kpatch_create_symtab(struct kpatch_elf *kelf)
|
||||
find_section_by_name(&kelf->sections, ".shstrtab")->index;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void kpatch_link_symtab_vmlinux(struct kpatch_elf *kelf, struct kpatch_elf *vmkelf)
|
||||
{
|
||||
struct symbol *sym, *vmsym;
|
||||
#define BUFSIZE 255
|
||||
char kstrbuf[BUFSIZE];
|
||||
int i;
|
||||
|
||||
for_each_symbol(i, sym, &kelf->symbols) {
|
||||
if (GELF_ST_BIND(sym->sym.st_info) != STB_GLOBAL)
|
||||
continue;
|
||||
|
||||
/* figure out if symbol is exported by the kernel */
|
||||
snprintf(kstrbuf, BUFSIZE, "%s%s", "__ksymtab_", sym->name);
|
||||
printf("looking for %s\n",kstrbuf);
|
||||
vmsym = find_symbol_by_name(&vmkelf->symbols, kstrbuf);
|
||||
if (vmsym)
|
||||
continue;
|
||||
|
||||
/* it is not, lookup address in vmlinux */
|
||||
vmsym = find_symbol_by_name(&vmkelf->symbols, sym->name);
|
||||
if (!vmsym)
|
||||
ERROR("symbol not found in vmlinux");
|
||||
|
||||
sym->sym.st_value = vmsym->sym.st_value;
|
||||
sym->sym.st_info = GELF_ST_INFO(STB_LOCAL,
|
||||
GELF_ST_TYPE(vmsym->sym.st_info));
|
||||
sym->sym.st_shndx = SHN_ABS;
|
||||
#if DEBUG
|
||||
printf("symbol %s found with address %016lx\n",
|
||||
sym->name, sym->sym.st_value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile)
|
||||
{
|
||||
int fd, i, index = 0;
|
||||
@ -1280,19 +1229,21 @@ int main(int argc, char *argv[])
|
||||
* section, symbol, and rela lists of kelf_patched.
|
||||
*/
|
||||
kpatch_compare_correlated_elements(kelf_patched);
|
||||
|
||||
/*
|
||||
* Mangle the relas a little. The compiler will sometimes
|
||||
* use section symbols to reference local objects and functions
|
||||
* rather than the object or function symbols themselves.
|
||||
* We substitute the object/function symbols for the section
|
||||
* symbol in this case so that the existing object/function
|
||||
* in vmlinux can be linked to.
|
||||
*/
|
||||
kpatch_replace_sections_syms(kelf_patched);
|
||||
|
||||
kpatch_include_changed_functions(kelf_patched);
|
||||
#if DEBUG
|
||||
kpatch_dump_kelf(kelf_patched);
|
||||
#endif
|
||||
/*
|
||||
* At this point, the kelf is fully linked and statuses on
|
||||
* all sections and symbols have been set.
|
||||
*/
|
||||
|
||||
/* Go through changes and make sure they are hot-patchable */
|
||||
kpatch_validate_reachability(kelf_patched);
|
||||
|
||||
if (!kpatch_find_changed_functions(kelf_patched))
|
||||
return 0;
|
||||
|
||||
/* Generate the output elf */
|
||||
kpatch_generate_output(kelf_patched, &kelf_out);
|
||||
|
Loading…
Reference in New Issue
Block a user