mirror of https://github.com/dynup/kpatch
create-diff-object: move addend math to a new function
Split out the addend offset math into a separate function so it can be used elsewhere. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
This commit is contained in:
parent
bec6488af6
commit
01427d50a1
|
@ -31,8 +31,8 @@ all: $(TARGETS)
|
|||
-include $(SOURCES:.c=.d)
|
||||
|
||||
create-diff-object: create-diff-object.o kpatch-elf.o lookup.o $(INSN)
|
||||
create-klp-module: create-klp-module.o kpatch-elf.o
|
||||
create-kpatch-module: create-kpatch-module.o kpatch-elf.o
|
||||
create-klp-module: create-klp-module.o kpatch-elf.o $(INSN)
|
||||
create-kpatch-module: create-kpatch-module.o kpatch-elf.o $(INSN)
|
||||
|
||||
$(PLUGIN): gcc-plugins/ppc64le-plugin.c
|
||||
g++ $(PLUGIN_CFLAGS) $< -o $@
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
#include "list.h"
|
||||
#include "lookup.h"
|
||||
#include "asm/insn.h"
|
||||
#include "kpatch-patch.h"
|
||||
#include "kpatch-elf.h"
|
||||
#include "kpatch-intermediate.h"
|
||||
|
@ -577,39 +576,6 @@ out:
|
|||
log_debug("section %s has changed\n", sec->name);
|
||||
}
|
||||
|
||||
static unsigned int insn_length(struct kpatch_elf *kelf, void *addr)
|
||||
{
|
||||
struct insn decoded_insn;
|
||||
char *insn = addr;
|
||||
|
||||
switch(kelf->arch) {
|
||||
|
||||
case X86_64:
|
||||
insn_init(&decoded_insn, addr, 1);
|
||||
insn_get_length(&decoded_insn);
|
||||
return decoded_insn.length;
|
||||
|
||||
case PPC64:
|
||||
return 4;
|
||||
|
||||
case S390:
|
||||
switch(insn[0] >> 6) {
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
case 2:
|
||||
return 4;
|
||||
case 3:
|
||||
return 6;
|
||||
}
|
||||
|
||||
default:
|
||||
ERROR("unsupported arch");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is not comprehensive, i.e. it doesn't detect immediate loads
|
||||
* to *all* registers. It only detects those which have been found in the wild
|
||||
|
@ -1477,33 +1443,6 @@ static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf)
|
|||
kpatch_compare_symbols(&kelf->symbols);
|
||||
}
|
||||
|
||||
static void rela_insn(const struct section *sec, const struct rela *rela,
|
||||
struct insn *insn)
|
||||
{
|
||||
unsigned long insn_addr, start, end, rela_addr;
|
||||
|
||||
start = (unsigned long)sec->data->d_buf;
|
||||
end = start + sec->sh.sh_size;
|
||||
|
||||
if (end <= start)
|
||||
ERROR("bad section size");
|
||||
|
||||
rela_addr = start + rela->offset;
|
||||
for (insn_addr = start; insn_addr < end; insn_addr += insn->length) {
|
||||
insn_init(insn, (void *)insn_addr, 1);
|
||||
insn_get_length(insn);
|
||||
if (!insn->length)
|
||||
ERROR("can't decode instruction in section %s at offset 0x%lx",
|
||||
sec->name, insn_addr);
|
||||
if (rela_addr >= insn_addr &&
|
||||
rela_addr < insn_addr + insn->length)
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR("can't find instruction for rela at %s+0x%x",
|
||||
sec->name, rela->offset);
|
||||
}
|
||||
|
||||
static bool is_callback_section(struct section *sec) {
|
||||
|
||||
static char *callback_sections[] = {
|
||||
|
@ -1538,13 +1477,12 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
|
|||
struct section *relasec;
|
||||
struct rela *rela;
|
||||
struct symbol *sym;
|
||||
unsigned int add_off;
|
||||
long target_off;
|
||||
|
||||
log_debug("\n");
|
||||
|
||||
list_for_each_entry(relasec, &kelf->sections, list) {
|
||||
if (!is_rela_section(relasec) ||
|
||||
is_debug_section(relasec))
|
||||
if (!is_rela_section(relasec) || is_debug_section(relasec))
|
||||
continue;
|
||||
|
||||
list_for_each_entry(rela, &relasec->relas, list) {
|
||||
|
@ -1573,29 +1511,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
|
|||
continue;
|
||||
}
|
||||
|
||||
switch(kelf->arch) {
|
||||
case PPC64:
|
||||
add_off = 0;
|
||||
break;
|
||||
case X86_64:
|
||||
if (!is_text_section(relasec->base) ||
|
||||
rela->type == R_X86_64_64 ||
|
||||
rela->type == R_X86_64_32S)
|
||||
add_off = 0;
|
||||
else if (rela->type == R_X86_64_PC32 ||
|
||||
rela->type == R_X86_64_PLT32 ||
|
||||
rela->type == R_X86_64_NONE) {
|
||||
struct insn insn;
|
||||
rela_insn(relasec->base, rela, &insn);
|
||||
add_off = (unsigned int)((long)insn.next_byte -
|
||||
(long)relasec->base->data->d_buf -
|
||||
rela->offset);
|
||||
} else
|
||||
ERROR("unhandled rela type %d", rela->type);
|
||||
break;
|
||||
default:
|
||||
ERROR("unsupported arch");
|
||||
}
|
||||
target_off = rela_target_offset(kelf, relasec, rela);
|
||||
|
||||
/*
|
||||
* Attempt to replace references to unbundled sections
|
||||
|
@ -1648,8 +1564,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
|
|||
* be the same as &var2.
|
||||
*/
|
||||
|
||||
} else if (rela->addend + add_off < start ||
|
||||
rela->addend + add_off >= end)
|
||||
} else if (target_off < start || target_off >= end)
|
||||
continue;
|
||||
|
||||
log_debug("%s: replacing %s+%ld reference with %s+%ld\n",
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "asm/insn.h"
|
||||
#include "kpatch-elf.h"
|
||||
|
||||
/*******************
|
||||
|
@ -164,6 +165,103 @@ int offset_of_string(struct list_head *list, char *name)
|
|||
return index;
|
||||
}
|
||||
|
||||
static void rela_insn(const struct section *sec, const struct rela *rela,
|
||||
struct insn *insn)
|
||||
{
|
||||
unsigned long insn_addr, start, end, rela_addr;
|
||||
|
||||
start = (unsigned long)sec->data->d_buf;
|
||||
end = start + sec->sh.sh_size;
|
||||
|
||||
if (end <= start)
|
||||
ERROR("bad section size");
|
||||
|
||||
rela_addr = start + rela->offset;
|
||||
for (insn_addr = start; insn_addr < end; insn_addr += insn->length) {
|
||||
insn_init(insn, (void *)insn_addr, 1);
|
||||
insn_get_length(insn);
|
||||
if (!insn->length)
|
||||
ERROR("can't decode instruction in section %s at offset 0x%lx",
|
||||
sec->name, insn_addr);
|
||||
if (rela_addr >= insn_addr &&
|
||||
rela_addr < insn_addr + insn->length)
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR("can't find instruction for rela at %s+0x%x",
|
||||
sec->name, rela->offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the addend, adjusted for any PC-relative relocation trickery, to
|
||||
* point to the relevant symbol offset.
|
||||
*/
|
||||
long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
|
||||
struct rela *rela)
|
||||
{
|
||||
long add_off;
|
||||
struct section *sec = relasec->base;
|
||||
|
||||
switch(kelf->arch) {
|
||||
case PPC64:
|
||||
add_off = 0;
|
||||
break;
|
||||
case X86_64:
|
||||
if (!is_text_section(sec) ||
|
||||
rela->type == R_X86_64_64 ||
|
||||
rela->type == R_X86_64_32S)
|
||||
add_off = 0;
|
||||
else if (rela->type == R_X86_64_PC32 ||
|
||||
rela->type == R_X86_64_PLT32 ||
|
||||
rela->type == R_X86_64_NONE) {
|
||||
struct insn insn;
|
||||
rela_insn(sec, rela, &insn);
|
||||
add_off = (long)insn.next_byte -
|
||||
(long)sec->data->d_buf -
|
||||
rela->offset;
|
||||
} else
|
||||
ERROR("unhandled rela type %d", rela->type);
|
||||
break;
|
||||
default:
|
||||
ERROR("unsupported arch\n");
|
||||
}
|
||||
|
||||
return rela->addend + add_off;
|
||||
}
|
||||
|
||||
unsigned int insn_length(struct kpatch_elf *kelf, void *addr)
|
||||
{
|
||||
struct insn decoded_insn;
|
||||
char *insn = addr;
|
||||
|
||||
switch(kelf->arch) {
|
||||
|
||||
case X86_64:
|
||||
insn_init(&decoded_insn, addr, 1);
|
||||
insn_get_length(&decoded_insn);
|
||||
return decoded_insn.length;
|
||||
|
||||
case PPC64:
|
||||
return 4;
|
||||
|
||||
case S390:
|
||||
switch(insn[0] >> 6) {
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
case 2:
|
||||
return 4;
|
||||
case 3:
|
||||
return 6;
|
||||
}
|
||||
|
||||
default:
|
||||
ERROR("unsupported arch");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kpatch_create_rela_list(struct kpatch_elf *kelf,
|
||||
struct section *relasec)
|
||||
{
|
||||
|
|
|
@ -152,6 +152,9 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset);
|
|||
|
||||
unsigned int absolute_rela_type(struct kpatch_elf *kelf);
|
||||
int offset_of_string(struct list_head *list, char *name);
|
||||
long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
|
||||
struct rela *rela);
|
||||
unsigned int insn_length(struct kpatch_elf *kelf, void *addr);
|
||||
|
||||
#ifndef R_PPC64_ENTRY
|
||||
#define R_PPC64_ENTRY 118
|
||||
|
|
Loading…
Reference in New Issue