mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-22 17:49:13 +00:00
compel: rewrite parasite cmd and args manipulation from assembly to C
Previously, __export_parasite_cmd was located in parasite-head.S, and __export_parasite_args located exactly at the end of the parasite blob. This is not ideal for various reasons: 1) These two variables work together. It would be preferrable to have them in the same location 2) This prevent us from allocating another section betweeen the parasite blob and the args area. We'll need this to allocate a GOT table This commit changes the allocation of these symbols from assembly/linker script to a C file. Moreover, the assembly entry points that invoke parasite_service() prepares arguments with hand crafted assembly. This is unecessary. This commit rewrite this logic with regular C code. Note: if it wasn't for the x86 compat mode, we could remove all parasite-head.S files and directly jump to parasite_service() via ptrace. An int3 architecture specific equivalent could be called at the end of parasite_service() with an inline asm statement. Signed-off-by: Nicolas Viennot <Nicolas.Viennot@twosigma.com>
This commit is contained in:
parent
67965cb836
commit
d7353b9bb7
18 changed files with 54 additions and 107 deletions
|
|
@ -2,19 +2,6 @@
|
|||
|
||||
.section .head.text, "ax"
|
||||
ENTRY(__export_parasite_head_start)
|
||||
adr x2, __export_parasite_head_start // get the address of this instruction
|
||||
|
||||
ldr x0, __export_parasite_cmd
|
||||
|
||||
ldr x1, parasite_args_ptr
|
||||
add x1, x1, x2 // fixup __export_parasite_args
|
||||
|
||||
bl parasite_service
|
||||
brk #0 // the instruction BRK #0 generates the signal SIGTRAP in Linux
|
||||
|
||||
parasite_args_ptr:
|
||||
.quad __export_parasite_args
|
||||
|
||||
__export_parasite_cmd:
|
||||
.quad 0
|
||||
END(__export_parasite_head_start)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,4 @@ SECTIONS
|
|||
*(.eh_frame*)
|
||||
*(*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,7 @@
|
|||
|
||||
.section .head.text, "ax"
|
||||
ENTRY(__export_parasite_head_start)
|
||||
sub r2, pc, #8 @ get the address of this instruction
|
||||
|
||||
adr r0, __export_parasite_cmd
|
||||
ldr r0, [r0]
|
||||
|
||||
adr r1, parasite_args_ptr
|
||||
ldr r1, [r1]
|
||||
add r1, r1, r2 @ fixup __export_parasite_args
|
||||
|
||||
bl parasite_service
|
||||
.byte 0xf0, 0x01, 0xf0, 0xe7 @ the instruction UDF #32 generates the signal SIGTRAP in Linux
|
||||
|
||||
parasite_args_ptr:
|
||||
.long __export_parasite_args
|
||||
|
||||
__export_parasite_cmd:
|
||||
.long 0
|
||||
END(__export_parasite_head_start)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,4 @@ SECTIONS
|
|||
*(.eh_frame*)
|
||||
*(*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,10 @@
|
|||
ENTRY(__export_parasite_head_start)
|
||||
.set push
|
||||
.set noreorder
|
||||
lw a0, __export_parasite_cmd
|
||||
dla a1, __export_parasite_args
|
||||
jal parasite_service
|
||||
nop
|
||||
.byte 0x0d, 0x00, 0x00, 0x00 //break
|
||||
.set pop
|
||||
// .byte 0x40,0x01,0x00,0x00 //pause
|
||||
|
||||
__export_parasite_cmd:
|
||||
.long 0
|
||||
END(__export_parasite_head_start)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,4 @@ SECTIONS
|
|||
*(.MIPS.options)
|
||||
*(.gnu.attributes)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(32);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@
|
|||
.align 8
|
||||
|
||||
ENTRY(__export_parasite_head_start)
|
||||
|
||||
// int __used parasite_service(unsigned int cmd, void *args)
|
||||
// cmd = r3 = *__export_parasite_cmd (u32 ?)
|
||||
// args = r4 = @parasite_args_ptr + @pc
|
||||
bl 0f
|
||||
0: mflr r2
|
||||
|
||||
|
|
@ -15,12 +11,6 @@ ENTRY(__export_parasite_head_start)
|
|||
addis reg,r2,(name - 0b)@ha; \
|
||||
addi reg,r2,(name - 0b)@l;
|
||||
|
||||
LOAD_REG_ADDR(r3,__export_parasite_cmd)
|
||||
lwz r3,0(r3)
|
||||
|
||||
LOAD_REG_ADDR(r4,parasite_args_ptr)
|
||||
ld r4,0(r4)
|
||||
|
||||
LOAD_REG_ADDR(r12,parasite_service_ptr)
|
||||
ld r12,0(r12)
|
||||
mtctr r12
|
||||
|
|
@ -28,9 +18,6 @@ ENTRY(__export_parasite_head_start)
|
|||
bctrl // call parasite_service
|
||||
twi 31,0,0 // Should generate SIGTRAP
|
||||
|
||||
parasite_args_ptr:
|
||||
.quad __export_parasite_args
|
||||
|
||||
parasite_service_ptr:
|
||||
// We want to run the function prototype to set r2.
|
||||
// Since the relocation will prefer the local entry
|
||||
|
|
@ -39,7 +26,4 @@ parasite_service_ptr:
|
|||
// FIXME: There should be a way to specify the global entry here.
|
||||
.quad parasite_service - 8
|
||||
|
||||
__export_parasite_cmd:
|
||||
.long 0
|
||||
|
||||
END(__export_parasite_head_start)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,4 @@ SECTIONS
|
|||
*(.group*)
|
||||
*(.eh_frame*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,25 +2,7 @@
|
|||
|
||||
.section .head.text, "ax"
|
||||
|
||||
/*
|
||||
* Entry point for parasite_service()
|
||||
*
|
||||
* Addresses of symbols are exported in auto-generated criu/pie/parasite-blob.h
|
||||
*
|
||||
* Function is called via parasite_run(). The command for parasite_service()
|
||||
* is stored in global variable __export_parasite_cmd.
|
||||
*
|
||||
* Load parameters for parasite_service(unsigned int cmd, void *args):
|
||||
*
|
||||
* - Parameter 1 (cmd) : %r2 = *(uint32 *)(__export_parasite_cmd + pc)
|
||||
* - Parameter 2 (args): %r3 = __export_parasite_args + pc
|
||||
*/
|
||||
ENTRY(__export_parasite_head_start)
|
||||
larl %r14,__export_parasite_cmd
|
||||
llgf %r2,0(%r14)
|
||||
larl %r3,__export_parasite_args
|
||||
brasl %r14,parasite_service
|
||||
.long 0x00010001 /* S390_BREAKPOINT_U16: Generates SIGTRAP */
|
||||
__export_parasite_cmd:
|
||||
.long 0
|
||||
END(__export_parasite_head_start)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,4 @@ SECTIONS
|
|||
*(.group*)
|
||||
*(.eh_frame*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
andq $~15, %rsp
|
||||
pushq $\num
|
||||
movq %rsp, %rbp
|
||||
movl __export_parasite_cmd(%rip), %edi
|
||||
leaq __export_parasite_args(%rip), %rsi
|
||||
call parasite_service
|
||||
.endm
|
||||
|
||||
|
|
@ -48,7 +46,3 @@ ENTRY(__export_parasite_head_start)
|
|||
PARASITE_ENTRY 0
|
||||
int $0x03
|
||||
END(__export_parasite_head_start)
|
||||
|
||||
.align 8
|
||||
GLOBAL(__export_parasite_cmd)
|
||||
.long 0
|
||||
|
|
|
|||
|
|
@ -34,8 +34,4 @@ SECTIONS
|
|||
*(.group*)
|
||||
*(.eh_frame*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,4 @@ SECTIONS
|
|||
*(.group*)
|
||||
*(.eh_frame*)
|
||||
}
|
||||
|
||||
/* Parasite args should have 4 bytes align, as we have futex inside. */
|
||||
. = ALIGN(4);
|
||||
__export_parasite_args = .;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ struct parasite_blob_desc {
|
|||
size_t nr_gotpcrel;
|
||||
unsigned long parasite_ip_off;
|
||||
unsigned long cmd_off;
|
||||
unsigned long args_ptr_off;
|
||||
unsigned long args_off;
|
||||
compel_reloc_t *relocs;
|
||||
unsigned int nr_relocs;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
#include "common/compiler.h"
|
||||
|
||||
extern int parasite_get_rpc_sock(void);
|
||||
extern int __must_check parasite_service(unsigned int cmd, void *args);
|
||||
|
||||
extern unsigned int __export_parasite_service_cmd;
|
||||
extern void * __export_parasite_service_args_ptr;
|
||||
extern int __must_check parasite_service(void);
|
||||
|
||||
/*
|
||||
* Must be supplied by user plugins.
|
||||
|
|
|
|||
|
|
@ -196,8 +196,22 @@ err:
|
|||
# define __parasite_entry
|
||||
#endif
|
||||
|
||||
int __used __parasite_entry parasite_service(unsigned int cmd, void *args)
|
||||
/*
|
||||
* __export_parasite_service_{cmd,args} serve as arguments to the
|
||||
* parasite_service() function. We use these global variables to make it
|
||||
* easier to pass arguments when invoking from ptrace.
|
||||
*
|
||||
* We need the linker to allocate these variables. Hence the dummy
|
||||
* initialization. Otherwise, we end up with COMMON symbols.
|
||||
*/
|
||||
unsigned int __export_parasite_service_cmd = 0;
|
||||
void * __export_parasite_service_args_ptr = NULL;
|
||||
|
||||
int __used __parasite_entry parasite_service(void)
|
||||
{
|
||||
unsigned int cmd = __export_parasite_service_cmd;
|
||||
void *args = __export_parasite_service_args_ptr;
|
||||
|
||||
pr_info("Parasite cmd %d/%x process\n", cmd, cmd);
|
||||
|
||||
if (cmd == PARASITE_CMD_INIT_DAEMON)
|
||||
|
|
|
|||
|
|
@ -699,10 +699,9 @@ int __handle_elf(void *mem, size_t size)
|
|||
pr_out("\t\tpbd->hdr.parasite_ip_off = "
|
||||
"%s_sym__export_parasite_head_start_compat;\n", opts.prefix);
|
||||
pr_out("#endif /* CONFIG_COMPAT */\n");
|
||||
pr_out("\tpbd->hdr.cmd_off = "
|
||||
"%s_sym__export_parasite_cmd;\n", opts.prefix);
|
||||
pr_out("\tpbd->hdr.args_off = "
|
||||
"%s_sym__export_parasite_args;\n", opts.prefix);
|
||||
pr_out("\tpbd->hdr.cmd_off = %s_sym__export_parasite_service_cmd;\n", opts.prefix);
|
||||
pr_out("\tpbd->hdr.args_ptr_off = %s_sym__export_parasite_service_args_ptr;\n", opts.prefix);
|
||||
pr_out("\tpbd->hdr.args_off = round_up(pbd->hdr.bsize, 4);\n");
|
||||
pr_out("\tpbd->hdr.relocs = %s_relocs;\n", opts.prefix);
|
||||
pr_out("\tpbd->hdr.nr_relocs = "
|
||||
"sizeof(%s_relocs) / sizeof(%s_relocs[0]);\n",
|
||||
|
|
|
|||
|
|
@ -822,6 +822,13 @@ void compel_relocs_apply(void *mem, void *vbase, struct parasite_blob_desc *pbd)
|
|||
|
||||
size_t i, j;
|
||||
|
||||
/*
|
||||
* parasite_service() reads the value of __export_parasite_service_args_ptr.
|
||||
* The reason it is set here is that semantically, we are doing a symbol
|
||||
* resolution on parasite_service_args, and it turns out to be relocatable.
|
||||
*/
|
||||
*(void **)(mem + pbd->hdr.args_ptr_off) = vbase + pbd->hdr.args_off;
|
||||
|
||||
#ifdef CONFIG_MIPS
|
||||
compel_relocs_apply_mips(mem, vbase, pbd);
|
||||
#else
|
||||
|
|
@ -883,7 +890,30 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l
|
|||
* without using ptrace at all.
|
||||
*/
|
||||
|
||||
parasite_size = ctl->pblob.hdr.bsize;
|
||||
/*
|
||||
* The parasite memory layout is the following:
|
||||
* Low address start first.
|
||||
* The number in parenthesis denotes the size of the section.
|
||||
* The arrow on the right shows the different variables that
|
||||
* corresponds to a given offset.
|
||||
* +------------------------------------------------------+ <--- 0
|
||||
* | Parasite blob (sizeof(parasite_blob)) |
|
||||
* +------------------------------------------------------+ <--- hdr.bsize
|
||||
* align 4
|
||||
* +------------------------------------------------------+ <--- hdr.args_off
|
||||
* | Args area (args_size) |
|
||||
* +------------------------------------------------------+
|
||||
* align 64
|
||||
* +------------------------------------------------------+ <--- ctl->rsigframe
|
||||
* | sigframe (RESTORE_STACK_SIGFRAME) | ctl->sigframe
|
||||
* +------------------------------------------------------+
|
||||
* | main stack (PARASITE_STACK_SIZE) |
|
||||
* +------------------------------------------------------+ <--- ctl->rstack
|
||||
* | compel_run_in_thread stack (PARASITE_STACK_SIZE) |
|
||||
* +------------------------------------------------------+ <--- ctl->r_thread_stack
|
||||
* map_exchange_size
|
||||
*/
|
||||
parasite_size = ctl->pblob.hdr.args_off;
|
||||
|
||||
ctl->args_size = args_size;
|
||||
parasite_size += ctl->args_size;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue