kpatch/0011-support-c-plus-kernel-module.patch

193 lines
6.6 KiB
Diff
Raw Normal View History

From d170861502e78c396f0283f66f444a496efd11de Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
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 <xiezhipeng1@huawei.com>
---
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
2020-05-11 14:59:12 +08:00
@@ -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