diff mbox series

[08/20] livepatch-build: detect special section group sizes

Message ID 20190821082056.91090-9-wipawel@amazon.de (mailing list archive)
State Superseded
Headers show
Series livepatch-build-tools: new features and fixes | expand

Commit Message

Wieczorkiewicz, Pawel Aug. 21, 2019, 8:20 a.m. UTC
Hard-coding the special section group sizes is unreliable. Instead,
determine them dynamically by finding the related struct definitions
in the DWARF metadata.

This is a livepatch backport of kpatch upstream commit [1]:
kpatch-build: detect special section group sizes 170449847136a48b19fc

Xen only deals with alt_instr, bug_frame and exception_table_entry
structures, so sizes of these structures are obtained from xen-syms.

This change is needed since with recent Xen the alt_instr structure
has changed size from 12 to 14 bytes.

[1] https://github.com/jpoimboe/kpatch/commit/170449847136a48b19fcceb19c1d4d257d386b56

Signed-off-by: Pawel Wieczorkiewicz <wipawel@amazon.de>
Reviewed-by: Bjoern Doebel <doebel@amazon.de>
Reviewed-by: Martin Mazein <amazein@amazon.de>
Reviewed-by: Ross Lagerwall <ross.lagerwall@citrix.com>
---
 create-diff-object.c | 50 ++++++++++++++++++++++++++++++++++++++++----------
 livepatch-build      | 22 ++++++++++++++++++++++
 2 files changed, 62 insertions(+), 10 deletions(-)

Comments

Konrad Rzeszutek Wilk Aug. 21, 2019, 6:49 p.m. UTC | #1
> +    # Using xen-syms built in the previous step by build_full().
> +    SPECIAL_VARS=$(readelf -wi "$OUTPUT/xen-syms" |

What version of readelf supports this? Asking as in the past there were 
some options with binutils that had conflicting options and we had to 
add some custom hackery code to figure out which parameter to use.
Wieczorkiewicz, Pawel Aug. 21, 2019, 7:28 p.m. UTC | #2
> On 21. Aug 2019, at 20:49, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> 
> 
>> +    # Using xen-syms built in the previous step by build_full().
>> +    SPECIAL_VARS=$(readelf -wi "$OUTPUT/xen-syms" |
> 
> What version of readelf supports this? Asking as in the past there were some options with binutils that had conflicting options and we had to add some custom hackery code to figure out which parameter to use.


The version I use does: GNU readelf version 2.23.52.0.1 20130226
The -wi is a shortcut for —debug-dump=info.
I do hope it’s a standard readelf feature by now.

Best Regards,
Pawel Wieczorkiewicz



Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Ralf Herbrich
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879
diff mbox series

Patch

diff --git a/create-diff-object.c b/create-diff-object.c
index 0df3fea..c6183c3 100644
--- a/create-diff-object.c
+++ b/create-diff-object.c
@@ -958,12 +958,42 @@  static void kpatch_mark_constant_labels_same(struct kpatch_elf *kelf)
 	}
 }
 
-static int bug_frames_0_group_size(struct kpatch_elf *kelf, int offset) { return 8; }
-static int bug_frames_1_group_size(struct kpatch_elf *kelf, int offset) { return 8; }
-static int bug_frames_2_group_size(struct kpatch_elf *kelf, int offset) { return 8; }
-static int bug_frames_3_group_size(struct kpatch_elf *kelf, int offset) { return 16; }
-static int ex_table_group_size(struct kpatch_elf *kelf, int offset) { return 8; }
-static int altinstructions_group_size(struct kpatch_elf *kelf, int offset) { return 12; }
+static int bug_frames_group_size(struct kpatch_elf *kelf, int offset)
+{
+	static int size = 0;
+	char *str;
+	if (!size) {
+		str = getenv("BUG_STRUCT_SIZE");
+		size = str ? atoi(str) : 8;
+	}
+
+	return size;
+}
+
+static int ex_table_group_size(struct kpatch_elf *kelf, int offset)
+{
+	static int size = 0;
+	char *str;
+	if (!size) {
+		str = getenv("EX_STRUCT_SIZE");
+		size = str ? atoi(str) : 8;
+	}
+
+	return size;
+}
+
+static int altinstructions_group_size(struct kpatch_elf *kelf, int offset)
+{
+	static int size = 0;
+	char *str;
+	if (!size) {
+		str = getenv("ALT_STRUCT_SIZE");
+		size = str ? atoi(str) : 12;
+	}
+
+	log_debug("altinstr_size=%d\n", size);
+	return size;
+}
 
 /*
  * The rela groups in the .fixup section vary in size.  The beginning of each
@@ -1016,19 +1046,19 @@  static int fixup_group_size(struct kpatch_elf *kelf, int offset)
 static struct special_section special_sections[] = {
 	{
 		.name		= ".bug_frames.0",
-		.group_size	= bug_frames_0_group_size,
+		.group_size	= bug_frames_group_size,
 	},
 	{
 		.name		= ".bug_frames.1",
-		.group_size	= bug_frames_1_group_size,
+		.group_size	= bug_frames_group_size,
 	},
 	{
 		.name		= ".bug_frames.2",
-		.group_size	= bug_frames_2_group_size,
+		.group_size	= bug_frames_group_size,
 	},
 	{
 		.name		= ".bug_frames.3",
-		.group_size	= bug_frames_3_group_size,
+		.group_size	= bug_frames_group_size,
 	},
 	{
 		.name		= ".fixup",
diff --git a/livepatch-build b/livepatch-build
index 3c4bf13..7068faf 100755
--- a/livepatch-build
+++ b/livepatch-build
@@ -315,6 +315,28 @@  if [ "${SKIP}" != "build" ]; then
     echo "Perform full initial build with ${CPUS} CPU(s)..."
     build_full
 
+    echo "Reading special section data"
+    # Using xen-syms built in the previous step by build_full().
+    SPECIAL_VARS=$(readelf -wi "$OUTPUT/xen-syms" |
+               gawk --non-decimal-data '
+               BEGIN { a = b = e = 0 }
+               a == 0 && /DW_AT_name.* alt_instr/ {a = 1; next}
+               b == 0 && /DW_AT_name.* bug_frame/ {b = 1; next}
+               e == 0 && /DW_AT_name.* exception_table_entry/ {e = 1; next}
+               a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2}
+               b == 1 {printf("export BUG_STRUCT_SIZE=%d\n", $4); b = 2}
+               e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2}
+               a == 2 && b == 2 && e == 2 {exit}')
+    [[ -n $SPECIAL_VARS ]] && eval "$SPECIAL_VARS"
+    if [[ -z $ALT_STRUCT_SIZE ]] || [[ -z $BUG_STRUCT_SIZE ]] || [[ -z $EX_STRUCT_SIZE ]]; then
+        die "can't find special struct size"
+    fi
+    for i in $ALT_STRUCT_SIZE $BUG_STRUCT_SIZE $EX_STRUCT_SIZE; do
+        if [[ ! $i -gt 0 ]] || [[ ! $i -le 16 ]]; then
+            die "invalid special struct size $i"
+        fi
+    done
+
     echo "Apply patch and build with ${CPUS} CPU(s)..."
     cd "$SRCDIR" || die
     patch -s -N -p1 -f --fuzz=0 < "$PATCHFILE" || die