mirror of https://github.com/xemu-project/xemu.git
linux-user/elfload: Write corefile elf header in one block
Fixes a bug in which write_note() wrote namesz_rounded and datasz_rounded bytes, even though name and data pointers contain only the unrounded number of bytes. Instead of many small writes, allocate a block to contain all of the elf headers and all of the notes. Copy the data into the block piecemeal and the write it to the file as a chunk. This also avoids the need to lseek forward for alignment. Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
2410d28dc9
commit
243c470662
|
@ -4002,18 +4002,6 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
||||||
* Example for ARM target is provided in this file.
|
* Example for ARM target is provided in this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* An ELF note in memory */
|
|
||||||
struct memelfnote {
|
|
||||||
const char *name;
|
|
||||||
size_t namesz;
|
|
||||||
size_t namesz_rounded;
|
|
||||||
int type;
|
|
||||||
size_t datasz;
|
|
||||||
size_t datasz_rounded;
|
|
||||||
void *data;
|
|
||||||
size_t notesz;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct target_elf_siginfo {
|
struct target_elf_siginfo {
|
||||||
abi_int si_signo; /* signal number */
|
abi_int si_signo; /* signal number */
|
||||||
abi_int si_code; /* extra code */
|
abi_int si_code; /* extra code */
|
||||||
|
@ -4053,40 +4041,6 @@ struct target_elf_prpsinfo {
|
||||||
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
|
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Here is the structure in which status of each thread is captured. */
|
|
||||||
struct elf_thread_status {
|
|
||||||
QTAILQ_ENTRY(elf_thread_status) ets_link;
|
|
||||||
struct target_elf_prstatus prstatus; /* NT_PRSTATUS */
|
|
||||||
#if 0
|
|
||||||
elf_fpregset_t fpu; /* NT_PRFPREG */
|
|
||||||
struct task_struct *thread;
|
|
||||||
elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */
|
|
||||||
#endif
|
|
||||||
struct memelfnote notes[1];
|
|
||||||
int num_notes;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NUMNOTES 3
|
|
||||||
|
|
||||||
struct elf_note_info {
|
|
||||||
struct memelfnote notes[NUMNOTES];
|
|
||||||
struct target_elf_prstatus prstatus; /* NT_PRSTATUS */
|
|
||||||
struct target_elf_prpsinfo psinfo; /* NT_PRPSINFO */
|
|
||||||
|
|
||||||
QTAILQ_HEAD(, elf_thread_status) thread_list;
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* Current version of ELF coredump doesn't support
|
|
||||||
* dumping fp regs etc.
|
|
||||||
*/
|
|
||||||
elf_fpregset_t *fpu;
|
|
||||||
elf_fpxregset_t *xfpu;
|
|
||||||
int thread_status_size;
|
|
||||||
#endif
|
|
||||||
int notes_size;
|
|
||||||
int numnote;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vm_area_struct {
|
struct vm_area_struct {
|
||||||
target_ulong vma_start; /* start vaddr of memory region */
|
target_ulong vma_start; /* start vaddr of memory region */
|
||||||
target_ulong vma_end; /* end vaddr of memory region */
|
target_ulong vma_end; /* end vaddr of memory region */
|
||||||
|
@ -4110,22 +4064,6 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *);
|
||||||
static int vma_walker(void *priv, target_ulong start, target_ulong end,
|
static int vma_walker(void *priv, target_ulong start, target_ulong end,
|
||||||
unsigned long flags);
|
unsigned long flags);
|
||||||
|
|
||||||
static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
|
|
||||||
static void fill_note(struct memelfnote *, const char *, int,
|
|
||||||
unsigned int, void *);
|
|
||||||
static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
|
|
||||||
static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
|
|
||||||
static void fill_auxv_note(struct memelfnote *, const TaskState *);
|
|
||||||
static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
|
|
||||||
static size_t note_size(const struct memelfnote *);
|
|
||||||
static void free_note_info(struct elf_note_info *);
|
|
||||||
static void fill_note_info(struct elf_note_info *, int, const CPUArchState *);
|
|
||||||
static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
|
|
||||||
|
|
||||||
static int dump_write(int, const void *, size_t);
|
|
||||||
static int write_note(struct memelfnote *, int);
|
|
||||||
static int write_note_info(struct elf_note_info *, int);
|
|
||||||
|
|
||||||
#ifdef BSWAP_NEEDED
|
#ifdef BSWAP_NEEDED
|
||||||
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
|
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
|
||||||
{
|
{
|
||||||
|
@ -4280,35 +4218,32 @@ static size_t size_note(const char *name, size_t datasz)
|
||||||
return sizeof(struct elf_note) + namesz + datasz;
|
return sizeof(struct elf_note) + namesz + datasz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_note(struct memelfnote *note, const char *name, int type,
|
static void *fill_note(void **pptr, int type, const char *name, size_t datasz)
|
||||||
unsigned int sz, void *data)
|
|
||||||
{
|
{
|
||||||
unsigned int namesz;
|
void *ptr = *pptr;
|
||||||
|
struct elf_note *n = ptr;
|
||||||
|
size_t namesz = strlen(name) + 1;
|
||||||
|
|
||||||
namesz = strlen(name) + 1;
|
n->n_namesz = namesz;
|
||||||
note->name = name;
|
n->n_descsz = datasz;
|
||||||
note->namesz = namesz;
|
n->n_type = type;
|
||||||
note->namesz_rounded = roundup(namesz, sizeof (int32_t));
|
bswap_note(n);
|
||||||
note->type = type;
|
|
||||||
note->datasz = sz;
|
|
||||||
note->datasz_rounded = roundup(sz, sizeof (int32_t));
|
|
||||||
|
|
||||||
note->data = data;
|
ptr += sizeof(*n);
|
||||||
|
memcpy(ptr, name, namesz);
|
||||||
|
|
||||||
/*
|
namesz = ROUND_UP(namesz, 4);
|
||||||
* We calculate rounded up note size here as specified by
|
datasz = ROUND_UP(datasz, 4);
|
||||||
* ELF document.
|
|
||||||
*/
|
*pptr = ptr + namesz + datasz;
|
||||||
note->notesz = sizeof (struct elf_note) +
|
return ptr + namesz;
|
||||||
note->namesz_rounded + note->datasz_rounded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
|
static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
(void) memset(elf, 0, sizeof(*elf));
|
memcpy(elf->e_ident, ELFMAG, SELFMAG);
|
||||||
|
|
||||||
(void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
|
|
||||||
elf->e_ident[EI_CLASS] = ELF_CLASS;
|
elf->e_ident[EI_CLASS] = ELF_CLASS;
|
||||||
elf->e_ident[EI_DATA] = ELF_DATA;
|
elf->e_ident[EI_DATA] = ELF_DATA;
|
||||||
elf->e_ident[EI_VERSION] = EV_CURRENT;
|
elf->e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
|
@ -4326,95 +4261,79 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
|
||||||
bswap_ehdr(elf);
|
bswap_ehdr(elf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
|
static void fill_elf_note_phdr(struct elf_phdr *phdr, size_t sz, off_t offset)
|
||||||
{
|
{
|
||||||
phdr->p_type = PT_NOTE;
|
phdr->p_type = PT_NOTE;
|
||||||
phdr->p_offset = offset;
|
phdr->p_offset = offset;
|
||||||
phdr->p_vaddr = 0;
|
|
||||||
phdr->p_paddr = 0;
|
|
||||||
phdr->p_filesz = sz;
|
phdr->p_filesz = sz;
|
||||||
phdr->p_memsz = 0;
|
|
||||||
phdr->p_flags = 0;
|
|
||||||
phdr->p_align = 0;
|
|
||||||
|
|
||||||
bswap_phdr(phdr, 1);
|
bswap_phdr(phdr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t note_size(const struct memelfnote *note)
|
static void fill_prstatus_note(void *data, const TaskState *ts,
|
||||||
|
CPUState *cpu, int signr)
|
||||||
{
|
{
|
||||||
return (note->notesz);
|
/*
|
||||||
|
* Because note memory is only aligned to 4, and target_elf_prstatus
|
||||||
|
* may well have higher alignment requirements, fill locally and
|
||||||
|
* memcpy to the destination afterward.
|
||||||
|
*/
|
||||||
|
struct target_elf_prstatus prstatus = {
|
||||||
|
.pr_info.si_signo = signr,
|
||||||
|
.pr_cursig = signr,
|
||||||
|
.pr_pid = ts->ts_tid,
|
||||||
|
.pr_ppid = getppid(),
|
||||||
|
.pr_pgrp = getpgrp(),
|
||||||
|
.pr_sid = getsid(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
elf_core_copy_regs(&prstatus.pr_reg, cpu_env(cpu));
|
||||||
|
bswap_prstatus(&prstatus);
|
||||||
|
memcpy(data, &prstatus, sizeof(prstatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_prstatus(struct target_elf_prstatus *prstatus,
|
static void fill_prpsinfo_note(void *data, const TaskState *ts)
|
||||||
const TaskState *ts, int signr)
|
|
||||||
{
|
|
||||||
(void) memset(prstatus, 0, sizeof (*prstatus));
|
|
||||||
prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
|
|
||||||
prstatus->pr_pid = ts->ts_tid;
|
|
||||||
prstatus->pr_ppid = getppid();
|
|
||||||
prstatus->pr_pgrp = getpgrp();
|
|
||||||
prstatus->pr_sid = getsid(0);
|
|
||||||
|
|
||||||
bswap_prstatus(prstatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
|
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Because note memory is only aligned to 4, and target_elf_prpsinfo
|
||||||
|
* may well have higher alignment requirements, fill locally and
|
||||||
|
* memcpy to the destination afterward.
|
||||||
|
*/
|
||||||
|
struct target_elf_prpsinfo psinfo;
|
||||||
char *base_filename;
|
char *base_filename;
|
||||||
unsigned int i, len;
|
size_t len;
|
||||||
|
|
||||||
(void) memset(psinfo, 0, sizeof (*psinfo));
|
|
||||||
|
|
||||||
len = ts->info->env_strings - ts->info->arg_strings;
|
len = ts->info->env_strings - ts->info->arg_strings;
|
||||||
if (len >= ELF_PRARGSZ)
|
len = MIN(len, ELF_PRARGSZ);
|
||||||
len = ELF_PRARGSZ - 1;
|
memcpy(&psinfo.pr_psargs, g2h_untagged(ts->info->arg_strings), len);
|
||||||
if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
return -EFAULT;
|
if (psinfo.pr_psargs[i] == 0) {
|
||||||
|
psinfo.pr_psargs[i] = ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
if (psinfo->pr_psargs[i] == 0)
|
|
||||||
psinfo->pr_psargs[i] = ' ';
|
|
||||||
psinfo->pr_psargs[len] = 0;
|
|
||||||
|
|
||||||
psinfo->pr_pid = getpid();
|
psinfo.pr_pid = getpid();
|
||||||
psinfo->pr_ppid = getppid();
|
psinfo.pr_ppid = getppid();
|
||||||
psinfo->pr_pgrp = getpgrp();
|
psinfo.pr_pgrp = getpgrp();
|
||||||
psinfo->pr_sid = getsid(0);
|
psinfo.pr_sid = getsid(0);
|
||||||
psinfo->pr_uid = getuid();
|
psinfo.pr_uid = getuid();
|
||||||
psinfo->pr_gid = getgid();
|
psinfo.pr_gid = getgid();
|
||||||
|
|
||||||
base_filename = g_path_get_basename(ts->bprm->filename);
|
base_filename = g_path_get_basename(ts->bprm->filename);
|
||||||
/*
|
/*
|
||||||
* Using strncpy here is fine: at max-length,
|
* Using strncpy here is fine: at max-length,
|
||||||
* this field is not NUL-terminated.
|
* this field is not NUL-terminated.
|
||||||
*/
|
*/
|
||||||
(void) strncpy(psinfo->pr_fname, base_filename,
|
strncpy(psinfo.pr_fname, base_filename, sizeof(psinfo.pr_fname));
|
||||||
sizeof(psinfo->pr_fname));
|
|
||||||
|
|
||||||
g_free(base_filename);
|
g_free(base_filename);
|
||||||
bswap_psinfo(psinfo);
|
|
||||||
return (0);
|
bswap_psinfo(&psinfo);
|
||||||
|
memcpy(data, &psinfo, sizeof(psinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
|
static void fill_auxv_note(void *data, const TaskState *ts)
|
||||||
{
|
{
|
||||||
elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
|
memcpy(data, g2h_untagged(ts->info->saved_auxv), ts->info->auxv_len);
|
||||||
elf_addr_t orig_auxv = auxv;
|
|
||||||
void *ptr;
|
|
||||||
int len = ts->info->auxv_len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Auxiliary vector is stored in target process stack. It contains
|
|
||||||
* {type, value} pairs that we need to dump into note. This is not
|
|
||||||
* strictly necessary but we do it here for sake of completeness.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* read in whole auxv vector and copy it to memelfnote */
|
|
||||||
ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
|
|
||||||
if (ptr != NULL) {
|
|
||||||
fill_note(note, "CORE", NT_AUXV, len, ptr);
|
|
||||||
unlock_user(ptr, auxv, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4462,111 +4381,6 @@ static int dump_write(int fd, const void *ptr, size_t size)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_note(struct memelfnote *men, int fd)
|
|
||||||
{
|
|
||||||
struct elf_note en;
|
|
||||||
|
|
||||||
en.n_namesz = men->namesz;
|
|
||||||
en.n_type = men->type;
|
|
||||||
en.n_descsz = men->datasz;
|
|
||||||
|
|
||||||
bswap_note(&en);
|
|
||||||
|
|
||||||
if (dump_write(fd, &en, sizeof(en)) != 0)
|
|
||||||
return (-1);
|
|
||||||
if (dump_write(fd, men->name, men->namesz_rounded) != 0)
|
|
||||||
return (-1);
|
|
||||||
if (dump_write(fd, men->data, men->datasz_rounded) != 0)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
|
|
||||||
{
|
|
||||||
CPUState *cpu = env_cpu((CPUArchState *)env);
|
|
||||||
TaskState *ts = (TaskState *)cpu->opaque;
|
|
||||||
struct elf_thread_status *ets;
|
|
||||||
|
|
||||||
ets = g_malloc0(sizeof (*ets));
|
|
||||||
ets->num_notes = 1; /* only prstatus is dumped */
|
|
||||||
fill_prstatus(&ets->prstatus, ts, 0);
|
|
||||||
elf_core_copy_regs(&ets->prstatus.pr_reg, env);
|
|
||||||
fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
|
|
||||||
&ets->prstatus);
|
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
|
|
||||||
|
|
||||||
info->notes_size += note_size(&ets->notes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_note_info(struct elf_note_info *info,
|
|
||||||
int signr, const CPUArchState *env)
|
|
||||||
{
|
|
||||||
CPUState *cpu = env_cpu((CPUArchState *)env);
|
|
||||||
TaskState *ts = (TaskState *)cpu->opaque;
|
|
||||||
|
|
||||||
memset(info, 0, sizeof (*info));
|
|
||||||
QTAILQ_INIT(&info->thread_list);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* First fill in status (and registers) of current thread
|
|
||||||
* including process info & aux vector.
|
|
||||||
*/
|
|
||||||
fill_prstatus(&info->prstatus, ts, signr);
|
|
||||||
elf_core_copy_regs(&info->prstatus.pr_reg, env);
|
|
||||||
fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
|
|
||||||
sizeof(info->prstatus), &info->prstatus);
|
|
||||||
fill_psinfo(&info->psinfo, ts);
|
|
||||||
fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
|
|
||||||
sizeof(info->psinfo), &info->psinfo);
|
|
||||||
fill_auxv_note(&info->notes[2], ts);
|
|
||||||
info->numnote = 3;
|
|
||||||
|
|
||||||
info->notes_size = 0;
|
|
||||||
for (int i = 0; i < info->numnote; i++) {
|
|
||||||
info->notes_size += note_size(&info->notes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read and fill status of all threads */
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
if (cpu == thread_cpu) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fill_thread_info(info, cpu_env(cpu));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_note_info(struct elf_note_info *info)
|
|
||||||
{
|
|
||||||
struct elf_thread_status *ets;
|
|
||||||
|
|
||||||
while (!QTAILQ_EMPTY(&info->thread_list)) {
|
|
||||||
ets = QTAILQ_FIRST(&info->thread_list);
|
|
||||||
QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
|
|
||||||
g_free(ets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_note_info(struct elf_note_info *info, int fd)
|
|
||||||
{
|
|
||||||
struct elf_thread_status *ets;
|
|
||||||
int i, error = 0;
|
|
||||||
|
|
||||||
/* write prstatus, psinfo and auxv for current thread */
|
|
||||||
for (i = 0; i < info->numnote; i++)
|
|
||||||
if ((error = write_note(&info->notes[i], fd)) != 0)
|
|
||||||
return (error);
|
|
||||||
|
|
||||||
/* write prstatus for each thread */
|
|
||||||
QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
|
|
||||||
if ((error = write_note(&ets->notes[0], fd)) != 0)
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write out ELF coredump.
|
* Write out ELF coredump.
|
||||||
*
|
*
|
||||||
|
@ -4615,14 +4429,13 @@ static int elf_core_dump(int signr, const CPUArchState *env)
|
||||||
const CPUState *cpu = env_cpu((CPUArchState *)env);
|
const CPUState *cpu = env_cpu((CPUArchState *)env);
|
||||||
const TaskState *ts = (const TaskState *)cpu->opaque;
|
const TaskState *ts = (const TaskState *)cpu->opaque;
|
||||||
struct vm_area_struct *vma;
|
struct vm_area_struct *vma;
|
||||||
struct elf_note_info info;
|
|
||||||
struct elfhdr elf;
|
|
||||||
struct elf_phdr phdr;
|
|
||||||
struct rlimit dumpsize;
|
struct rlimit dumpsize;
|
||||||
struct mm_struct mm;
|
struct mm_struct mm;
|
||||||
off_t offset, note_offset, data_offset;
|
off_t offset, note_offset, data_offset;
|
||||||
|
size_t note_size;
|
||||||
int segs, cpus, ret;
|
int segs, cpus, ret;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
CPUState *cpu_iter;
|
||||||
|
|
||||||
if (prctl(PR_GET_DUMPABLE) == 0) {
|
if (prctl(PR_GET_DUMPABLE) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4644,7 +4457,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
|
||||||
segs = vma_get_mapping_count(&mm);
|
segs = vma_get_mapping_count(&mm);
|
||||||
|
|
||||||
cpus = 0;
|
cpus = 0;
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu_iter) {
|
||||||
cpus++;
|
cpus++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4655,6 +4468,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
|
||||||
offset += size_note("CORE", ts->info->auxv_len);
|
offset += size_note("CORE", ts->info->auxv_len);
|
||||||
offset += size_note("CORE", sizeof(struct target_elf_prpsinfo));
|
offset += size_note("CORE", sizeof(struct target_elf_prpsinfo));
|
||||||
offset += size_note("CORE", sizeof(struct target_elf_prstatus)) * cpus;
|
offset += size_note("CORE", sizeof(struct target_elf_prstatus)) * cpus;
|
||||||
|
note_size = offset - note_offset;
|
||||||
offset = ROUND_UP(offset, ELF_EXEC_PAGESIZE);
|
offset = ROUND_UP(offset, ELF_EXEC_PAGESIZE);
|
||||||
data_offset = offset;
|
data_offset = offset;
|
||||||
|
|
||||||
|
@ -4678,61 +4492,64 @@ static int elf_core_dump(int signr, const CPUArchState *env)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct valid coredump ELF header. We also
|
* There is a fair amount of alignment padding within the notes
|
||||||
* add one more segment for notes.
|
* as well as preceeding the process memory. Allocate a zeroed
|
||||||
|
* block to hold it all. Write all of the headers directly into
|
||||||
|
* this buffer and then write it out as a block.
|
||||||
*/
|
*/
|
||||||
fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
|
{
|
||||||
if (dump_write(fd, &elf, sizeof (elf)) != 0)
|
g_autofree void *header = g_malloc0(data_offset);
|
||||||
goto out;
|
void *hptr, *dptr;
|
||||||
|
|
||||||
/* fill in the in-memory version of notes */
|
/* Create elf file header. */
|
||||||
fill_note_info(&info, signr, env);
|
hptr = header;
|
||||||
|
fill_elf_header(hptr, segs + 1, ELF_MACHINE, 0);
|
||||||
|
hptr += sizeof(struct elfhdr);
|
||||||
|
|
||||||
/* write out notes program header */
|
/* Create elf program headers. */
|
||||||
fill_elf_note_phdr(&phdr, info.notes_size, note_offset);
|
fill_elf_note_phdr(hptr, note_size, note_offset);
|
||||||
|
hptr += sizeof(struct elf_phdr);
|
||||||
|
|
||||||
if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
|
offset = data_offset;
|
||||||
goto out;
|
for (vma = vma_first(&mm); vma != NULL; vma = vma_next(vma)) {
|
||||||
|
struct elf_phdr *phdr = hptr;
|
||||||
|
|
||||||
/*
|
phdr->p_type = PT_LOAD;
|
||||||
* Write program headers for memory regions mapped in
|
phdr->p_offset = offset;
|
||||||
* the target process.
|
phdr->p_vaddr = vma->vma_start;
|
||||||
*/
|
phdr->p_paddr = 0;
|
||||||
offset = data_offset;
|
phdr->p_filesz = vma_dump_size(vma);
|
||||||
for (vma = vma_first(&mm); vma != NULL; vma = vma_next(vma)) {
|
offset += phdr->p_filesz;
|
||||||
(void) memset(&phdr, 0, sizeof (phdr));
|
phdr->p_memsz = vma->vma_end - vma->vma_start;
|
||||||
|
phdr->p_flags = (vma->vma_flags & PROT_READ ? PF_R : 0)
|
||||||
|
| (vma->vma_flags & PROT_WRITE ? PF_W : 0)
|
||||||
|
| (vma->vma_flags & PROT_EXEC ? PF_X : 0);
|
||||||
|
phdr->p_align = ELF_EXEC_PAGESIZE;
|
||||||
|
|
||||||
phdr.p_type = PT_LOAD;
|
bswap_phdr(phdr, 1);
|
||||||
phdr.p_offset = offset;
|
hptr += sizeof(struct elf_phdr);
|
||||||
phdr.p_vaddr = vma->vma_start;
|
}
|
||||||
phdr.p_paddr = 0;
|
|
||||||
phdr.p_filesz = vma_dump_size(vma);
|
|
||||||
offset += phdr.p_filesz;
|
|
||||||
phdr.p_memsz = vma->vma_end - vma->vma_start;
|
|
||||||
phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
|
|
||||||
if (vma->vma_flags & PROT_WRITE)
|
|
||||||
phdr.p_flags |= PF_W;
|
|
||||||
if (vma->vma_flags & PROT_EXEC)
|
|
||||||
phdr.p_flags |= PF_X;
|
|
||||||
phdr.p_align = ELF_EXEC_PAGESIZE;
|
|
||||||
|
|
||||||
bswap_phdr(&phdr, 1);
|
/* Create the notes. */
|
||||||
if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
|
dptr = fill_note(&hptr, NT_AUXV, "CORE", ts->info->auxv_len);
|
||||||
|
fill_auxv_note(dptr, ts);
|
||||||
|
|
||||||
|
dptr = fill_note(&hptr, NT_PRPSINFO, "CORE",
|
||||||
|
sizeof(struct target_elf_prpsinfo));
|
||||||
|
fill_prpsinfo_note(dptr, ts);
|
||||||
|
|
||||||
|
CPU_FOREACH(cpu_iter) {
|
||||||
|
dptr = fill_note(&hptr, NT_PRSTATUS, "CORE",
|
||||||
|
sizeof(struct target_elf_prstatus));
|
||||||
|
fill_prstatus_note(dptr, ts, cpu_iter,
|
||||||
|
cpu_iter == cpu ? signr : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dump_write(fd, header, data_offset) < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Next we write notes just after program headers. No
|
|
||||||
* alignment needed here.
|
|
||||||
*/
|
|
||||||
if (write_note_info(&info, fd) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* align data to page boundary */
|
|
||||||
if (lseek(fd, data_offset, SEEK_SET) != data_offset)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally we can dump process memory into corefile as well.
|
* Finally we can dump process memory into corefile as well.
|
||||||
*/
|
*/
|
||||||
|
@ -4768,7 +4585,6 @@ static int elf_core_dump(int signr, const CPUArchState *env)
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
cpu_list_unlock();
|
cpu_list_unlock();
|
||||||
free_note_info(&info);
|
|
||||||
vma_delete(&mm);
|
vma_delete(&mm);
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue