From d170861502e78c396f0283f66f444a496efd11de Mon Sep 17 00:00:00 2001 From: Zhipeng Xie Date: Wed, 26 Feb 2020 07:36:59 -0500 Subject: [PATCH 11/23] support c plus kernel module support GNU_UNIQUE type symbols. support .group section corelation. ignore compile warning for third party modules. Signed-off-by: Zhipeng Xie --- kpatch-build/create-diff-object.c | 60 +++++++++++++++++++++---------- kpatch-build/kpatch-build | 2 +- kpatch-build/kpatch-elf.c | 8 ++++- kpatch-build/kpatch-gcc | 3 +- kpatch-build/lookup.c | 5 ++- 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index f37d404..d139f45 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -460,7 +460,7 @@ static void kpatch_compare_correlated_nonrela_section(struct section *sec) { struct section *sec1 = sec, *sec2 = sec->twin; - if (sec1->sh.sh_type != SHT_NOBITS && + if (sec1->sh.sh_type != SHT_NOBITS && sec1->sh.sh_type != SHT_GROUP && memcmp(sec1->data->d_buf, sec2->data->d_buf, sec1->data->d_size)) sec->status = CHANGED; else @@ -476,7 +476,7 @@ static void kpatch_compare_correlated_section(struct section *sec) sec1->sh.sh_flags != sec2->sh.sh_flags || sec1->sh.sh_entsize != sec2->sh.sh_entsize || (sec1->sh.sh_addralign != sec2->sh.sh_addralign && - !is_text_section(sec1))) + !is_text_section(sec1) && strcmp(sec1->name, ".rodata"))) DIFF_FATAL("%s section header details differ from %s", sec1->name, sec2->name); /* Short circuit for mcount sections, we rebuild regardless */ @@ -913,6 +913,34 @@ static void kpatch_correlate_section(struct section *sec1, struct section *sec2) kpatch_correlate_symbol(sec1->sym, sec2->sym); } +static int kpatch_correlate_group_section(struct list_head *seclist1, + struct list_head *seclist2, struct section *sec1, struct section *sec2) +{ + unsigned int *data1, *end1, *data2; + struct section *isec1, *isec2; + + if (sec1->data->d_size != sec2->data->d_size) + return 1; + data1 = sec1->data->d_buf; + data2 = sec2->data->d_buf; + end1 = sec1->data->d_buf + sec1->data->d_size; + data1++; + data2++; + while (data1 < end1) { + isec1 = find_section_by_index(seclist1, *data1); + if (!isec1) + ERROR("group section not found"); + isec2 = find_section_by_index(seclist2, *data2); + if (!isec2) + ERROR("group section not found"); + if (strcmp(isec1->name, isec2->name)) + return 1; + data1++; + data2++; + } + return 0; +} + static void kpatch_correlate_sections(struct list_head *seclist1, struct list_head *seclist2) { struct section *sec1, *sec2; @@ -931,14 +959,19 @@ static void kpatch_correlate_sections(struct list_head *seclist1, struct list_he continue; /* - * Group sections must match exactly to be correlated. - * Changed group sections are currently not supported. + * Group section的格式为: + * flag + * section index + * section index + * ... + * + * 当C++代码发生修改时,section index可能会发生变化 + * 这时候我们就比对一下section index所对应的section的 + * name,如果相同,我们就认为这两个group是SAME */ + if (sec1->sh.sh_type == SHT_GROUP) { - if (sec1->data->d_size != sec2->data->d_size) - continue; - if (memcmp(sec1->data->d_buf, sec2->data->d_buf, - sec1->data->d_size)) + if (kpatch_correlate_group_section(seclist1, seclist2, sec1, sec2)) continue; } @@ -1521,17 +1554,6 @@ static void kpatch_verify_patchability(struct kpatch_elf *kelf) errs++; } - if (sec->status != SAME && sec->grouped) { - log_normal("changed section %s is part of a section group\n", - sec->name); - errs++; - } - - if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { - log_normal("new/changed group sections are not supported\n"); - errs++; - } - /* * ensure we aren't including .data.* or .bss.* * (.data.unlikely and .data.once is ok b/c it only has __warned vars) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 4e38412..4896136 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1157,7 +1157,7 @@ fi # column containing lines unique to first file. UNDEFINED=$(comm -23 <(sort -u "${TEMPDIR}"/undefined_references) \ <(sort -u "${TEMPDIR}"/new_symbols) | tr '\n' ' ') -[[ -n "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" +[[ -z "$USERMODBUILDDIR" ]] && [[ -n "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" cp -f "$TEMPDIR/patch/$MODNAME.ko" "$BASE" || die diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index c6af59e..f76a9eb 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -710,8 +710,14 @@ void kpatch_reindex_elements(struct kpatch_elf *kelf) unsigned int index; index = 1; /* elf write function handles NULL section 0 */ - list_for_each_entry(sec, &kelf->sections, list) + list_for_each_entry(sec, &kelf->sections, list) { sec->index = index++; + /* + * since we exclude .group section, we clear SHF_GROUP + * for every section in case of link error. + */ + sec->sh.sh_flags &= (~SHF_GROUP); + } index = 0; list_for_each_entry(sym, &kelf->symbols, list) { diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc index 35d7c1c..6ad6ebc 100755 --- a/kpatch-build/kpatch-gcc +++ b/kpatch-build/kpatch-gcc @@ -13,7 +13,8 @@ fi declare -a args=("$@") -if [[ "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}gcc" ]] ; then +if [[ "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}gcc" || + "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}g++" ]] ; then while [ "$#" -gt 0 ]; do if [ "$1" = "-o" ]; then obj="$2" diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c index 8387e8b..4e2fcb9 100644 --- a/kpatch-build/lookup.c +++ b/kpatch-build/lookup.c @@ -255,6 +255,8 @@ static void symtab_read(struct lookup_table *table, char *path) table->obj_syms[i].bind = STB_GLOBAL; } else if (!strcmp(bind, "WEAK")) { table->obj_syms[i].bind = STB_WEAK; + } else if (!strcmp(bind, "UNIQUE")) { + table->obj_syms[i].bind = STB_GNU_UNIQUE; } else { ERROR("unknown symbol bind %s", bind); } @@ -431,7 +433,8 @@ int lookup_global_symbol(struct lookup_table *table, char *name, memset(result, 0, sizeof(*result)); for_each_obj_symbol(i, sym, table) { - if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && + if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK + || sym->bind == STB_GNU_UNIQUE) && !strcmp(sym->name, name)) { result->value = sym->value; result->size = sym->size; -- 2.18.1