print_pc: fix multiple personalities support

* syscall.c (print_pc): Choose instruction pointer format depending
on current_wordsize, not the size of long integer type.
* tests/pc.c: New file.
* tests/pc.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add pc.
(TESTS): Add pc.test.
* tests/.gitignore: Add pc.
This commit is contained in:
Дмитрий Левин 2015-02-15 15:52:02 +00:00
parent 4f2d1ae243
commit e96cb621fa
5 changed files with 141 additions and 58 deletions

114
syscall.c
View File

@ -793,140 +793,138 @@ static long get_regs_error;
void
print_pc(struct tcb *tcp)
{
#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
sizeof(long) == 8 ? "[????????????????] " : \
NULL /* crash */)
const char *fmt;
const char *bad;
#if SUPPORTED_PERSONALITIES > 1
# define pc_wordsize personality_wordsize[tcp->currpers]
#else
# define pc_wordsize current_wordsize
#endif
if (pc_wordsize == 4) {
fmt = "[%08lx] ";
bad = "[????????] ";
} else {
fmt = "[%016lx] ";
bad = "[????????????????] ";
}
#undef pc_wordsize
#define PRINTBADPC tprints(bad)
if (get_regs_error) {
PRINTBADPC;
return;
}
#if defined(I386)
tprintf("[%08lx] ", i386_regs.eip);
tprintf(fmt, i386_regs.eip);
#elif defined(X86_64) || defined(X32)
if (x86_io.iov_len == sizeof(i386_regs))
tprintf(fmt, (unsigned long) i386_regs.eip);
else
tprintf(fmt, (unsigned long) x86_64_regs.rip);
#elif defined(S390) || defined(S390X)
long psw;
if (upeek(tcp->pid, PT_PSWADDR, &psw) < 0) {
PRINTBADPC;
return;
}
# ifdef S390
tprintf("[%08lx] ", psw);
# elif S390X
tprintf("[%016lx] ", psw);
# endif
#elif defined(X86_64) || defined(X32)
if (x86_io.iov_len == sizeof(i386_regs)) {
tprintf("[%08x] ", (unsigned) i386_regs.eip);
} else {
# if defined(X86_64)
tprintf("[%016lx] ", (unsigned long) x86_64_regs.rip);
# elif defined(X32)
/* Note: this truncates 64-bit rip to 32 bits */
tprintf("[%08lx] ", (unsigned long) x86_64_regs.rip);
# endif
}
tprintf(fmt, psw);
#elif defined(IA64)
long ip;
if (upeek(tcp->pid, PT_B0, &ip) < 0) {
PRINTBADPC;
return;
}
tprintf("[%08lx] ", ip);
tprintf(fmt, ip);
#elif defined(POWERPC)
long pc = ppc_regs.nip;
# ifdef POWERPC64
tprintf("[%016lx] ", pc);
# else
tprintf("[%08lx] ", pc);
# endif
tprintf(fmt, ppc_regs.nip);
#elif defined(M68K)
long pc;
if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
tprints("[????????] ");
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(ALPHA)
long pc;
if (upeek(tcp->pid, REG_PC, &pc) < 0) {
tprints("[????????????????] ");
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(SPARC)
tprintf("[%08lx] ", sparc_regs.pc);
tprintf(fmt, sparc_regs.pc);
#elif defined(SPARC64)
tprintf("[%08lx] ", sparc_regs.tpc);
tprintf(fmt, sparc_regs.tpc);
#elif defined(HPPA)
long pc;
if (upeek(tcp->pid, PT_IAOQ0, &pc) < 0) {
tprints("[????????] ");
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
#elif defined LINUX_MIPSN64
tprintf("[%016lx] ", mips_REG_EPC);
tprintf(fmt, pc);
#elif defined MIPS
tprintf("[%08lx] ", (unsigned long) mips_REG_EPC);
tprintf(fmt, (unsigned long) mips_REG_EPC);
#elif defined(SH)
long pc;
if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
tprints("[????????] ");
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(SH64)
long pc;
if (upeek(tcp->pid, REG_PC, &pc) < 0) {
tprints("[????????????????] ");
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(ARM)
tprintf("[%08lx] ", arm_regs.ARM_pc);
#elif defined(AARCH64)
/* tprintf("[%016lx] ", aarch64_regs.regs[???]); */
tprintf(fmt, arm_regs.ARM_pc);
#elif defined(AVR32)
tprintf("[%08lx] ", avr32_regs.pc);
tprintf(fmt, avr32_regs.pc);
#elif defined(BFIN)
long pc;
if (upeek(tcp->pid, PT_PC, &pc) < 0) {
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(CRISV10)
long pc;
if (upeek(tcp->pid, 4*PT_IRP, &pc) < 0) {
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(CRISV32)
long pc;
if (upeek(tcp->pid, 4*PT_ERP, &pc) < 0) {
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(TILE)
# ifdef _LP64
tprintf("[%016lx] ", (unsigned long) tile_regs.pc);
# else
tprintf("[%08lx] ", (unsigned long) tile_regs.pc);
# endif
tprintf(fmt, (unsigned long) tile_regs.pc);
#elif defined(OR1K)
tprintf("[%08lx] ", or1k_regs.pc);
tprintf(fmt, or1k_regs.pc);
#elif defined(METAG)
tprintf("[%08lx] ", metag_regs.pc);
tprintf(fmt, metag_regs.pc);
#elif defined(XTENSA)
long pc;
if (upeek(tcp->pid, REG_PC, &pc) < 0) {
PRINTBADPC;
return;
}
tprintf("[%08lx] ", pc);
tprintf(fmt, pc);
#elif defined(ARC)
tprintf("[%08lx] ", arc_regs.efa);
tprintf(fmt, arc_regs.efa);
#else
# warning print_pc is not implemented for this architecture
PRINTBADPC;
#endif /* architecture */
}

1
tests/.gitignore vendored
View File

@ -10,6 +10,7 @@ mmsg
net-accept-connect
netlink_inet_diag
netlink_unix_diag
pc
scm_rights
select
set_ptracer_any

View File

@ -15,6 +15,7 @@ check_PROGRAMS = \
net-accept-connect \
netlink_inet_diag \
netlink_unix_diag \
pc \
scm_rights \
select \
set_ptracer_any \
@ -60,6 +61,7 @@ TESTS = \
net.test \
net-fd.test \
net-yy.test \
pc.test \
sun_path.test \
unix-yy.test \
uid.test \

35
tests/pc.c Normal file
View File

@ -0,0 +1,35 @@
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(void)
{
const unsigned long size = sysconf(_SC_PAGESIZE);
const unsigned long mask = ~(size - 1);
/* write instruction pointer length to the log */
if (write(-1, NULL, 2 * sizeof(void *)) >= 0)
return 77;
/* just a noticeable line in the log */
if (munmap(&munmap, 0) >= 0)
return 77;
int pid = fork();
if (pid < 0)
return 77;
if (!pid) {
munmap((void *) ((unsigned long) &munmap & mask), size);
/* SIGSEGV is expected */
munmap((void *) (((unsigned long) &munmap & mask) + size), size);
return 77;
}
int status;
if (wait(&status) != pid ||
!WIFSIGNALED(status) ||
WTERMSIG(status) != SIGSEGV)
return 77;
return 0;
}

47
tests/pc.test Executable file
View File

@ -0,0 +1,47 @@
#!/bin/sh
# Check -i option.
. "${srcdir=.}/init.sh"
check_prog grep
OUT="$LOG.out"
./pc > /dev/null ||
framework_skip_ 'munmap/fork/wait do not behave as expected'
args="-if ./pc"
$STRACE $args > "$OUT" 2> "$LOG" || {
cat "$LOG"
fail_ "$STRACE $args does not work"
}
len="$(sed -n 's/^\[[[:xdigit:]]\+\] write(-1, NULL, \([[:digit:]]\{1,2\}\))[[:space:]]\+= -1 .*/\1/p' "$LOG")" &&
[ -n "$len" ] &&
pid="$(sed -n 's/^\[[[:xdigit:]]\{'"$len"'\}\] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=\([[:digit:]]\+\), .*/\1/p' "$LOG")" &&
[ -n "$pid" ] &&
ip="$(sed -n 's/^\[pid \+'"$pid"'\] \[\([[:xdigit:]]\{'"$len"'\}\)] --- SIGSEGV {.*} ---$/\1/p' "$LOG")" &&
[ -n "$ip" ] &&
addr="$(echo "$ip" |sed 's/^0\+//')" &&
[ -n "$addr" ] || {
cat "$LOG"
fail_ "$STRACE $args output mismatch"
}
grep_log()
{
LC_ALL=C grep -x -e "$*" < "$LOG" > /dev/null || {
cat "$LOG"
fail_ "$STRACE $args output mismatch"
}
}
grep_log '\[[[:xdigit:]]\{'"$len"'\}\] munmap(0x[[:xdigit:]]\+, 0)[[:space:]]\+= -1 .*'
grep_log '\[pid \+'"$pid"'\] \['"$ip"'\] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x'"$addr"'} ---'
grep_log '\[pid \+'"$pid"'\] \[?\{'"$len"'\}\] +++ killed by SIGSEGV +++'
grep_log '\[?\{'"$len"'\}\] +++ exited with 0 +++'
rm -f "$OUT"
exit 0