mirror of
https://github.com/dynup/kpatch
synced 2025-03-11 05:07:53 +00:00
Merge pull request #879 from jpoimboe/orc
create-diff-object: add ORC section support
This commit is contained in:
commit
63582367f4
@ -1998,6 +1998,94 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
|
||||
sec->base->data->d_size = dest_offset;
|
||||
}
|
||||
|
||||
#define ORC_IP_PTR_SIZE 4
|
||||
|
||||
/*
|
||||
* This function is similar to kpatch_regenerate_special_section(), but
|
||||
* customized for the ORC-related sections. ORC is more special than the other
|
||||
* special sections because each ORC entry is split into .orc_unwind (struct
|
||||
* orc_entry) and .orc_unwind_ip.
|
||||
*/
|
||||
static void kpatch_regenerate_orc_sections(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct rela *rela, *safe;
|
||||
char *src, *dest, *str;
|
||||
unsigned int src_idx = 0, dest_idx = 0, orc_entry_size;
|
||||
struct section *orc_sec, *ip_sec;
|
||||
|
||||
|
||||
str = getenv("ORC_STRUCT_SIZE");
|
||||
if (!str)
|
||||
return;
|
||||
orc_entry_size = atoi(str);
|
||||
|
||||
LIST_HEAD(newrelas);
|
||||
|
||||
orc_sec = find_section_by_name(&kelf->sections, ".orc_unwind");
|
||||
ip_sec = find_section_by_name(&kelf->sections, ".orc_unwind_ip");
|
||||
|
||||
if (!orc_sec || !ip_sec)
|
||||
return;
|
||||
|
||||
if (orc_sec->sh.sh_size % orc_entry_size != 0)
|
||||
ERROR("bad .orc_unwind size");
|
||||
|
||||
if (ip_sec->sh.sh_size !=
|
||||
(orc_sec->sh.sh_size / orc_entry_size) * ORC_IP_PTR_SIZE)
|
||||
ERROR(".orc_unwind/.orc_unwind_ip size mismatch");
|
||||
|
||||
src = orc_sec->data->d_buf;
|
||||
dest = malloc(orc_sec->sh.sh_size);
|
||||
if (!dest)
|
||||
ERROR("malloc");
|
||||
|
||||
list_for_each_entry_safe(rela, safe, &ip_sec->rela->relas, list) {
|
||||
|
||||
if (rela->sym->type != STT_FUNC || !rela->sym->sec->include)
|
||||
goto next;
|
||||
|
||||
/* copy orc entry */
|
||||
memcpy(dest + (dest_idx * orc_entry_size),
|
||||
src + (src_idx * orc_entry_size),
|
||||
orc_entry_size);
|
||||
|
||||
/* move ip rela */
|
||||
list_del(&rela->list);
|
||||
list_add_tail(&rela->list, &newrelas);
|
||||
rela->offset = dest_idx * ORC_IP_PTR_SIZE;
|
||||
rela->sym->include = 1;
|
||||
|
||||
dest_idx++;
|
||||
next:
|
||||
src_idx++;
|
||||
}
|
||||
|
||||
if (!dest_idx) {
|
||||
/* no changed or global functions referenced */
|
||||
orc_sec->status = ip_sec->status = ip_sec->rela->status = SAME;
|
||||
orc_sec->include = ip_sec->include = ip_sec->rela->include = 0;
|
||||
free(dest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* overwrite with new relas list */
|
||||
list_replace(&newrelas, &ip_sec->rela->relas);
|
||||
|
||||
/* include the sections */
|
||||
orc_sec->include = ip_sec->include = ip_sec->rela->include = 1;
|
||||
|
||||
/*
|
||||
* Update data buf/size.
|
||||
*
|
||||
* The ip section can keep its old (zeroed data), though its size has
|
||||
* possibly decreased. The ip rela section's data buf and size will be
|
||||
* regenerated in kpatch_rebuild_rela_section_data().
|
||||
*/
|
||||
orc_sec->data->d_buf = dest;
|
||||
orc_sec->data->d_size = dest_idx * orc_entry_size;
|
||||
ip_sec->data->d_size = dest_idx * ORC_IP_PTR_SIZE;
|
||||
}
|
||||
|
||||
static void kpatch_check_relocations(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct rela *rela;
|
||||
@ -2278,6 +2366,8 @@ static void kpatch_process_special_sections(struct kpatch_elf *kelf)
|
||||
sec->rela->include = 0;
|
||||
}
|
||||
}
|
||||
|
||||
kpatch_regenerate_orc_sections(kelf);
|
||||
}
|
||||
|
||||
static struct sym_compare_type *kpatch_elf_locals(struct kpatch_elf *kelf)
|
||||
|
@ -260,30 +260,35 @@ find_special_section_data() {
|
||||
fi
|
||||
|
||||
[[ "$CONFIG_PARAVIRT" -eq 0 ]] && AWK_OPTIONS="-vskip_p=1"
|
||||
[[ "$CONFIG_UNWINDER_ORC" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_o=1"
|
||||
|
||||
SPECIAL_VARS="$(readelf -wi "$VMLINUX" |
|
||||
gawk --non-decimal-data $AWK_OPTIONS '
|
||||
BEGIN { a = b = p = e = 0 }
|
||||
gawk --non-decimal-data "$AWK_OPTIONS" '
|
||||
BEGIN { a = b = p = e = o = 0 }
|
||||
|
||||
# Set state if name matches
|
||||
a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next}
|
||||
b == 0 && /DW_AT_name.* bug_entry[[:space:]]*$/ {b = 1; next}
|
||||
p == 0 && /DW_AT_name.* paravirt_patch_site[[:space:]]*$/ {p = 1; next}
|
||||
e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next}
|
||||
o == 0 && /DW_AT_name.* orc_entry[[:space:]]*$/ {o = 1; next}
|
||||
|
||||
# Reset state unless this abbrev describes the struct size
|
||||
a == 1 && !/DW_AT_byte_size/ { a = 0; next }
|
||||
b == 1 && !/DW_AT_byte_size/ { b = 0; next }
|
||||
p == 1 && !/DW_AT_byte_size/ { p = 0; next }
|
||||
e == 1 && !/DW_AT_byte_size/ { e = 0; next }
|
||||
o == 1 && !/DW_AT_byte_size/ { o = 0; next }
|
||||
|
||||
# Now that we know the size, stop parsing for it
|
||||
a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2}
|
||||
b == 1 {printf("export BUG_STRUCT_SIZE=%d\n", $4); b = 2}
|
||||
p == 1 {printf("export PARA_STRUCT_SIZE=%d\n", $4); p = 2}
|
||||
e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2}
|
||||
o == 1 {printf("export ORC_STRUCT_SIZE=%d\n", $4); o = 2}
|
||||
|
||||
# Bail out once we have everything
|
||||
a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 {exit}')"
|
||||
a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 && (o == 2 || skip_o) {exit}')"
|
||||
|
||||
[[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS"
|
||||
|
||||
@ -291,6 +296,7 @@ find_special_section_data() {
|
||||
[[ -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size"
|
||||
[[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct paravirt_patch_site size"
|
||||
[[ -z "$PARA_STRUCT_SIZE" && "$CONFIG_PARAVIRT" -ne 0 ]] && die "can't find special struct paravirt_patch_site size"
|
||||
[[ -z "$ORC_STRUCT_SIZE" && "$CONFIG_UNWINDER_ORC" -ne 0 ]] && die "can't find special struct orc_entry size"
|
||||
|
||||
return
|
||||
}
|
||||
@ -667,12 +673,17 @@ else
|
||||
KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE"
|
||||
fi
|
||||
|
||||
# optional kernel configs: CONFIG_PARAVIRT
|
||||
# optional kernel configs:
|
||||
if grep -q "CONFIG_PARAVIRT=y" "$CONFIGFILE"; then
|
||||
CONFIG_PARAVIRT=1
|
||||
else
|
||||
CONFIG_PARAVIRT=0
|
||||
fi
|
||||
if grep -q "CONFIG_UNWINDER_ORC=y" "$CONFIGFILE"; then
|
||||
CONFIG_UNWINDER_ORC=1
|
||||
else
|
||||
CONFIG_UNWINDER_ORC=0
|
||||
fi
|
||||
|
||||
# unsupported kernel option checking: CONFIG_DEBUG_INFO_SPLIT
|
||||
grep -q "CONFIG_DEBUG_INFO_SPLIT=y" "$CONFIGFILE" && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported"
|
||||
|
Loading…
Reference in New Issue
Block a user