mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
- Split up m_ume.c into m_ume/{main,elf,script}.c. This will make merging
the DARWIN branch easier later. - Remove the disabled vgtest_ume test, it's very unlikely it'll ever work again. - Move VG_(find_auxv) to initimg-linux.c, the only place it's used, and make it static. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9004
This commit is contained in:
parent
74e8c02cea
commit
c07262448b
@ -140,6 +140,7 @@ noinst_HEADERS = \
|
||||
pub_core_vkiscnums.h \
|
||||
pub_core_wordfm.h \
|
||||
pub_core_xarray.h \
|
||||
m_aspacemgr/priv_aspacemgr.h \
|
||||
m_coredump/priv_elf.h \
|
||||
m_debuginfo/priv_misc.h \
|
||||
m_debuginfo/priv_storage.h \
|
||||
@ -163,7 +164,7 @@ noinst_HEADERS = \
|
||||
m_syswrap/priv_syswrap-linux-variants.h \
|
||||
m_syswrap/priv_syswrap-aix5.h \
|
||||
m_syswrap/priv_syswrap-main.h \
|
||||
m_aspacemgr/priv_aspacemgr.h \
|
||||
m_ume/priv_ume.h \
|
||||
launcher-aix5-bootblock.h \
|
||||
m_initimg/simple_huffman.c
|
||||
|
||||
@ -203,7 +204,6 @@ COREGRIND_SOURCES_COMMON = \
|
||||
m_trampoline.S \
|
||||
m_translate.c \
|
||||
m_transtab.c \
|
||||
m_ume.c \
|
||||
m_vki.c \
|
||||
m_vkiscnums.c \
|
||||
m_wordfm.c \
|
||||
@ -222,7 +222,10 @@ COREGRIND_SOURCES_COMMON = \
|
||||
m_replacemalloc/replacemalloc_core.c \
|
||||
m_scheduler/scheduler.c \
|
||||
m_scheduler/sema.c \
|
||||
m_syswrap/syswrap-main.c
|
||||
m_syswrap/syswrap-main.c \
|
||||
m_ume/elf.c \
|
||||
m_ume/main.c \
|
||||
m_ume/script.c
|
||||
|
||||
COREGRIND_LINUX_SOURCE = \
|
||||
m_coredump/coredump-elf.c \
|
||||
|
||||
@ -412,6 +412,38 @@ static char *copy_str(char **tab, const char *str)
|
||||
|
||||
---------------------------------------------------------------- */
|
||||
|
||||
struct auxv
|
||||
{
|
||||
Word a_type;
|
||||
union {
|
||||
void *a_ptr;
|
||||
Word a_val;
|
||||
} u;
|
||||
};
|
||||
|
||||
static
|
||||
struct auxv *find_auxv(UWord* sp)
|
||||
{
|
||||
sp++; // skip argc (Nb: is word-sized, not int-sized!)
|
||||
|
||||
while (*sp != 0) // skip argv
|
||||
sp++;
|
||||
sp++;
|
||||
|
||||
while (*sp != 0) // skip env
|
||||
sp++;
|
||||
sp++;
|
||||
|
||||
#if defined(VGA_ppc32) || defined(VGA_ppc64)
|
||||
# if defined AT_IGNOREPPC
|
||||
while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
|
||||
sp += 2;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return (struct auxv *)sp;
|
||||
}
|
||||
|
||||
static
|
||||
Addr setup_client_stack( void* init_sp,
|
||||
char** orig_envp,
|
||||
@ -425,9 +457,9 @@ Addr setup_client_stack( void* init_sp,
|
||||
char *strtab; /* string table */
|
||||
char *stringbase;
|
||||
Addr *ptr;
|
||||
struct ume_auxv *auxv;
|
||||
const struct ume_auxv *orig_auxv;
|
||||
const struct ume_auxv *cauxv;
|
||||
struct auxv *auxv;
|
||||
const struct auxv *orig_auxv;
|
||||
const struct auxv *cauxv;
|
||||
unsigned stringsize; /* total size of strings in bytes */
|
||||
unsigned auxsize; /* total size of auxv in bytes */
|
||||
Int argc; /* total argc */
|
||||
@ -442,7 +474,7 @@ Addr setup_client_stack( void* init_sp,
|
||||
vg_assert( VG_(args_for_client) );
|
||||
|
||||
/* use our own auxv as a prototype */
|
||||
orig_auxv = VG_(find_auxv)(init_sp);
|
||||
orig_auxv = find_auxv(init_sp);
|
||||
|
||||
/* ==================== compute sizes ==================== */
|
||||
|
||||
@ -636,7 +668,7 @@ Addr setup_client_stack( void* init_sp,
|
||||
*ptr++ = 0;
|
||||
|
||||
/* --- auxv --- */
|
||||
auxv = (struct ume_auxv *)ptr;
|
||||
auxv = (struct auxv *)ptr;
|
||||
*client_auxv = (UInt *)auxv;
|
||||
|
||||
# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- User-mode execve(), and other stuff shared between stage1 ---*/
|
||||
/*--- and stage2. m_ume.c ---*/
|
||||
/*--- User-mode execve() for ELF executables m_ume_elf.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -29,24 +28,24 @@
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "pub_core_basics.h"
|
||||
#include "pub_core_vki.h"
|
||||
|
||||
#if defined(VGO_linux)
|
||||
|
||||
#include "pub_core_aspacemgr.h" // various mapping fns
|
||||
#include "pub_core_aspacemgr.h" // various mapping fns
|
||||
#include "pub_core_debuglog.h"
|
||||
#include "pub_core_libcbase.h"
|
||||
#include "pub_core_machine.h"
|
||||
#include "pub_core_libcassert.h" // VG_(exit), vg_assert
|
||||
#include "pub_core_libcbase.h" // VG_(memcmp), etc
|
||||
#include "pub_core_libcprint.h"
|
||||
#include "pub_core_libcfile.h" // VG_(close) et al
|
||||
#include "pub_core_libcproc.h" // VG_(geteuid), VG_(getegid)
|
||||
#include "pub_core_libcassert.h" // VG_(exit), vg_assert
|
||||
#include "pub_core_mallocfree.h" // VG_(malloc), VG_(free)
|
||||
#include "pub_core_syscall.h" // VG_(strerror)
|
||||
#include "pub_core_options.h" // VG_(clo_xml)
|
||||
#include "pub_core_ume.h" // self
|
||||
#include "pub_core_libcfile.h" // VG_(open) et al
|
||||
#include "pub_core_machine.h" // VG_ELF_CLASS (XXX: which should be moved)
|
||||
#include "pub_core_mallocfree.h" // VG_(malloc), VG_(free)
|
||||
#include "pub_core_syscall.h" // VG_(strerror)
|
||||
#include "pub_core_ume.h" // self
|
||||
|
||||
#include "priv_ume.h"
|
||||
|
||||
|
||||
#if defined(HAVE_ELF)
|
||||
|
||||
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
|
||||
#define _GNU_SOURCE
|
||||
@ -56,19 +55,19 @@
|
||||
/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
|
||||
|
||||
|
||||
#if VG_WORDSIZE == 8
|
||||
#define ESZ(x) Elf64_##x
|
||||
#elif VG_WORDSIZE == 4
|
||||
#define ESZ(x) Elf32_##x
|
||||
#if VG_WORDSIZE == 8
|
||||
#define ESZ(x) Elf64_##x
|
||||
#elif VG_WORDSIZE == 4
|
||||
#define ESZ(x) Elf32_##x
|
||||
#else
|
||||
#error VG_WORDSIZE needs to ==4 or ==8
|
||||
#endif
|
||||
|
||||
struct elfinfo
|
||||
{
|
||||
ESZ(Ehdr) e;
|
||||
ESZ(Phdr) *p;
|
||||
Int fd;
|
||||
ESZ(Ehdr) e;
|
||||
ESZ(Phdr) *p;
|
||||
Int fd;
|
||||
};
|
||||
|
||||
static void check_mmap(SysRes res, Addr base, SizeT len)
|
||||
@ -86,32 +85,6 @@ static void check_mmap(SysRes res, Addr base, SizeT len)
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Finding auxv on the stack ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
struct ume_auxv *VG_(find_auxv)(UWord* sp)
|
||||
{
|
||||
sp++; // skip argc (Nb: is word-sized, not int-sized!)
|
||||
|
||||
while (*sp != 0) // skip argv
|
||||
sp++;
|
||||
sp++;
|
||||
|
||||
while (*sp != 0) // skip env
|
||||
sp++;
|
||||
sp++;
|
||||
|
||||
#if defined(VGA_ppc32) || defined(VGA_ppc64)
|
||||
# if defined AT_IGNOREPPC
|
||||
while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
|
||||
sp += 2;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return (struct ume_auxv *)sp;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Loading ELF files ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
@ -189,23 +162,23 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
|
||||
SysRes res;
|
||||
ESZ(Addr) elfbrk = 0;
|
||||
|
||||
for(i = 0; i < e->e.e_phnum; i++) {
|
||||
for (i = 0; i < e->e.e_phnum; i++) {
|
||||
ESZ(Phdr) *ph = &e->p[i];
|
||||
ESZ(Addr) addr, brkaddr;
|
||||
ESZ(Word) memsz;
|
||||
|
||||
if (ph->p_type != PT_LOAD)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
addr = ph->p_vaddr+base;
|
||||
memsz = ph->p_memsz;
|
||||
brkaddr = addr+memsz;
|
||||
|
||||
if (brkaddr > elfbrk)
|
||||
elfbrk = brkaddr;
|
||||
elfbrk = brkaddr;
|
||||
}
|
||||
|
||||
for(i = 0; i < e->e.e_phnum; i++) {
|
||||
for (i = 0; i < e->e.e_phnum; i++) {
|
||||
ESZ(Phdr) *ph = &e->p[i];
|
||||
ESZ(Addr) addr, bss, brkaddr;
|
||||
ESZ(Off) off;
|
||||
@ -214,7 +187,7 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
|
||||
unsigned prot = 0;
|
||||
|
||||
if (ph->p_type != PT_LOAD)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
if (ph->p_flags & PF_X) prot |= VKI_PROT_EXEC;
|
||||
if (ph->p_flags & PF_W) prot |= VKI_PROT_WRITE;
|
||||
@ -248,33 +221,33 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
|
||||
|
||||
// if memsz > filesz, fill the remainder with zeroed pages
|
||||
if (memsz > filesz) {
|
||||
UInt bytes;
|
||||
UInt bytes;
|
||||
|
||||
bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
|
||||
if (bytes > 0) {
|
||||
bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
|
||||
if (bytes > 0) {
|
||||
if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n");
|
||||
res = VG_(am_mmap_anon_fixed_client)(
|
||||
res = VG_(am_mmap_anon_fixed_client)(
|
||||
VG_PGROUNDUP(bss), bytes,
|
||||
prot
|
||||
prot
|
||||
);
|
||||
if (0) VG_(am_show_nsegments)(0,"after #2");
|
||||
check_mmap(res, VG_PGROUNDUP(bss), bytes);
|
||||
}
|
||||
|
||||
bytes = bss & (VKI_PAGE_SIZE - 1);
|
||||
bytes = bss & (VKI_PAGE_SIZE - 1);
|
||||
|
||||
// The 'prot' condition allows for a read-only bss
|
||||
if ((prot & VKI_PROT_WRITE) && (bytes > 0)) {
|
||||
bytes = VKI_PAGE_SIZE - bytes;
|
||||
VG_(memset)((char *)bss, 0, bytes);
|
||||
}
|
||||
bytes = VKI_PAGE_SIZE - bytes;
|
||||
VG_(memset)((char *)bss, 0, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elfbrk;
|
||||
}
|
||||
|
||||
static Bool match_ELF(const char *hdr, Int len)
|
||||
Bool VG_(match_ELF)(Char *hdr, Int len)
|
||||
{
|
||||
ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
|
||||
return (len > sizeof(*e)) && VG_(memcmp)(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
|
||||
@ -324,15 +297,15 @@ static Bool match_ELF(const char *hdr, Int len)
|
||||
|
||||
- The entry point in INFO is set to the interpreter's entry point,
|
||||
and we're done. */
|
||||
static Int load_ELF(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
|
||||
Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
|
||||
{
|
||||
SysRes sres;
|
||||
struct elfinfo *e;
|
||||
struct elfinfo *interp = NULL;
|
||||
ESZ(Addr) minaddr = ~0; /* lowest mapped address */
|
||||
ESZ(Addr) maxaddr = 0; /* highest mapped address */
|
||||
ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
|
||||
ESZ(Word) interp_size = 0; /* interpreter size */
|
||||
ESZ(Addr) minaddr = ~0; /* lowest mapped address */
|
||||
ESZ(Addr) maxaddr = 0; /* highest mapped address */
|
||||
ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
|
||||
ESZ(Word) interp_size = 0; /* interpreter size */
|
||||
ESZ(Word) interp_align = VKI_PAGE_SIZE;
|
||||
Int i;
|
||||
void *entry;
|
||||
@ -374,66 +347,66 @@ static Int load_ELF(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
|
||||
info->entry = e->e.e_entry + ebase;
|
||||
info->phdr = 0;
|
||||
|
||||
for(i = 0; i < e->e.e_phnum; i++) {
|
||||
for (i = 0; i < e->e.e_phnum; i++) {
|
||||
ESZ(Phdr) *ph = &e->p[i];
|
||||
|
||||
switch(ph->p_type) {
|
||||
case PT_PHDR:
|
||||
info->phdr = ph->p_vaddr + ebase;
|
||||
break;
|
||||
info->phdr = ph->p_vaddr + ebase;
|
||||
break;
|
||||
|
||||
case PT_LOAD:
|
||||
if (ph->p_vaddr < minaddr)
|
||||
minaddr = ph->p_vaddr;
|
||||
if (ph->p_vaddr+ph->p_memsz > maxaddr)
|
||||
maxaddr = ph->p_vaddr+ph->p_memsz;
|
||||
break;
|
||||
|
||||
if (ph->p_vaddr < minaddr)
|
||||
minaddr = ph->p_vaddr;
|
||||
if (ph->p_vaddr+ph->p_memsz > maxaddr)
|
||||
maxaddr = ph->p_vaddr+ph->p_memsz;
|
||||
break;
|
||||
|
||||
case PT_INTERP: {
|
||||
HChar *buf = VG_(malloc)("ume.LE.1", ph->p_filesz+1);
|
||||
Int j;
|
||||
Int intfd;
|
||||
Int baseaddr_set;
|
||||
Int j;
|
||||
Int intfd;
|
||||
Int baseaddr_set;
|
||||
|
||||
vg_assert(buf);
|
||||
VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset);
|
||||
buf[ph->p_filesz] = '\0';
|
||||
VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset);
|
||||
buf[ph->p_filesz] = '\0';
|
||||
|
||||
sres = VG_(open)(buf, VKI_O_RDONLY, 0);
|
||||
sres = VG_(open)(buf, VKI_O_RDONLY, 0);
|
||||
if (sres.isError) {
|
||||
VG_(printf)("valgrind: m_ume.c: can't open interpreter\n");
|
||||
VG_(exit)(1);
|
||||
}
|
||||
VG_(printf)("valgrind: m_ume.c: can't open interpreter\n");
|
||||
VG_(exit)(1);
|
||||
}
|
||||
intfd = sres.res;
|
||||
|
||||
interp = readelf(intfd, buf);
|
||||
if (interp == NULL) {
|
||||
VG_(printf)("valgrind: m_ume.c: can't read interpreter\n");
|
||||
return 1;
|
||||
}
|
||||
VG_(free)(buf);
|
||||
interp = readelf(intfd, buf);
|
||||
if (interp == NULL) {
|
||||
VG_(printf)("valgrind: m_ume.c: can't read interpreter\n");
|
||||
return 1;
|
||||
}
|
||||
VG_(free)(buf);
|
||||
|
||||
baseaddr_set = 0;
|
||||
for(j = 0; j < interp->e.e_phnum; j++) {
|
||||
ESZ(Phdr) *iph = &interp->p[j];
|
||||
ESZ(Addr) end;
|
||||
baseaddr_set = 0;
|
||||
for (j = 0; j < interp->e.e_phnum; j++) {
|
||||
ESZ(Phdr) *iph = &interp->p[j];
|
||||
ESZ(Addr) end;
|
||||
|
||||
if (iph->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (!baseaddr_set) {
|
||||
interp_addr = iph->p_vaddr;
|
||||
interp_align = iph->p_align;
|
||||
baseaddr_set = 1;
|
||||
}
|
||||
if (iph->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (!baseaddr_set) {
|
||||
interp_addr = iph->p_vaddr;
|
||||
interp_align = iph->p_align;
|
||||
baseaddr_set = 1;
|
||||
}
|
||||
|
||||
/* assumes that all segments in the interp are close */
|
||||
end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
|
||||
/* assumes that all segments in the interp are close */
|
||||
end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
|
||||
|
||||
if (end > interp_size)
|
||||
interp_size = end;
|
||||
}
|
||||
break;
|
||||
if (end > interp_size)
|
||||
interp_size = end;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
@ -447,17 +420,17 @@ static Int load_ELF(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
|
||||
|
||||
if (info->exe_base != info->exe_end) {
|
||||
if (minaddr >= maxaddr ||
|
||||
(minaddr + ebase < info->exe_base ||
|
||||
maxaddr + ebase > info->exe_end)) {
|
||||
VG_(printf)("Executable range %p-%p is outside the\n"
|
||||
(minaddr + ebase < info->exe_base ||
|
||||
maxaddr + ebase > info->exe_end)) {
|
||||
VG_(printf)("Executable range %p-%p is outside the\n"
|
||||
"acceptable range %p-%p\n",
|
||||
(char *)minaddr + ebase, (char *)maxaddr + ebase,
|
||||
(char *)info->exe_base, (char *)info->exe_end);
|
||||
return VKI_ENOMEM;
|
||||
return VKI_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
info->brkbase = mapelf(e, ebase); /* map the executable */
|
||||
info->brkbase = mapelf(e, ebase); /* map the executable */
|
||||
|
||||
if (info->brkbase == 0)
|
||||
return VKI_ENOMEM;
|
||||
@ -539,334 +512,7 @@ static Int load_ELF(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static Bool match_script(char *hdr, Int len)
|
||||
{
|
||||
Char* end = hdr + len;
|
||||
Char* interp = hdr + 2;
|
||||
|
||||
// len < 4: need '#', '!', plus at least a '/' and one more char
|
||||
if (len < 4) return False;
|
||||
if (0 != VG_(memcmp)(hdr, "#!", 2)) return False;
|
||||
|
||||
// Find interpreter name, make sure it's an absolute path (starts with
|
||||
// '/') and has at least one more char. First, skip over any space
|
||||
// between the #! and the start of the interpreter name
|
||||
while (interp < end && VG_(isspace)(*interp)) interp++;
|
||||
|
||||
// overrun?
|
||||
if (interp >= end) return False; // can't find start of interp name
|
||||
|
||||
// interp should now point at the /
|
||||
if (*interp != '/') return False; // absolute path only for interpreter
|
||||
|
||||
// check for something plausible after the /
|
||||
interp++;
|
||||
if (interp >= end) return False;
|
||||
if (VG_(isspace)(*interp)) return False;
|
||||
|
||||
// Here we should get the full interpreter name and check it with
|
||||
// check_executable(). See the "EXEC FAILED" failure when running shell
|
||||
// for an example.
|
||||
|
||||
return True; // looks like a #! script
|
||||
}
|
||||
|
||||
// Forward declaration.
|
||||
static Int do_exec_inner(const HChar* exe, ExeInfo* info);
|
||||
|
||||
/* returns: 0 = success, non-0 is failure */
|
||||
static Int load_script(Int fd, const HChar* name, ExeInfo* info)
|
||||
{
|
||||
Char hdr[4096];
|
||||
Int len = 4096;
|
||||
Int eol;
|
||||
Char* interp;
|
||||
Char* end;
|
||||
Char* cp;
|
||||
Char* arg = NULL;
|
||||
SysRes res;
|
||||
|
||||
// Read the first part of the file.
|
||||
res = VG_(pread)(fd, hdr, len, 0);
|
||||
if (res.isError) {
|
||||
VG_(close)(fd);
|
||||
return VKI_EACCES;
|
||||
} else {
|
||||
len = res.res;
|
||||
}
|
||||
|
||||
vg_assert('#' == hdr[0] && '!' == hdr[1]);
|
||||
|
||||
end = hdr + len;
|
||||
interp = hdr + 2;
|
||||
while (interp < end && VG_(isspace)(*interp))
|
||||
interp++;
|
||||
|
||||
vg_assert(*interp == '/'); /* absolute path only for interpreter */
|
||||
|
||||
/* skip over interpreter name */
|
||||
for (cp = interp; cp < end && !VG_(isspace)(*cp); cp++)
|
||||
;
|
||||
|
||||
eol = (*cp == '\n');
|
||||
|
||||
*cp++ = '\0';
|
||||
|
||||
if (!eol && cp < end) {
|
||||
/* skip space before arg */
|
||||
while (cp < end && VG_(isspace)(*cp) && *cp != '\n')
|
||||
cp++;
|
||||
|
||||
/* arg is from here to eol */
|
||||
arg = cp;
|
||||
while (cp < end && *cp != '\n')
|
||||
cp++;
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
info->interp_name = VG_(strdup)("ume.ls.1", interp);
|
||||
vg_assert(NULL != info->interp_name);
|
||||
if (arg != NULL && *arg != '\0') {
|
||||
info->interp_args = VG_(strdup)("ume.ls.2", arg);
|
||||
vg_assert(NULL != info->interp_args);
|
||||
}
|
||||
|
||||
if (info->argv && info->argv[0] != NULL)
|
||||
info->argv[0] = (char *)name;
|
||||
|
||||
if (0)
|
||||
VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
|
||||
info->interp_name, info->interp_args);
|
||||
|
||||
return do_exec_inner(interp, info);
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
VG_EXE_FORMAT_ELF = 1,
|
||||
VG_EXE_FORMAT_SCRIPT = 2,
|
||||
} ExeFormat;
|
||||
|
||||
// Check the file looks executable.
|
||||
SysRes
|
||||
VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd, Bool allow_setuid)
|
||||
{
|
||||
Int fd, ret;
|
||||
SysRes res;
|
||||
Char buf[4096];
|
||||
SizeT bufsz = 4096, fsz;
|
||||
Bool is_setuid = False;
|
||||
|
||||
// Check it's readable
|
||||
res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
|
||||
if (res.isError) {
|
||||
return res;
|
||||
}
|
||||
fd = res.res;
|
||||
|
||||
// Check we have execute permissions
|
||||
ret = VG_(check_executable)(&is_setuid, (HChar*)exe_name, allow_setuid);
|
||||
if (0 != ret) {
|
||||
VG_(close)(fd);
|
||||
if (is_setuid && !VG_(clo_xml)) {
|
||||
VG_(message)(Vg_UserMsg, "");
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"Warning: Can't execute setuid/setgid executable: %s",
|
||||
exe_name);
|
||||
VG_(message)(Vg_UserMsg, "Possible workaround: remove "
|
||||
"--trace-children=yes, if in effect");
|
||||
VG_(message)(Vg_UserMsg, "");
|
||||
}
|
||||
return VG_(mk_SysRes_Error)(ret);
|
||||
}
|
||||
|
||||
fsz = (SizeT)VG_(fsize)(fd);
|
||||
if (fsz < bufsz)
|
||||
bufsz = fsz;
|
||||
|
||||
res = VG_(pread)(fd, buf, bufsz, 0);
|
||||
if (res.isError || res.res != bufsz) {
|
||||
VG_(close)(fd);
|
||||
return VG_(mk_SysRes_Error)(VKI_EACCES);
|
||||
}
|
||||
bufsz = res.res;
|
||||
|
||||
if (match_ELF(buf, bufsz)) {
|
||||
res = VG_(mk_SysRes_Success)(VG_EXE_FORMAT_ELF);
|
||||
} else if (match_script(buf, bufsz)) {
|
||||
res = VG_(mk_SysRes_Success)(VG_EXE_FORMAT_SCRIPT);
|
||||
} else {
|
||||
res = VG_(mk_SysRes_Error)(VKI_ENOEXEC);
|
||||
}
|
||||
|
||||
// Write the 'out_fd' param if necessary, or close the file.
|
||||
if (!res.isError && out_fd) {
|
||||
*out_fd = fd;
|
||||
} else {
|
||||
VG_(close)(fd);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// returns: 0 = success, non-0 is failure
|
||||
//
|
||||
// We can execute only ELF binaries or scripts that begin with "#!". (Not,
|
||||
// for example, scripts that don't begin with "#!"; see the VG_(do_exec)()
|
||||
// invocation from m_main.c for how that's handled.)
|
||||
static Int do_exec_inner(const HChar *exe, ExeInfo* info)
|
||||
{
|
||||
SysRes res;
|
||||
Int fd;
|
||||
Int ret;
|
||||
|
||||
res = VG_(pre_exec_check)(exe, &fd, False/*allow_setuid*/);
|
||||
if (res.isError)
|
||||
return res.err;
|
||||
|
||||
switch (res.res) {
|
||||
case VG_EXE_FORMAT_ELF: ret = load_ELF (fd, exe, info); break;
|
||||
case VG_EXE_FORMAT_SCRIPT: ret = load_script(fd, exe, info); break;
|
||||
default:
|
||||
vg_assert2(0, "unrecognised VG_EXE_FORMAT value\n");
|
||||
}
|
||||
|
||||
VG_(close)(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static Bool is_hash_bang_file(Char* f)
|
||||
{
|
||||
SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
|
||||
if (!res.isError) {
|
||||
Char buf[3] = {0,0,0};
|
||||
Int fd = res.res;
|
||||
Int n = VG_(read)(fd, buf, 2);
|
||||
if (n == 2 && VG_STREQ("#!", buf))
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
// Look at the first 80 chars, and if any are greater than 127, it's binary.
|
||||
// This is crude, but should be good enough. Note that it fails on a
|
||||
// zero-length file, as we want.
|
||||
static Bool is_binary_file(Char* f)
|
||||
{
|
||||
SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
|
||||
if (!res.isError) {
|
||||
UChar buf[80];
|
||||
Int fd = res.res;
|
||||
Int n = VG_(read)(fd, buf, 80);
|
||||
Int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (buf[i] > 127)
|
||||
return True; // binary char found
|
||||
}
|
||||
return False;
|
||||
} else {
|
||||
// Something went wrong. This will only happen if we earlier
|
||||
// succeeded in opening the file but fail here (eg. the file was
|
||||
// deleted between then and now).
|
||||
VG_(printf)("valgrind: %s: unknown error\n", f);
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
}
|
||||
|
||||
// If the do_exec fails we try to emulate what the shell does (I used
|
||||
// bash as a guide). It's worth noting that the shell can execute some
|
||||
// things that VG_(do_exec)() (which subsitutes for the kernel's exec())
|
||||
// will refuse to (eg. scripts lacking a "#!" prefix).
|
||||
static Int do_exec_shell_followup(Int ret, HChar* exe_name,
|
||||
ExeInfo* info)
|
||||
{
|
||||
Char* default_interp_name = "/bin/sh";
|
||||
SysRes res;
|
||||
struct vg_stat st;
|
||||
|
||||
if (VKI_ENOEXEC == ret) {
|
||||
// It was an executable file, but in an unacceptable format. Probably
|
||||
// is a shell script lacking the "#!" prefix; try to execute it so.
|
||||
|
||||
// Is it a binary file?
|
||||
if (is_binary_file(exe_name)) {
|
||||
VG_(printf)("valgrind: %s: cannot execute binary file\n", exe_name);
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
|
||||
// Looks like a script. Run it with /bin/sh. This includes
|
||||
// zero-length files.
|
||||
|
||||
info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
|
||||
info->interp_args = NULL;
|
||||
if (info->argv && info->argv[0] != NULL)
|
||||
info->argv[0] = (char *)exe_name;
|
||||
|
||||
ret = do_exec_inner(info->interp_name, info);
|
||||
|
||||
if (0 != ret) {
|
||||
// Something went wrong with executing the default interpreter
|
||||
VG_(printf)("valgrind: %s: bad interpreter (%s): %s\n",
|
||||
exe_name, info->interp_name, VG_(strerror)(ret));
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
|
||||
} else if (0 != ret) {
|
||||
// Something else went wrong. Try to make the error more specific,
|
||||
// and then print a message and abort.
|
||||
|
||||
// Was it a directory?
|
||||
res = VG_(stat)(exe_name, &st);
|
||||
if (!res.isError && VKI_S_ISDIR(st.st_mode)) {
|
||||
VG_(printf)("valgrind: %s: is a directory\n", exe_name);
|
||||
|
||||
// Was it not executable?
|
||||
} else if (0 != VG_(check_executable)(NULL, exe_name,
|
||||
False/*allow_setuid*/)) {
|
||||
VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret));
|
||||
|
||||
// Did it start with "#!"? If so, it must have been a bad interpreter.
|
||||
} else if (is_hash_bang_file(exe_name)) {
|
||||
VG_(printf)("valgrind: %s: bad interpreter: %s\n",
|
||||
exe_name, VG_(strerror)(ret));
|
||||
|
||||
// Otherwise it was something else.
|
||||
} else {
|
||||
VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret));
|
||||
}
|
||||
// 126 means NOEXEC; I think this is Posix, and that in some cases we
|
||||
// should be returning 127, meaning NOTFOUND. Oh well.
|
||||
VG_(exit)(126);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// This emulates the kernel's exec(). If it fails, it then emulates the
|
||||
// shell's handling of the situation.
|
||||
// See ume.h for an indication of which entries of 'info' are inputs, which
|
||||
// are outputs, and which are both.
|
||||
/* returns: 0 = success, non-0 is failure */
|
||||
Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info)
|
||||
{
|
||||
Int ret;
|
||||
|
||||
info->interp_name = NULL;
|
||||
info->interp_args = NULL;
|
||||
|
||||
ret = do_exec_inner(exe_name, info);
|
||||
|
||||
if (0 != ret) {
|
||||
Char* exe_name_casted = (Char*)exe_name;
|
||||
ret = do_exec_shell_followup(ret, exe_name_casted, info);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(VGO_linux) */
|
||||
#endif /* defined(HAVE_ELF) */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
286
coregrind/m_ume/main.c
Normal file
286
coregrind/m_ume/main.c
Normal file
@ -0,0 +1,286 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- User-mode execve(), and other stuff shared between stage1 ---*/
|
||||
/*--- and stage2. m_ume.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2000-2008 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
|
||||
#include "pub_core_basics.h"
|
||||
#include "pub_core_vki.h"
|
||||
|
||||
#include "pub_core_libcbase.h"
|
||||
#include "pub_core_libcassert.h" // VG_(exit), vg_assert
|
||||
#include "pub_core_libcfile.h" // VG_(close) et al
|
||||
#include "pub_core_libcprint.h" // VG_(message)
|
||||
#include "pub_core_mallocfree.h" // VG_(strdup)
|
||||
#include "pub_core_syscall.h" // VG_(mk_SysRes_Error)
|
||||
#include "pub_core_options.h" // VG_(clo_xml)
|
||||
#include "pub_core_ume.h" // self
|
||||
|
||||
#include "priv_ume.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
const HChar *name;
|
||||
Bool (*match_fn)(Char *hdr, Int len);
|
||||
Int (*load_fn)(Int fd, const HChar *name, ExeInfo *info);
|
||||
} ExeHandler;
|
||||
|
||||
static ExeHandler exe_handlers[] = {
|
||||
#if defined(HAVE_ELF)
|
||||
{ "ELF", VG_(match_ELF), VG_(load_ELF) },
|
||||
#endif
|
||||
#if defined(HAVE_SCRIPT)
|
||||
{ "script", VG_(match_script), VG_(load_script) },
|
||||
#endif
|
||||
};
|
||||
#define EXE_HANDLER_COUNT (sizeof(exe_handlers)/sizeof(exe_handlers[0]))
|
||||
|
||||
|
||||
// Check the file looks executable.
|
||||
SysRes
|
||||
VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd, Bool allow_setuid)
|
||||
{
|
||||
Int fd, ret, i;
|
||||
SysRes res;
|
||||
Char buf[4096];
|
||||
SizeT bufsz = 4096, fsz;
|
||||
Bool is_setuid = False;
|
||||
|
||||
// Check it's readable
|
||||
res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
|
||||
if (res.isError) {
|
||||
return res;
|
||||
}
|
||||
fd = res.res;
|
||||
|
||||
// Check we have execute permissions
|
||||
ret = VG_(check_executable)(&is_setuid, (HChar*)exe_name, allow_setuid);
|
||||
if (0 != ret) {
|
||||
VG_(close)(fd);
|
||||
if (is_setuid && !VG_(clo_xml)) {
|
||||
VG_(message)(Vg_UserMsg, "");
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"Warning: Can't execute setuid/setgid executable: %s",
|
||||
exe_name);
|
||||
VG_(message)(Vg_UserMsg, "Possible workaround: remove "
|
||||
"--trace-children=yes, if in effect");
|
||||
VG_(message)(Vg_UserMsg, "");
|
||||
}
|
||||
return VG_(mk_SysRes_Error)(ret);
|
||||
}
|
||||
|
||||
fsz = (SizeT)VG_(fsize)(fd);
|
||||
if (fsz < bufsz)
|
||||
bufsz = fsz;
|
||||
|
||||
res = VG_(pread)(fd, buf, bufsz, 0);
|
||||
if (res.isError || res.res != bufsz) {
|
||||
VG_(close)(fd);
|
||||
return VG_(mk_SysRes_Error)(VKI_EACCES);
|
||||
}
|
||||
bufsz = res.res;
|
||||
|
||||
// Look for a matching executable format
|
||||
for (i = 0; i < EXE_HANDLER_COUNT; i++) {
|
||||
if ((*exe_handlers[i].match_fn)(buf, bufsz)) {
|
||||
res = VG_(mk_SysRes_Success)(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == EXE_HANDLER_COUNT) {
|
||||
// Rejected by all executable format handlers.
|
||||
res = VG_(mk_SysRes_Error)(VKI_ENOEXEC);
|
||||
}
|
||||
|
||||
// Write the 'out_fd' param if necessary, or close the file.
|
||||
if (!res.isError && out_fd) {
|
||||
*out_fd = fd;
|
||||
} else {
|
||||
VG_(close)(fd);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// returns: 0 = success, non-0 is failure
|
||||
//
|
||||
// We can execute only binaries (ELF, etc) or scripts that begin with "#!".
|
||||
// (Not, for example, scripts that don't begin with "#!"; see the
|
||||
// VG_(do_exec)() invocation from m_main.c for how that's handled.)
|
||||
Int VG_(do_exec_inner)(const HChar* exe, ExeInfo* info)
|
||||
{
|
||||
SysRes res;
|
||||
Int fd;
|
||||
Int ret;
|
||||
|
||||
res = VG_(pre_exec_check)(exe, &fd, False/*allow_setuid*/);
|
||||
if (res.isError)
|
||||
return res.err;
|
||||
|
||||
vg_assert2(res.res >= 0 && res.res < EXE_HANDLER_COUNT,
|
||||
"invalid VG_(pre_exec_check) result");
|
||||
|
||||
ret = (*exe_handlers[res.res].load_fn)(fd, exe, info);
|
||||
|
||||
VG_(close)(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static Bool is_hash_bang_file(Char* f)
|
||||
{
|
||||
SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
|
||||
if (!res.isError) {
|
||||
Char buf[3] = {0,0,0};
|
||||
Int fd = res.res;
|
||||
Int n = VG_(read)(fd, buf, 2);
|
||||
if (n == 2 && VG_STREQ("#!", buf))
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
// Look at the first 80 chars, and if any are greater than 127, it's binary.
|
||||
// This is crude, but should be good enough. Note that it fails on a
|
||||
// zero-length file, as we want.
|
||||
static Bool is_binary_file(Char* f)
|
||||
{
|
||||
SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
|
||||
if (!res.isError) {
|
||||
UChar buf[80];
|
||||
Int fd = res.res;
|
||||
Int n = VG_(read)(fd, buf, 80);
|
||||
Int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (buf[i] > 127)
|
||||
return True; // binary char found
|
||||
}
|
||||
return False;
|
||||
} else {
|
||||
// Something went wrong. This will only happen if we earlier
|
||||
// succeeded in opening the file but fail here (eg. the file was
|
||||
// deleted between then and now).
|
||||
VG_(printf)("valgrind: %s: unknown error\n", f);
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
}
|
||||
|
||||
// If the do_exec fails we try to emulate what the shell does (I used
|
||||
// bash as a guide). It's worth noting that the shell can execute some
|
||||
// things that VG_(do_exec)() (which subsitutes for the kernel's exec())
|
||||
// will refuse to (eg. scripts lacking a "#!" prefix).
|
||||
static Int do_exec_shell_followup(Int ret, HChar* exe_name, ExeInfo* info)
|
||||
{
|
||||
Char* default_interp_name = "/bin/sh";
|
||||
SysRes res;
|
||||
struct vg_stat st;
|
||||
|
||||
if (VKI_ENOEXEC == ret) {
|
||||
// It was an executable file, but in an unacceptable format. Probably
|
||||
// is a shell script lacking the "#!" prefix; try to execute it so.
|
||||
|
||||
// Is it a binary file?
|
||||
if (is_binary_file(exe_name)) {
|
||||
VG_(printf)("valgrind: %s: cannot execute binary file\n", exe_name);
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
|
||||
// Looks like a script. Run it with /bin/sh. This includes
|
||||
// zero-length files.
|
||||
|
||||
info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
|
||||
info->interp_args = NULL;
|
||||
if (info->argv && info->argv[0] != NULL)
|
||||
info->argv[0] = (char *)exe_name;
|
||||
|
||||
ret = VG_(do_exec_inner)(info->interp_name, info);
|
||||
|
||||
if (0 != ret) {
|
||||
// Something went wrong with executing the default interpreter
|
||||
VG_(printf)("valgrind: %s: bad interpreter (%s): %s\n",
|
||||
exe_name, info->interp_name, VG_(strerror)(ret));
|
||||
VG_(exit)(126); // 126 == NOEXEC
|
||||
}
|
||||
|
||||
} else if (0 != ret) {
|
||||
// Something else went wrong. Try to make the error more specific,
|
||||
// and then print a message and abort.
|
||||
|
||||
// Was it a directory?
|
||||
res = VG_(stat)(exe_name, &st);
|
||||
if (!res.isError && VKI_S_ISDIR(st.st_mode)) {
|
||||
VG_(printf)("valgrind: %s: is a directory\n", exe_name);
|
||||
|
||||
// Was it not executable?
|
||||
} else if (0 != VG_(check_executable)(NULL, exe_name,
|
||||
False/*allow_setuid*/)) {
|
||||
VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret));
|
||||
|
||||
// Did it start with "#!"? If so, it must have been a bad interpreter.
|
||||
} else if (is_hash_bang_file(exe_name)) {
|
||||
VG_(printf)("valgrind: %s: bad interpreter: %s\n",
|
||||
exe_name, VG_(strerror)(ret));
|
||||
|
||||
// Otherwise it was something else.
|
||||
} else {
|
||||
VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret));
|
||||
}
|
||||
// 126 means NOEXEC; I think this is Posix, and that in some cases we
|
||||
// should be returning 127, meaning NOTFOUND. Oh well.
|
||||
VG_(exit)(126);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// This emulates the kernel's exec(). If it fails, it then emulates the
|
||||
// shell's handling of the situation.
|
||||
// See ume.h for an indication of which entries of 'info' are inputs, which
|
||||
// are outputs, and which are both.
|
||||
/* returns: 0 = success, non-0 is failure */
|
||||
Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info)
|
||||
{
|
||||
Int ret;
|
||||
|
||||
info->interp_name = NULL;
|
||||
info->interp_args = NULL;
|
||||
|
||||
ret = VG_(do_exec_inner)(exe_name, info);
|
||||
|
||||
if (0 != ret) {
|
||||
Char* exe_name_casted = (Char*)exe_name;
|
||||
ret = do_exec_shell_followup(ret, exe_name_casted, info);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
150
coregrind/m_ume/script.c
Normal file
150
coregrind/m_ume/script.c
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- User-mode execve() for #! scripts. m_ume_script.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2000-2008 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
#include "pub_core_basics.h"
|
||||
#include "pub_core_vki.h"
|
||||
|
||||
#include "pub_core_libcbase.h"
|
||||
#include "pub_core_libcassert.h" // VG_(exit), vg_assert
|
||||
#include "pub_core_libcfile.h" // VG_(close) et al
|
||||
#include "pub_core_libcprint.h"
|
||||
#include "pub_core_mallocfree.h" // VG_(strdup)
|
||||
#include "pub_core_ume.h" // self
|
||||
|
||||
#include "priv_ume.h" // self
|
||||
|
||||
|
||||
#if defined(HAVE_SCRIPT)
|
||||
|
||||
Bool VG_(match_script)(Char *hdr, Int len)
|
||||
{
|
||||
Char* end = hdr + len;
|
||||
Char* interp = hdr + 2;
|
||||
|
||||
// len < 4: need '#', '!', plus at least a '/' and one more char
|
||||
if (len < 4) return False;
|
||||
if (0 != VG_(memcmp)(hdr, "#!", 2)) return False;
|
||||
|
||||
// Find interpreter name, make sure it's an absolute path (starts with
|
||||
// '/') and has at least one more char. First, skip over any space
|
||||
// between the #! and the start of the interpreter name
|
||||
while (interp < end && VG_(isspace)(*interp)) interp++;
|
||||
|
||||
// overrun?
|
||||
if (interp >= end) return False; // can't find start of interp name
|
||||
|
||||
// interp should now point at the /
|
||||
if (*interp != '/') return False; // absolute path only for interpreter
|
||||
|
||||
// check for something plausible after the /
|
||||
interp++;
|
||||
if (interp >= end) return False;
|
||||
if (VG_(isspace)(*interp)) return False;
|
||||
|
||||
// Here we should get the full interpreter name and check it with
|
||||
// check_executable(). See the "EXEC FAILED" failure when running shell
|
||||
// for an example.
|
||||
|
||||
return True; // looks like a #! script
|
||||
}
|
||||
|
||||
|
||||
/* returns: 0 = success, non-0 is failure */
|
||||
Int VG_(load_script)(Int fd, const HChar* name, ExeInfo* info)
|
||||
{
|
||||
Char hdr[4096];
|
||||
Int len = 4096;
|
||||
Int eol;
|
||||
Char* interp;
|
||||
Char* end;
|
||||
Char* cp;
|
||||
Char* arg = NULL;
|
||||
SysRes res;
|
||||
|
||||
// Read the first part of the file.
|
||||
res = VG_(pread)(fd, hdr, len, 0);
|
||||
if (res.isError) {
|
||||
VG_(close)(fd);
|
||||
return VKI_EACCES;
|
||||
} else {
|
||||
len = res.res;
|
||||
}
|
||||
|
||||
vg_assert('#' == hdr[0] && '!' == hdr[1]);
|
||||
|
||||
end = hdr + len;
|
||||
interp = hdr + 2;
|
||||
while (interp < end && VG_(isspace)(*interp))
|
||||
interp++;
|
||||
|
||||
vg_assert(*interp == '/'); /* absolute path only for interpreter */
|
||||
|
||||
/* skip over interpreter name */
|
||||
for (cp = interp; cp < end && !VG_(isspace)(*cp); cp++)
|
||||
;
|
||||
|
||||
eol = (*cp == '\n');
|
||||
|
||||
*cp++ = '\0';
|
||||
|
||||
if (!eol && cp < end) {
|
||||
/* skip space before arg */
|
||||
while (cp < end && VG_(isspace)(*cp) && *cp != '\n')
|
||||
cp++;
|
||||
|
||||
/* arg is from here to eol */
|
||||
arg = cp;
|
||||
while (cp < end && *cp != '\n')
|
||||
cp++;
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
info->interp_name = VG_(strdup)("ume.ls.1", interp);
|
||||
vg_assert(NULL != info->interp_name);
|
||||
if (arg != NULL && *arg != '\0') {
|
||||
info->interp_args = VG_(strdup)("ume.ls.2", arg);
|
||||
vg_assert(NULL != info->interp_args);
|
||||
}
|
||||
|
||||
if (info->argv && info->argv[0] != NULL)
|
||||
info->argv[0] = (char *)name;
|
||||
|
||||
if (0)
|
||||
VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
|
||||
info->interp_name, info->interp_args);
|
||||
|
||||
return VG_(do_exec_inner)(interp, info);
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_SCRIPT) */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@ -37,7 +37,7 @@
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Loading ELF files ---*/
|
||||
/*--- Loading files ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
// Info needed to load and run a program. IN/INOUT/OUT refers to the
|
||||
@ -67,7 +67,7 @@ typedef
|
||||
|
||||
// Do a number of appropriate checks to see if the file looks executable by
|
||||
// the kernel: ie. it's a file, it's readable and executable, and it's in
|
||||
// either ELF or "#!" format. On success, 'out_fd' gets the fd of the file
|
||||
// either binary or "#!" format. On success, 'out_fd' gets the fd of the file
|
||||
// if it's non-NULL. Otherwise the fd is closed.
|
||||
extern SysRes VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd,
|
||||
Bool allow_setuid);
|
||||
@ -78,21 +78,6 @@ extern SysRes VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd,
|
||||
// the program.
|
||||
extern Int VG_(do_exec)(const HChar* exe, ExeInfo* info);
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Finding and dealing with auxv ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
struct ume_auxv
|
||||
{
|
||||
Word a_type;
|
||||
union {
|
||||
void *a_ptr;
|
||||
Word a_val;
|
||||
} u;
|
||||
};
|
||||
|
||||
extern struct ume_auxv *VG_(find_auxv)(UWord* orig_esp);
|
||||
|
||||
#endif /* __PUB_CORE_UME_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@ -172,7 +172,6 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
|
||||
vcpu_fbench.stdout.exp vcpu_fbench.stderr.exp vcpu_fbench.vgtest \
|
||||
vcpu_fnfns.stdout.exp vcpu_fnfns.stdout.exp-glibc28-amd64 \
|
||||
vcpu_fnfns.stderr.exp vcpu_fnfns.vgtest \
|
||||
vgtest_ume.stderr.exp vgtest_ume.disabled \
|
||||
with-space.stderr.exp with-space.stdout.exp with-space.vgtest \
|
||||
wrap1.vgtest wrap1.stdout.exp wrap1.stderr.exp \
|
||||
wrap2.vgtest wrap2.stdout.exp wrap2.stderr.exp \
|
||||
@ -190,7 +189,6 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
|
||||
zeropage.stderr.exp zeropage.stderr.exp2 zeropage.stdout.exp \
|
||||
zeropage.vgtest
|
||||
|
||||
# vgtest_ume is not working
|
||||
check_PROGRAMS = \
|
||||
addressable \
|
||||
badaddrvalue badfree badjump badjump2 \
|
||||
@ -370,7 +368,3 @@ endif
|
||||
# -Wl,-T,$(top_builddir)/valt_load_address.lds
|
||||
#hello_DEPENDENCIES = $(top_builddir)/valt_load_address.lds
|
||||
|
||||
# vgtest_ume is not working
|
||||
#vgtest_ume_CFLAGS = -DVGA_$(VG_ARCH_PRI) -DVGO_$(VG_OS)
|
||||
#vgtest_ume_LDADD = ../../coregrind/m_ume.o
|
||||
|
||||
|
||||
@ -1,150 +0,0 @@
|
||||
|
||||
// This file is a unit self-test for ume.c, jmp_with_stack.c
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include "../../include/pub_tool_basics.h"
|
||||
#include "../../coregrind/pub_core_ume.h"
|
||||
|
||||
#define STKSZ (64*1024)
|
||||
|
||||
static void* init_sp;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Test VG_(foreach_map)()
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
static int x[8];
|
||||
|
||||
static int f(char *start, char *end, const char *perm, off_t off,
|
||||
int maj, int min, int ino, void* dummy) {
|
||||
// Just do some nonsense action with each of the values so that Memcheck
|
||||
// checks that they are valid.
|
||||
x[0] = ( start == 0 ? 0 : 1 );
|
||||
x[1] = ( end == 0 ? 0 : 1 );
|
||||
x[2] = ( perm == 0 ? 0 : 1 );
|
||||
x[3] = ( off == 0 ? 0 : 1 );
|
||||
x[4] = ( maj == 0 ? 0 : 1 );
|
||||
x[5] = ( min == 0 ? 0 : 1 );
|
||||
x[6] = ( ino == 0 ? 0 : 1 );
|
||||
x[7] = ( dummy == 0 ? 0 : 1 );
|
||||
|
||||
return /*True*/1 + x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + x[7];
|
||||
}
|
||||
|
||||
static void test__foreach_map(void)
|
||||
{
|
||||
fprintf(stderr, "Calling VG_(foreach_map)()\n");
|
||||
VG_(foreach_map)(f, /*dummy*/NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Test VG_(find_auxv)()
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
static void test__find_auxv(void)
|
||||
{
|
||||
struct ume_auxv *auxv;
|
||||
|
||||
assert(init_sp != NULL);
|
||||
|
||||
fprintf(stderr, "Calling VG_(find_auxv)()\n");
|
||||
auxv = VG_(find_auxv)((UWord*)init_sp);
|
||||
|
||||
// Check the auxv value looks sane
|
||||
assert((void*)auxv > (void*)init_sp);
|
||||
assert((unsigned int)auxv - (unsigned int)init_sp < 0x10000);
|
||||
|
||||
// Scan the auxv, check it looks sane
|
||||
for (; auxv->a_type != AT_NULL; auxv++) {
|
||||
switch(auxv->a_type) {
|
||||
// Check a_type value looks like a plausible small constant
|
||||
case 1 ... 64:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "auxv->a_type = %lld\n", (Long)auxv->a_type);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Test VG_(do_exec)()
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
static void push_auxv(unsigned char **espp, int type, void *val)
|
||||
{
|
||||
struct ume_auxv *auxp = (struct ume_auxv *)*espp;
|
||||
auxp--;
|
||||
auxp->a_type = type;
|
||||
auxp->u.a_ptr = val;
|
||||
*espp = (unsigned char *)auxp;
|
||||
}
|
||||
|
||||
static void push(unsigned char **espp, void *v)
|
||||
{
|
||||
void **vp = *(void ***)espp;
|
||||
*--vp = v;
|
||||
*espp = (unsigned char *)vp;
|
||||
}
|
||||
|
||||
static void test__do_exec(void)
|
||||
{
|
||||
struct exeinfo info;
|
||||
int err;
|
||||
unsigned char* newstack;
|
||||
unsigned char *esp;
|
||||
|
||||
info.argv = NULL;
|
||||
info.exe_base = 0x50000000;
|
||||
info.exe_end = 0x50ffffff;
|
||||
|
||||
fprintf(stderr, "Calling VG_(do_exec)(\"hello\")\n");
|
||||
err = VG_(do_exec)("hello", &info);
|
||||
assert(0 == err);
|
||||
|
||||
// printf("info.exe_base=%p exe_end=%p\n",
|
||||
// (void*)info.exe_base, (void*)info.exe_end);
|
||||
|
||||
newstack = malloc(STKSZ);
|
||||
assert(0 != newstack);
|
||||
|
||||
esp = newstack+STKSZ;
|
||||
|
||||
/*
|
||||
Set the new executable's stack up like the kernel would after
|
||||
exec.
|
||||
|
||||
These are being pushed onto the stack, towards decreasing
|
||||
addresses.
|
||||
*/
|
||||
push_auxv(&esp, AT_NULL, 0); // auxv terminator
|
||||
push_auxv(&esp, AT_ENTRY, (void *)info.entry); // entrypoint of the main executable */
|
||||
push_auxv(&esp, AT_BASE, (void *)info.interp_base); // base address of ld-linux.so
|
||||
push_auxv(&esp, AT_PHDR, (void *)info.phdr); // where the ELF PHDRs are mapped
|
||||
push_auxv(&esp, AT_PHNUM, (void*)info.phnum); // and how many of them
|
||||
|
||||
push(&esp, 0); /* no env */
|
||||
push(&esp, 0); /* no argv */
|
||||
push(&esp, 0); /* argc=0 */
|
||||
|
||||
// fprintf(stderr, "ume_go: %p %p\n", (void*)info.init_eip, (void*)esp);
|
||||
|
||||
VG_(jump_and_switch_stacks)((Addr)esp, info.init_eip);
|
||||
|
||||
assert(0); // UNREACHABLE
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
init_sp = argv - 1;
|
||||
|
||||
test__foreach_map();
|
||||
test__find_auxv();
|
||||
test__do_exec();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
# This one currently not used because it doesn't compile any more
|
||||
prog: vgtest_ume
|
||||
vgopts: -q
|
||||
@ -1,4 +0,0 @@
|
||||
Calling VG_(foreach_map)()
|
||||
Calling VG_(find_auxv)()
|
||||
Calling VG_(do_exec)("hello")
|
||||
Hello, world!
|
||||
Loading…
x
Reference in New Issue
Block a user