Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/imgact_elf.c
Show First 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | |||||
SYSCTL_BOOL(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, allow_wx, | SYSCTL_BOOL(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, allow_wx, | ||||
CTLFLAG_RWTUN, &__elfN(allow_wx), 0, | CTLFLAG_RWTUN, &__elfN(allow_wx), 0, | ||||
"Allow pages to be mapped simultaneously writable and executable"); | "Allow pages to be mapped simultaneously writable and executable"); | ||||
static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; | static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; | ||||
#define aligned(a, t) (rounddown2((u_long)(a), sizeof(t)) == (u_long)(a)) | #define aligned(a, t) (rounddown2((u_long)(a), sizeof(t)) == (u_long)(a)) | ||||
static const char FREEBSD_ABI_VENDOR[] = "FreeBSD"; | |||||
Elf_Brandnote __elfN(freebsd_brandnote) = { | Elf_Brandnote __elfN(freebsd_brandnote) = { | ||||
.hdr.n_namesz = sizeof(FREEBSD_ABI_VENDOR), | .hdr.n_namesz = sizeof(FREEBSD_ABI_VENDOR), | ||||
.hdr.n_descsz = sizeof(int32_t), | .hdr.n_descsz = sizeof(int32_t), | ||||
.hdr.n_type = NT_FREEBSD_ABI_TAG, | .hdr.n_type = NT_FREEBSD_ABI_TAG, | ||||
.vendor = FREEBSD_ABI_VENDOR, | .vendor = FREEBSD_ABI_VENDOR, | ||||
.flags = BN_TRANSLATE_OSREL, | .flags = BN_TRANSLATE_OSREL, | ||||
.trans_osrel = __elfN(freebsd_trans_osrel) | .trans_osrel = __elfN(freebsd_trans_osrel) | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 1,219 Lines • ▼ Show 20 Lines | |||||
typedef void (*segment_callback)(vm_map_entry_t, void *); | typedef void (*segment_callback)(vm_map_entry_t, void *); | ||||
/* Closure for cb_put_phdr(). */ | /* Closure for cb_put_phdr(). */ | ||||
struct phdr_closure { | struct phdr_closure { | ||||
Elf_Phdr *phdr; /* Program header to fill in */ | Elf_Phdr *phdr; /* Program header to fill in */ | ||||
Elf_Off offset; /* Offset of segment in core file */ | Elf_Off offset; /* Offset of segment in core file */ | ||||
}; | }; | ||||
typedef void (*outfunc_t)(void *, struct sbuf *, size_t *); | |||||
struct note_info { | struct note_info { | ||||
int type; /* Note type. */ | int type; /* Note type. */ | ||||
outfunc_t outfunc; /* Output function. */ | outfunc_t outfunc; /* Output function. */ | ||||
void *outarg; /* Argument for the output function. */ | void *outarg; /* Argument for the output function. */ | ||||
size_t outsize; /* Output size. */ | size_t outsize; /* Output size. */ | ||||
TAILQ_ENTRY(note_info) link; /* Link to the next note info. */ | TAILQ_ENTRY(note_info) link; /* Link to the next note info. */ | ||||
}; | }; | ||||
TAILQ_HEAD(note_info_list, note_info); | TAILQ_HEAD(note_info_list, note_info); | ||||
extern int compress_user_cores; | extern int compress_user_cores; | ||||
extern int compress_user_cores_level; | extern int compress_user_cores_level; | ||||
static void cb_put_phdr(vm_map_entry_t, void *); | static void cb_put_phdr(vm_map_entry_t, void *); | ||||
static void cb_size_segment(vm_map_entry_t, void *); | static void cb_size_segment(vm_map_entry_t, void *); | ||||
static void each_dumpable_segment(struct thread *, segment_callback, void *, | static void each_dumpable_segment(struct thread *, segment_callback, void *, | ||||
int); | int); | ||||
static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t, | static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t, | ||||
struct note_info_list *, size_t, int); | struct note_info_list *, size_t, int); | ||||
static void __elfN(prepare_notes)(struct thread *, struct note_info_list *, | static void __elfN(putnote)(struct thread *td, struct note_info *, struct sbuf *); | ||||
size_t *); | |||||
static void __elfN(putnote)(struct note_info *, struct sbuf *); | |||||
static size_t register_note(struct note_info_list *, int, outfunc_t, void *); | |||||
static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *); | static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *); | static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *); | static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *); | static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *); | static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_ptlwpinfo)(void *, struct sbuf *, size_t *); | static void __elfN(note_ptlwpinfo)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); | static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); | ||||
Show All 34 Lines | __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) | ||||
__elfN(size_segments)(td, &seginfo, flags); | __elfN(size_segments)(td, &seginfo, flags); | ||||
/* | /* | ||||
* Collect info about the core file header area. | * Collect info about the core file header area. | ||||
*/ | */ | ||||
hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count); | hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count); | ||||
if (seginfo.count + 1 >= PN_XNUM) | if (seginfo.count + 1 >= PN_XNUM) | ||||
hdrsize += sizeof(Elf_Shdr); | hdrsize += sizeof(Elf_Shdr); | ||||
__elfN(prepare_notes)(td, ¬elst, ¬esz); | td->td_proc->p_sysent->sv_elf_core_prepare_notes(td, ¬elst, ¬esz); | ||||
coresize = round_page(hdrsize + notesz) + seginfo.size; | coresize = round_page(hdrsize + notesz) + seginfo.size; | ||||
/* Set up core dump parameters. */ | /* Set up core dump parameters. */ | ||||
params.offset = 0; | params.offset = 0; | ||||
params.active_cred = cred; | params.active_cred = cred; | ||||
params.file_cred = NOCRED; | params.file_cred = NOCRED; | ||||
params.td = td; | params.td = td; | ||||
params.vp = vp; | params.vp = vp; | ||||
▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | __elfN(corehdr)(struct coredump_params *p, int numsegs, void *hdr, | ||||
bzero(hdr, hdrsize); | bzero(hdr, hdrsize); | ||||
__elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz, flags); | __elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz, flags); | ||||
sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN); | sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN); | ||||
sbuf_set_drain(sb, sbuf_drain_core_output, p); | sbuf_set_drain(sb, sbuf_drain_core_output, p); | ||||
sbuf_start_section(sb, NULL); | sbuf_start_section(sb, NULL); | ||||
sbuf_bcat(sb, hdr, hdrsize); | sbuf_bcat(sb, hdr, hdrsize); | ||||
TAILQ_FOREACH(ninfo, notelst, link) | TAILQ_FOREACH(ninfo, notelst, link) | ||||
__elfN(putnote)(ninfo, sb); | __elfN(putnote)(p->td, ninfo, sb); | ||||
/* Align up to a page boundary for the program segments. */ | /* Align up to a page boundary for the program segments. */ | ||||
sbuf_end_section(sb, -1, PAGE_SIZE, 0); | sbuf_end_section(sb, -1, PAGE_SIZE, 0); | ||||
error = sbuf_finish(sb); | error = sbuf_finish(sb); | ||||
sbuf_delete(sb); | sbuf_delete(sb); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | void | ||||
__elfN(prepare_notes)(struct thread *td, struct note_info_list *list, | __elfN(prepare_notes)(struct thread *td, struct note_info_list *list, | ||||
size_t *sizep) | size_t *sizep) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct thread *thr; | struct thread *thr; | ||||
size_t size; | size_t size; | ||||
p = td->td_proc; | p = td->td_proc; | ||||
size = 0; | size = 0; | ||||
size += register_note(list, NT_PRPSINFO, __elfN(note_prpsinfo), p); | size += __elfN(register_note)(td, list, NT_PRPSINFO, __elfN(note_prpsinfo), p); | ||||
/* | /* | ||||
* To have the debugger select the right thread (LWP) as the initial | * To have the debugger select the right thread (LWP) as the initial | ||||
* thread, we dump the state of the thread passed to us in td first. | * thread, we dump the state of the thread passed to us in td first. | ||||
* This is the thread that causes the core dump and thus likely to | * This is the thread that causes the core dump and thus likely to | ||||
* be the right thread one wants to have selected in the debugger. | * be the right thread one wants to have selected in the debugger. | ||||
*/ | */ | ||||
thr = td; | thr = td; | ||||
while (thr != NULL) { | while (thr != NULL) { | ||||
size += register_note(list, NT_PRSTATUS, | size += __elfN(register_note)(td, list, NT_PRSTATUS, | ||||
__elfN(note_prstatus), thr); | __elfN(note_prstatus), thr); | ||||
size += register_note(list, NT_FPREGSET, | size += __elfN(register_note)(td, list, NT_FPREGSET, | ||||
__elfN(note_fpregset), thr); | __elfN(note_fpregset), thr); | ||||
size += register_note(list, NT_THRMISC, | size += __elfN(register_note)(td, list, NT_THRMISC, | ||||
__elfN(note_thrmisc), thr); | __elfN(note_thrmisc), thr); | ||||
size += register_note(list, NT_PTLWPINFO, | size += __elfN(register_note)(td, list, NT_PTLWPINFO, | ||||
__elfN(note_ptlwpinfo), thr); | __elfN(note_ptlwpinfo), thr); | ||||
size += register_note(list, -1, | size += __elfN(register_note)(td, list, -1, | ||||
__elfN(note_threadmd), thr); | __elfN(note_threadmd), thr); | ||||
thr = thr == td ? TAILQ_FIRST(&p->p_threads) : | thr = thr == td ? TAILQ_FIRST(&p->p_threads) : | ||||
TAILQ_NEXT(thr, td_plist); | TAILQ_NEXT(thr, td_plist); | ||||
if (thr == td) | if (thr == td) | ||||
thr = TAILQ_NEXT(thr, td_plist); | thr = TAILQ_NEXT(thr, td_plist); | ||||
} | } | ||||
size += register_note(list, NT_PROCSTAT_PROC, | size += __elfN(register_note)(td, list, NT_PROCSTAT_PROC, | ||||
__elfN(note_procstat_proc), p); | __elfN(note_procstat_proc), p); | ||||
size += register_note(list, NT_PROCSTAT_FILES, | size += __elfN(register_note)(td, list, NT_PROCSTAT_FILES, | ||||
note_procstat_files, p); | note_procstat_files, p); | ||||
size += register_note(list, NT_PROCSTAT_VMMAP, | size += __elfN(register_note)(td, list, NT_PROCSTAT_VMMAP, | ||||
note_procstat_vmmap, p); | note_procstat_vmmap, p); | ||||
size += register_note(list, NT_PROCSTAT_GROUPS, | size += __elfN(register_note)(td, list, NT_PROCSTAT_GROUPS, | ||||
note_procstat_groups, p); | note_procstat_groups, p); | ||||
size += register_note(list, NT_PROCSTAT_UMASK, | size += __elfN(register_note)(td, list, NT_PROCSTAT_UMASK, | ||||
note_procstat_umask, p); | note_procstat_umask, p); | ||||
size += register_note(list, NT_PROCSTAT_RLIMIT, | size += __elfN(register_note)(td, list, NT_PROCSTAT_RLIMIT, | ||||
note_procstat_rlimit, p); | note_procstat_rlimit, p); | ||||
size += register_note(list, NT_PROCSTAT_OSREL, | size += __elfN(register_note)(td, list, NT_PROCSTAT_OSREL, | ||||
note_procstat_osrel, p); | note_procstat_osrel, p); | ||||
size += register_note(list, NT_PROCSTAT_PSSTRINGS, | size += __elfN(register_note)(td, list, NT_PROCSTAT_PSSTRINGS, | ||||
__elfN(note_procstat_psstrings), p); | __elfN(note_procstat_psstrings), p); | ||||
size += register_note(list, NT_PROCSTAT_AUXV, | size += __elfN(register_note)(td, list, NT_PROCSTAT_AUXV, | ||||
__elfN(note_procstat_auxv), p); | __elfN(note_procstat_auxv), p); | ||||
*sizep = size; | *sizep = size; | ||||
} | } | ||||
void | void | ||||
__elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs, | __elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs, | ||||
size_t notesz, int flags) | size_t notesz, int flags) | ||||
{ | { | ||||
Elf_Ehdr *ehdr; | Elf_Ehdr *ehdr; | ||||
Elf_Phdr *phdr; | Elf_Phdr *phdr; | ||||
Elf_Shdr *shdr; | Elf_Shdr *shdr; | ||||
struct phdr_closure phc; | struct phdr_closure phc; | ||||
ehdr = (Elf_Ehdr *)hdr; | ehdr = (Elf_Ehdr *)hdr; | ||||
ehdr->e_ident[EI_MAG0] = ELFMAG0; | ehdr->e_ident[EI_MAG0] = ELFMAG0; | ||||
ehdr->e_ident[EI_MAG1] = ELFMAG1; | ehdr->e_ident[EI_MAG1] = ELFMAG1; | ||||
ehdr->e_ident[EI_MAG2] = ELFMAG2; | ehdr->e_ident[EI_MAG2] = ELFMAG2; | ||||
ehdr->e_ident[EI_MAG3] = ELFMAG3; | ehdr->e_ident[EI_MAG3] = ELFMAG3; | ||||
ehdr->e_ident[EI_CLASS] = ELF_CLASS; | ehdr->e_ident[EI_CLASS] = ELF_CLASS; | ||||
ehdr->e_ident[EI_DATA] = ELF_DATA; | ehdr->e_ident[EI_DATA] = ELF_DATA; | ||||
ehdr->e_ident[EI_VERSION] = EV_CURRENT; | ehdr->e_ident[EI_VERSION] = EV_CURRENT; | ||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | ehdr->e_ident[EI_OSABI] = td->td_proc->p_sysent->sv_elf_core_osabi; | ||||
ehdr->e_ident[EI_ABIVERSION] = 0; | ehdr->e_ident[EI_ABIVERSION] = 0; | ||||
ehdr->e_ident[EI_PAD] = 0; | ehdr->e_ident[EI_PAD] = 0; | ||||
ehdr->e_type = ET_CORE; | ehdr->e_type = ET_CORE; | ||||
ehdr->e_machine = td->td_proc->p_elf_machine; | ehdr->e_machine = td->td_proc->p_elf_machine; | ||||
ehdr->e_version = EV_CURRENT; | ehdr->e_version = EV_CURRENT; | ||||
ehdr->e_entry = 0; | ehdr->e_entry = 0; | ||||
ehdr->e_phoff = sizeof(Elf_Ehdr); | ehdr->e_phoff = sizeof(Elf_Ehdr); | ||||
ehdr->e_flags = td->td_proc->p_elf_flags; | ehdr->e_flags = td->td_proc->p_elf_flags; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | __elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs, | ||||
phdr++; | phdr++; | ||||
/* All the writable segments from the program. */ | /* All the writable segments from the program. */ | ||||
phc.phdr = phdr; | phc.phdr = phdr; | ||||
phc.offset = round_page(hdrsize + notesz); | phc.offset = round_page(hdrsize + notesz); | ||||
each_dumpable_segment(td, cb_put_phdr, &phc, flags); | each_dumpable_segment(td, cb_put_phdr, &phc, flags); | ||||
} | } | ||||
static size_t | size_t | ||||
register_note(struct note_info_list *list, int type, outfunc_t out, void *arg) | __elfN(register_note)(struct thread *td, struct note_info_list *list, | ||||
int type, outfunc_t out, void *arg) | |||||
{ | { | ||||
const struct sysentvec *sv; | |||||
struct note_info *ninfo; | struct note_info *ninfo; | ||||
size_t size, notesize; | size_t size, notesize; | ||||
sv = td->td_proc->p_sysent; | |||||
size = 0; | size = 0; | ||||
out(arg, NULL, &size); | out(arg, NULL, &size); | ||||
ninfo = malloc(sizeof(*ninfo), M_TEMP, M_ZERO | M_WAITOK); | ninfo = malloc(sizeof(*ninfo), M_TEMP, M_ZERO | M_WAITOK); | ||||
ninfo->type = type; | ninfo->type = type; | ||||
ninfo->outfunc = out; | ninfo->outfunc = out; | ||||
ninfo->outarg = arg; | ninfo->outarg = arg; | ||||
ninfo->outsize = size; | ninfo->outsize = size; | ||||
TAILQ_INSERT_TAIL(list, ninfo, link); | TAILQ_INSERT_TAIL(list, ninfo, link); | ||||
if (type == -1) | if (type == -1) | ||||
return (size); | return (size); | ||||
notesize = sizeof(Elf_Note) + /* note header */ | notesize = sizeof(Elf_Note) + /* note header */ | ||||
roundup2(sizeof(FREEBSD_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) + | roundup2(strlen(sv->sv_elf_core_abi_vendor) + 1, ELF_NOTE_ROUNDSIZE) + | ||||
/* note name */ | /* note name */ | ||||
roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ | roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ | ||||
return (notesize); | return (notesize); | ||||
} | } | ||||
static size_t | static size_t | ||||
append_note_data(const void *src, void *dst, size_t len) | append_note_data(const void *src, void *dst, size_t len) | ||||
Show All 33 Lines | notesize = sizeof(Elf_Note) + /* note header */ | ||||
roundup2(sizeof(FREEBSD_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) + | roundup2(sizeof(FREEBSD_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) + | ||||
/* note name */ | /* note name */ | ||||
roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ | roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ | ||||
return (notesize); | return (notesize); | ||||
} | } | ||||
static void | static void | ||||
__elfN(putnote)(struct note_info *ninfo, struct sbuf *sb) | __elfN(putnote)(struct thread *td, struct note_info *ninfo, struct sbuf *sb) | ||||
{ | { | ||||
Elf_Note note; | Elf_Note note; | ||||
const struct sysentvec *sv; | |||||
ssize_t old_len, sect_len; | ssize_t old_len, sect_len; | ||||
size_t new_len, descsz, i; | size_t new_len, descsz, i; | ||||
if (ninfo->type == -1) { | if (ninfo->type == -1) { | ||||
ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); | ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); | ||||
return; | return; | ||||
} | } | ||||
note.n_namesz = sizeof(FREEBSD_ABI_VENDOR); | sv = td->td_proc->p_sysent; | ||||
note.n_namesz = strlen(sv->sv_elf_core_abi_vendor) + 1; | |||||
note.n_descsz = ninfo->outsize; | note.n_descsz = ninfo->outsize; | ||||
note.n_type = ninfo->type; | note.n_type = ninfo->type; | ||||
sbuf_bcat(sb, ¬e, sizeof(note)); | sbuf_bcat(sb, ¬e, sizeof(note)); | ||||
sbuf_start_section(sb, &old_len); | sbuf_start_section(sb, &old_len); | ||||
sbuf_bcat(sb, FREEBSD_ABI_VENDOR, sizeof(FREEBSD_ABI_VENDOR)); | sbuf_bcat(sb, sv->sv_elf_core_abi_vendor, | ||||
strlen(sv->sv_elf_core_abi_vendor) + 1); | |||||
sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); | sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); | ||||
if (note.n_descsz == 0) | if (note.n_descsz == 0) | ||||
return; | return; | ||||
sbuf_start_section(sb, &old_len); | sbuf_start_section(sb, &old_len); | ||||
ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); | ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); | ||||
sect_len = sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); | sect_len = sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); | ||||
if (sect_len < 0) | if (sect_len < 0) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 712 Lines • Show Last 20 Lines |