194 lines
6.6 KiB
Diff
194 lines
6.6 KiB
Diff
From 20de56a8393e6be3b556156124aa4b2139b10733 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/17] 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 <root@localhost.localdomain>
|
||
---
|
||
kpatch-build/create-diff-object.c | 62 ++++++++++++++++++++-----------
|
||
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(+), 25 deletions(-)
|
||
|
||
diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c
|
||
index 643ae3e..190753a 100644
|
||
--- a/kpatch-build/create-diff-object.c
|
||
+++ b/kpatch-build/create-diff-object.c
|
||
@@ -454,7 +454,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
|
||
@@ -470,7 +470,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 */
|
||
@@ -907,6 +907,33 @@ 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;
|
||
@@ -924,15 +951,19 @@ static void kpatch_correlate_sections(struct list_head *seclist1, struct list_he
|
||
sec1->secsym))
|
||
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;
|
||
}
|
||
|
||
@@ -1507,17 +1538,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 1c0e099..debf028 100644
|
||
--- a/kpatch-build/kpatch-elf.c
|
||
+++ b/kpatch-build/kpatch-elf.c
|
||
@@ -708,8 +708,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
|
||
|