Merge in a port for mips32-linux, by Petar Jovanovic and Dejan Jevtic,
mips-valgrind@rt-rk.com, Bug 270777.
Valgrind: changes to existing files.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12616 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index efb4de3..68b8ed2 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -301,6 +301,7 @@
m_dispatch/dispatch-ppc64-linux.S \
m_dispatch/dispatch-arm-linux.S \
m_dispatch/dispatch-s390x-linux.S \
+ m_dispatch/dispatch-mips32-linux.S \
m_dispatch/dispatch-x86-darwin.S \
m_dispatch/dispatch-amd64-darwin.S \
m_gdbserver/m_gdbserver.c \
@@ -318,6 +319,7 @@
m_gdbserver/valgrind-low-ppc32.c \
m_gdbserver/valgrind-low-ppc64.c \
m_gdbserver/valgrind-low-s390x.c \
+ m_gdbserver/valgrind-low-mips32.c \
m_gdbserver/version.c \
m_initimg/initimg-linux.c \
m_initimg/initimg-darwin.c \
@@ -337,6 +339,7 @@
m_sigframe/sigframe-ppc64-linux.c \
m_sigframe/sigframe-arm-linux.c \
m_sigframe/sigframe-s390x-linux.c \
+ m_sigframe/sigframe-mips32-linux.c \
m_sigframe/sigframe-x86-darwin.c \
m_sigframe/sigframe-amd64-darwin.c \
m_syswrap/syscall-x86-linux.S \
@@ -345,6 +348,7 @@
m_syswrap/syscall-ppc64-linux.S \
m_syswrap/syscall-arm-linux.S \
m_syswrap/syscall-s390x-linux.S \
+ m_syswrap/syscall-mips32-linux.S \
m_syswrap/syscall-x86-darwin.S \
m_syswrap/syscall-amd64-darwin.S \
m_syswrap/syswrap-main.c \
@@ -358,6 +362,7 @@
m_syswrap/syswrap-ppc64-linux.c \
m_syswrap/syswrap-arm-linux.c \
m_syswrap/syswrap-s390x-linux.c \
+ m_syswrap/syswrap-mips32-linux.c \
m_syswrap/syswrap-x86-darwin.c \
m_syswrap/syswrap-amd64-darwin.c \
m_ume/elf.c \
@@ -532,7 +537,18 @@
m_gdbserver/s390x-generic.xml \
m_gdbserver/s390x-linux64-valgrind-s1.xml \
m_gdbserver/s390x-linux64-valgrind-s2.xml \
- m_gdbserver/s390x-linux64.xml
+ m_gdbserver/s390x-linux64.xml \
+ m_gdbserver/mips-cp0-valgrind-s1.xml \
+ m_gdbserver/mips-cp0-valgrind-s2.xml \
+ m_gdbserver/mips-cp0.xml \
+ m_gdbserver/mips-cpu-valgrind-s1.xml \
+ m_gdbserver/mips-cpu-valgrind-s2.xml \
+ m_gdbserver/mips-cpu.xml \
+ m_gdbserver/mips-linux.xml \
+ m_gdbserver/mips-linux-valgrind.xml \
+ m_gdbserver/mips-fpu-valgrind-s1.xml \
+ m_gdbserver/mips-fpu-valgrind-s2.xml \
+ m_gdbserver/mips-fpu.xml
# so as to make sure these get copied into the install tree
vglibdir = $(pkglibdir)
diff --git a/coregrind/launcher-linux.c b/coregrind/launcher-linux.c
index 6a200c3..a9ad1e3 100644
--- a/coregrind/launcher-linux.c
+++ b/coregrind/launcher-linux.c
@@ -179,6 +179,12 @@
ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
platform = "arm-linux";
}
+ else
+ if (ehdr->e_machine == EM_MIPS &&
+ (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
+ ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
+ platform = "mips32-linux";
+ }
}
else if (header[EI_DATA] == ELFDATA2MSB) {
if (ehdr->e_machine == EM_PPC &&
@@ -186,6 +192,12 @@
ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
platform = "ppc32-linux";
}
+ else
+ if (ehdr->e_machine == EM_MIPS &&
+ (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
+ ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
+ platform = "mips32-linux";
+ }
}
} else if (n_bytes >= sizeof(Elf64_Ehdr) && header[EI_CLASS] == ELFCLASS64) {
@@ -284,7 +296,8 @@
(0==strcmp(VG_PLATFORM,"ppc32-linux")) ||
(0==strcmp(VG_PLATFORM,"ppc64-linux")) ||
(0==strcmp(VG_PLATFORM,"arm-linux")) ||
- (0==strcmp(VG_PLATFORM,"s390x-linux")))
+ (0==strcmp(VG_PLATFORM,"s390x-linux")) ||
+ (0==strcmp(VG_PLATFORM,"mips32-linux")))
default_platform = VG_PLATFORM;
else
barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM);
diff --git a/coregrind/link_tool_exe_linux.in b/coregrind/link_tool_exe_linux.in
index 6de2562..a47747b 100644
--- a/coregrind/link_tool_exe_linux.in
+++ b/coregrind/link_tool_exe_linux.in
@@ -68,7 +68,18 @@
# so, build up the complete command here:
# 'cc' -static -Ttext='ala' 'restargs'
-my $cmd="$cc -static -Wl,-Ttext=$ala";
+# For mips we need to use "--section-start=.reginfo=$ala" because
+# "--section-start=.reginfo=$ala" will put all the sections to the
+# specificed address ($ala)
+my $x=`$cc -v 2>&1 | grep Target | sed 's/Target: //g'`;
+my $arch=substr($x, 0, index($x, '-'));
+my $cmd;
+
+if (($arch eq 'mips') || ($arch eq 'mipsel')) {
+ $cmd = "$cc -static -Wl,--section-start=.reginfo=$ala";
+} else {
+ $cmd = "$cc -static -Wl,-Ttext=$ala";
+}
# Add the rest of the parameters
foreach my $n (2 .. $#ARGV) {
diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c
index 7f7717c..6a65610 100644
--- a/coregrind/m_aspacemgr/aspacemgr-common.c
+++ b/coregrind/m_aspacemgr/aspacemgr-common.c
@@ -159,7 +159,7 @@
res = VG_(do_syscall6)(__NR_mmap2, (UWord)start, length,
prot, flags, fd, offset / 4096);
# elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
- || defined(VGP_s390x_linux)
+ || defined(VGP_s390x_linux) || defined(VGP_mips32_linux)
res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
prot, flags, fd, offset);
# elif defined(VGP_x86_darwin)
diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c
index 9980501..0695a66 100644
--- a/coregrind/m_aspacemgr/aspacemgr-linux.c
+++ b/coregrind/m_aspacemgr/aspacemgr-linux.c
@@ -2533,7 +2533,7 @@
/* Ask for an advisory. If it's negative, fail immediately. */
req.rkind = MAny;
req.start = 0;
- #if defined(VGA_arm)
+ #if defined(VGA_arm) || defined(VGA_mips32)
aspacem_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
#else
aspacem_assert(VKI_SHMLBA == VKI_PAGE_SIZE);
diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c
index 745bd7e..ddfe2ba 100644
--- a/coregrind/m_coredump/coredump-elf.c
+++ b/coregrind/m_coredump/coredump-elf.c
@@ -375,6 +375,15 @@
DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
# undef DO
regs->orig_gpr2 = arch->vex.guest_r2;
+#elif defined(VGP_mips32_linux)
+# define DO(n) regs->MIPS_r##n = arch->vex.guest_r##n
+ DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
+ DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
+ DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
+ DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
+# undef DO
+ regs->MIPS_hi = arch->vex.guest_HI;
+ regs->MIPS_lo = arch->vex.guest_LO;
#else
# error Unknown ELF platform
#endif
@@ -455,6 +464,13 @@
DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
# undef DO
+#elif defined(VGP_mips32_linux)
+# define DO(n) (*fpu)[n] = *(double*)(&arch->vex.guest_f##n)
+ DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
+ DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
+ DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
+ DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
+# undef DO
#else
# error Unknown ELF platform
#endif
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index bb559f4..c08b5a7 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -307,6 +307,43 @@
return VG_(ptrace)(VKI_PTRACE_POKEUSR_AREA, pid, &pa, NULL);
+#elif defined(VGP_mips32_linux)
+ struct vki_user_regs_struct regs;
+ VG_(memset)(®s, 0, sizeof(regs));
+ regs.MIPS_r0 = vex->guest_r0;
+ regs.MIPS_r1 = vex->guest_r1;
+ regs.MIPS_r2 = vex->guest_r2;
+ regs.MIPS_r3 = vex->guest_r3;
+ regs.MIPS_r4 = vex->guest_r4;
+ regs.MIPS_r5 = vex->guest_r5;
+ regs.MIPS_r6 = vex->guest_r6;
+ regs.MIPS_r7 = vex->guest_r7;
+ regs.MIPS_r8 = vex->guest_r8;
+ regs.MIPS_r9 = vex->guest_r9;
+ regs.MIPS_r10 = vex->guest_r10;
+ regs.MIPS_r11 = vex->guest_r11;
+ regs.MIPS_r12 = vex->guest_r12;
+ regs.MIPS_r13 = vex->guest_r13;
+ regs.MIPS_r14 = vex->guest_r14;
+ regs.MIPS_r15 = vex->guest_r15;
+ regs.MIPS_r16 = vex->guest_r16;
+ regs.MIPS_r17 = vex->guest_r17;
+ regs.MIPS_r18 = vex->guest_r18;
+ regs.MIPS_r19 = vex->guest_r19;
+ regs.MIPS_r20 = vex->guest_r20;
+ regs.MIPS_r21 = vex->guest_r21;
+ regs.MIPS_r22 = vex->guest_r22;
+ regs.MIPS_r23 = vex->guest_r23;
+ regs.MIPS_r24 = vex->guest_r24;
+ regs.MIPS_r25 = vex->guest_r25;
+ regs.MIPS_r26 = vex->guest_r26;
+ regs.MIPS_r27 = vex->guest_r27;
+ regs.MIPS_r28 = vex->guest_r28;
+ regs.MIPS_r29 = vex->guest_r29;
+ regs.MIPS_r30 = vex->guest_r30;
+ regs.MIPS_r31 = vex->guest_r31;
+ return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, ®s);
+
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c
index 03af598..5999f2e 100644
--- a/coregrind/m_debuginfo/d3basics.c
+++ b/coregrind/m_debuginfo/d3basics.c
@@ -410,6 +410,9 @@
# elif defined(VGP_s390x_linux)
if (regno == 15) { *a = regs->sp; return True; }
if (regno == 11) { *a = regs->fp; return True; }
+# elif defined(VGP_mips32_linux)
+ if (regno == 29) { *a = regs->sp; return True; }
+ if (regno == 30) { *a = regs->fp; return True; }
# else
# error "Unknown platform"
# endif
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index fa08d8e..99389c2 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -792,7 +792,7 @@
is_rw_map = False;
is_ro_map = False;
-# if defined(VGA_x86) || defined(VGA_ppc32)
+# if defined(VGA_x86) || defined(VGA_ppc32) || defined(VGA_mips32)
is_rx_map = seg->hasR && seg->hasX;
is_rw_map = seg->hasR && seg->hasW;
# elif defined(VGA_amd64) || defined(VGA_ppc64) || defined(VGA_arm)
@@ -1516,6 +1516,22 @@
/*offsetP*/NULL );
}
+/* mips-linux only: find the offset of current address. This is needed for
+ stack unwinding for MIPS.
+*/
+Bool VG_(get_inst_offset_in_function)( Addr a,
+ /*OUT*/PtrdiffT* offset )
+{
+ Char fnname[64];
+ return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
+ /*below-main-renaming*/False,
+ a, fnname, 64,
+ /*match_anywhere_in_sym*/True,
+ /*show offset?*/True,
+ /*data syms only please*/True,
+ offset );
+}
+
Vg_FnNameKind VG_(get_fnname_kind) ( Char* name )
{
if (VG_STREQ("main", name)) {
@@ -2040,6 +2056,11 @@
case Creg_IA_SP: return eec->uregs->sp;
case Creg_IA_BP: return eec->uregs->fp;
case Creg_S390_R14: return eec->uregs->lr;
+# elif defined(VGA_mips32)
+ case Creg_IA_IP: return eec->uregs->pc;
+ case Creg_IA_SP: return eec->uregs->sp;
+ case Creg_IA_BP: return eec->uregs->fp;
+ case Creg_MIPS_RA: return eec->uregs->ra;
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unsupported arch"
@@ -2268,6 +2289,16 @@
case CFIC_IA_BPREL:
cfa = cfsi->cfa_off + uregs->fp;
break;
+# elif defined(VGA_mips32)
+ case CFIC_IA_SPREL:
+ cfa = cfsi->cfa_off + uregs->sp;
+ break;
+ case CFIR_SAME:
+ cfa = uregs->fp;
+ break;
+ case CFIC_IA_BPREL:
+ cfa = cfsi->cfa_off + uregs->fp;
+ break;
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unsupported arch"
@@ -2362,6 +2393,8 @@
ipHere = uregsHere->r15;
# elif defined(VGA_s390x)
ipHere = uregsHere->ia;
+# elif defined(VGA_mips32)
+ ipHere = uregsHere->pc;
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unknown arch"
@@ -2438,6 +2471,10 @@
COMPUTE(uregsPrev.ia, uregsHere->ia, cfsi->ra_how, cfsi->ra_off);
COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi->sp_how, cfsi->sp_off);
COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi->fp_how, cfsi->fp_off);
+# elif defined(VGA_mips32)
+ COMPUTE(uregsPrev.pc, uregsHere->pc, cfsi->ra_how, cfsi->ra_off);
+ COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi->sp_how, cfsi->sp_off);
+ COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi->fp_how, cfsi->fp_off);
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unknown arch"
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index 53ca0d2..193b154 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -257,6 +257,21 @@
Int fp_off;
}
DiCfSI;
+#elif defined(VGA_mips32)
+typedef
+ struct {
+ Addr base;
+ UInt len;
+ UChar cfa_how; /* a CFIC_ value */
+ UChar ra_how; /* a CFIR_ value */
+ UChar sp_how; /* a CFIR_ value */
+ UChar fp_how; /* a CFIR_ value */
+ Int cfa_off;
+ Int ra_off;
+ Int sp_off;
+ Int fp_off;
+ }
+ DiCfSI;
#else
# error "Unknown arch"
#endif
@@ -288,7 +303,8 @@
Creg_ARM_R12,
Creg_ARM_R15,
Creg_ARM_R14,
- Creg_S390_R14
+ Creg_S390_R14,
+ Creg_MIPS_RA
}
CfiReg;
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 36a6698..9329fa2 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -1843,6 +1843,10 @@
# define FP_REG 11 // sometimes s390 has a frame pointer in r11
# define SP_REG 15 // stack is always r15
# define RA_REG_DEFAULT 14 // the return address is in r14
+#elif defined(VGP_mips32_linux)
+# define FP_REG 30
+# define SP_REG 29
+# define RA_REG_DEFAULT 31
#else
# error "Unknown platform"
#endif
@@ -1851,7 +1855,8 @@
arm-linux (320) seems ludicrously high, but the ARM IHI 0040A page
7 (DWARF for the ARM Architecture) specifies that values up to 320
might exist, for Neon/VFP-v3. */
-#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \
+ || defined(VGP_mips32_linux)
# define N_CFI_REGS 72
#elif defined(VGP_arm_linux)
# define N_CFI_REGS 320
@@ -2155,7 +2160,8 @@
else
if (ctxs->cfa_is_regoff && ctxs->cfa_reg == SP_REG) {
si->cfa_off = ctxs->cfa_off;
-# if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x)
+# if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x) \
+ || defined(VGA_mips32)
si->cfa_how = CFIC_IA_SPREL;
# elif defined(VGA_arm)
si->cfa_how = CFIC_ARM_R13REL;
@@ -2166,7 +2172,8 @@
else
if (ctxs->cfa_is_regoff && ctxs->cfa_reg == FP_REG) {
si->cfa_off = ctxs->cfa_off;
-# if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x)
+# if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x) \
+ || defined(VGA_mips32)
si->cfa_how = CFIC_IA_BPREL;
# elif defined(VGA_arm)
si->cfa_how = CFIC_ARM_R12REL;
@@ -2367,6 +2374,50 @@
return True;
+# elif defined(VGA_mips32)
+
+ /* --- entire tail of this fn specialised for mips --- */
+
+ SUMMARISE_HOW(si->ra_how, si->ra_off,
+ ctxs->reg[ctx->ra_reg] );
+ SUMMARISE_HOW(si->fp_how, si->fp_off,
+ ctxs->reg[FP_REG] );
+ SUMMARISE_HOW(si->sp_how, si->sp_off,
+ ctxs->reg[SP_REG] );
+ si->sp_how = CFIR_CFAREL;
+ si->sp_off = 0;
+
+ if (si->fp_how == CFIR_UNKNOWN)
+ si->fp_how = CFIR_SAME;
+ if (si->cfa_how == CFIR_UNKNOWN) {
+ si->cfa_how = CFIC_IA_SPREL;
+ si->cfa_off = 160;
+ }
+ if (si->ra_how == CFIR_UNKNOWN) {
+ if (!debuginfo->cfsi_exprs)
+ debuginfo->cfsi_exprs = VG_(newXA)( ML_(dinfo_zalloc),
+ "di.ccCt.2a",
+ ML_(dinfo_free),
+ sizeof(CfiExpr) );
+ si->ra_how = CFIR_EXPR;
+ si->ra_off = ML_(CfiExpr_CfiReg)( debuginfo->cfsi_exprs,
+ Creg_MIPS_RA);
+ }
+
+ if (si->ra_how == CFIR_SAME)
+ { why = 3; goto failed; }
+
+ if (loc_start >= ctx->loc)
+ { why = 4; goto failed; }
+ if (ctx->loc - loc_start > 10000000 /* let's say */)
+ { why = 5; goto failed; }
+
+ si->base = loc_start + ctx->initloc;
+ si->len = (UInt)(ctx->loc - loc_start);
+
+ return True;
+
+
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
@@ -2449,6 +2500,13 @@
return ML_(CfiExpr_CfiReg)( dstxa, Creg_IA_BP );
if (dwreg == srcuc->ra_reg)
return ML_(CfiExpr_CfiReg)( dstxa, Creg_IA_IP ); /* correct? */
+# elif defined(VGA_mips32)
+ if (dwreg == SP_REG)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_IA_SP );
+ if (dwreg == FP_REG)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_IA_BP );
+ if (dwreg == srcuc->ra_reg)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_IA_IP );
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unknown arch"
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index 99b213c..1654097 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -2307,8 +2307,10 @@
case DW_ATE_unsigned: case DW_ATE_unsigned_char:
case DW_ATE_UTF: /* since DWARF4, e.g. char16_t from C++ */
case DW_ATE_boolean:/* FIXME - is this correct? */
+ case DW_ATE_unsigned_fixed:
typeE.Te.TyBase.enc = 'U'; break;
case DW_ATE_signed: case DW_ATE_signed_char:
+ case DW_ATE_signed_fixed:
typeE.Te.TyBase.enc = 'S'; break;
case DW_ATE_float:
typeE.Te.TyBase.enc = 'F'; break;
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index 3a70122..40f5eea 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -1955,7 +1955,8 @@
/* PLT is different on different platforms, it seems. */
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
- || defined(VGP_arm_linux) || defined (VGP_s390x_linux)
+ || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \
+ || defined(VGP_mips32_linux)
/* Accept .plt where mapped as rx (code) */
if (0 == VG_(strcmp)(name, ".plt")) {
if (inrx && size > 0 && !di->plt_present) {
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index b90b2e7..a5fe07f 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -189,7 +189,7 @@
VG_(printf)(" R7=");
SHOW_HOW(si->r7_how, si->r7_off);
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
-# elif defined(VGA_s390x)
+# elif defined(VGA_s390x) || defined(VGA_mips32)
VG_(printf)(" SP=");
SHOW_HOW(si->sp_how, si->sp_off);
VG_(printf)(" FP=");
@@ -629,6 +629,7 @@
case Creg_ARM_R12: VG_(printf)("R12"); break;
case Creg_ARM_R15: VG_(printf)("R15"); break;
case Creg_ARM_R14: VG_(printf)("R14"); break;
+ case Creg_MIPS_RA: VG_(printf)("RA"); break;
default: vg_assert(0);
}
}
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 44f7376..8e1c032 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -388,6 +388,43 @@
return (UInt)(__res);
}
+#elif defined(VGP_mips32_linux)
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+ volatile Int block[2];
+ block[0] = (Int)buf;
+ block[1] = n;
+ __asm__ volatile (
+ "li $4, 2\n\t" /* stderr */
+ "lw $5, 0(%0)\n\t" /* buf */
+ "lw $6, 4(%0)\n\t" /* n */
+ "move $7, $0\n\t"
+ "li $2, %1\n\t" /* set v0 = __NR_write */
+ "syscall\n\t" /* write() */
+ "nop\n\t"
+ :
+ : "r" (block), "n" (__NR_write)
+ : "2", "4", "5", "6", "7"
+ );
+ if (block[0] < 0)
+ block[0] = -1;
+ return (UInt)block[0];
+}
+
+static UInt local_sys_getpid ( void )
+{
+ UInt __res;
+ __asm__ volatile (
+ "li $2, %1\n\t" /* set v0 = __NR_getpid */
+ "syscall\n\t" /* getpid() */
+ "nop\n\t"
+ "move %0, $2\n"
+ : "=r" (__res)
+ : "n" (__NR_getpid)
+ : "$2" );
+ return __res;
+}
+
#else
# error Unknown platform
diff --git a/coregrind/m_gdbserver/target.c b/coregrind/m_gdbserver/target.c
index 905efb9..6117fce 100644
--- a/coregrind/m_gdbserver/target.c
+++ b/coregrind/m_gdbserver/target.c
@@ -618,6 +618,8 @@
ppc64_init_architecture(&the_low_target);
#elif defined(VGA_s390x)
s390x_init_architecture(&the_low_target);
+#elif defined(VGA_mips32)
+ s390x_init_architecture(&the_low_target);
#else
architecture missing in target.c valgrind_initialize_target
#endif
diff --git a/coregrind/m_gdbserver/valgrind_low.h b/coregrind/m_gdbserver/valgrind_low.h
index 29dafcd..0348895 100644
--- a/coregrind/m_gdbserver/valgrind_low.h
+++ b/coregrind/m_gdbserver/valgrind_low.h
@@ -73,5 +73,6 @@
extern void ppc32_init_architecture (struct valgrind_target_ops *target);
extern void ppc64_init_architecture (struct valgrind_target_ops *target);
extern void s390x_init_architecture (struct valgrind_target_ops *target);
+extern void mips32_init_architecture (struct valgrind_target_ops *target);
#endif
diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c
index b752f01..8acc7b0 100644
--- a/coregrind/m_initimg/initimg-linux.c
+++ b/coregrind/m_initimg/initimg-linux.c
@@ -1081,6 +1081,20 @@
VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_INSTR_PTR, 8);
return;
+# elif defined(VGP_mips32_linux)
+ vg_assert(0 == sizeof(VexGuestMIPS32State) % 16);
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestMIPS32_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestMIPS32State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestMIPS32State));
+
+ arch->vex.guest_r29 = iifii.initial_client_SP;
+ arch->vex.guest_PC = iifii.initial_client_IP;
+ arch->vex.guest_r31 = iifii.initial_client_SP;
+
# else
# error Unknown platform
# endif
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index 1f5b95c..a8e7e11 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -152,6 +152,31 @@
(srP)->misc.S390X.r_fp = fp; \
(srP)->misc.S390X.r_lr = lr; \
}
+#elif defined(VGP_mips32_linux)
+# define GET_STARTREGS(srP) \
+ { UInt pc, sp, fp, ra, gp; \
+ asm("move $8, $31;" /* t0 = ra */ \
+ "bal m_libcassert_get_ip;" /* ra = pc */ \
+ "m_libcassert_get_ip:\n" \
+ "move %0, $31;" \
+ "move $31, $8;" /* restore lr */ \
+ "move %1, $29;" \
+ "move %2, $30;" \
+ "move %3, $31;" \
+ "move %4, $28;" \
+ : "=r" (pc), \
+ "=r" (sp), \
+ "=r" (fp), \
+ "=r" (ra), \
+ "=r" (gp) \
+ : /* reads none */ \
+ : "$8" /* trashed */ ); \
+ (srP)->r_pc = (ULong)pc - 8; \
+ (srP)->r_sp = (ULong)sp; \
+ (srP)->misc.MIPS32.r30 = (ULong)fp; \
+ (srP)->misc.MIPS32.r31 = (ULong)ra; \
+ (srP)->misc.MIPS32.r28 = (ULong)gp; \
+ }
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index 4bc07cb..e8368b3 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -194,7 +194,17 @@
Int VG_(pipe) ( Int fd[2] )
{
-# if defined(VGO_linux)
+# if defined(VGP_mips32_linux)
+ /* __NR_pipe has a strange return convention on mips32-linux. */
+ SysRes res = VG_(do_syscall0)(__NR_pipe);
+ if (!sr_isError(res)) {
+ fd[0] = (Int)sr_Res(res);
+ fd[1] = (Int)sr_ResEx(res);
+ return 0;
+ } else {
+ return -1;
+ }
+# elif defined(VGO_linux)
SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
return sr_isError(res) ? -1 : 0;
# elif defined(VGO_darwin)
@@ -596,6 +606,16 @@
0, // Padding needed on PPC32
0, offset); // Big endian long long
return res;
+# elif defined(VGP_mips32_linux) && VKI_LITTLE_ENDIAN
+ vg_assert(sizeof(OffT) == 4);
+ res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
+ 0, offset, 0);
+ return res;
+# elif defined(VGP_mips32_linux) && VKI_BIG_ENDIAN
+ vg_assert(sizeof(OffT) == 4);
+ res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
+ 0, 0, offset);
+ return res;
# elif defined(VGP_amd64_linux) \
|| defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
@@ -837,7 +857,8 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
return sr_isError(res) ? -1 : sr_Res(res);
-# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
return sr_isError(res) ? -1 : sr_Res(res);
@@ -875,7 +896,8 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
return sr_isError(res) ? -1 : sr_Res(res);
-# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
return sr_isError(res) ? -1 : sr_Res(res);
@@ -913,7 +935,8 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
return sr_isError(res) ? -1 : sr_Res(res);
-# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
count, VKI_MSG_NOSIGNAL, 0,0);
@@ -932,7 +955,8 @@
Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
- || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
+ || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
UWord args[3];
args[0] = sd;
@@ -961,7 +985,8 @@
Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
- || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
+ || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
UWord args[3];
args[0] = sd;
@@ -1002,7 +1027,8 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
return sr_isError(res) ? -1 : sr_Res(res);
-# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
+ || defined(VGP_mips32_linux)
SysRes res;
res = VG_(do_syscall5)( __NR_getsockopt,
(UWord)sd, (UWord)level, (UWord)optname,
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 21fee60..6f0c71b 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -549,7 +549,8 @@
# elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
|| defined(VGP_arm_linux) \
- || defined(VGO_darwin) || defined(VGP_s390x_linux)
+ || defined(VGO_darwin) || defined(VGP_s390x_linux) \
+ || defined(VGP_mips32_linux)
SysRes sres;
sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
if (sr_isError(sres))
@@ -764,6 +765,11 @@
Addr endaddr = startaddr + nbytes;
VG_(do_syscall2)(__NR_ARM_cacheflush, startaddr, endaddr);
+# elif defined(VGA_mips32)
+ SysRes sres = VG_(do_syscall3)(__NR_cacheflush, (UWord) ptr,
+ (UWord) nbytes, (UWord) 3);
+ vg_assert( sres._isError == 0 );
+
# else
# error "Unknown ARCH"
# endif
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 9980640..047c508 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -103,6 +103,15 @@
= VG_(threads)[tid].arch.vex.guest_r11;
regs->misc.S390X.r_lr
= VG_(threads)[tid].arch.vex.guest_r14;
+# elif defined(VGA_mips32)
+ regs->r_pc = VG_(threads)[tid].arch.vex.guest_PC;
+ regs->r_sp = VG_(threads)[tid].arch.vex.guest_r29;
+ regs->misc.MIPS32.r30
+ = VG_(threads)[tid].arch.vex.guest_r30;
+ regs->misc.MIPS32.r31
+ = VG_(threads)[tid].arch.vex.guest_r31;
+ regs->misc.MIPS32.r28
+ = VG_(threads)[tid].arch.vex.guest_r28;
# else
# error "Unknown arch"
# endif
@@ -132,6 +141,9 @@
# elif defined(VGP_s390x_linux)
VG_(threads)[tid].arch.vex_shadow1.guest_r2 = s1res;
VG_(threads)[tid].arch.vex_shadow2.guest_r2 = s2res;
+# elif defined(VGP_mips32_linux)
+ VG_(threads)[tid].arch.vex_shadow1.guest_r2 = s1res;
+ VG_(threads)[tid].arch.vex_shadow2.guest_r2 = s2res;
# else
# error "Unknown plat"
# endif
@@ -282,6 +294,39 @@
(*f)(tid, "r13", vex->guest_r13);
(*f)(tid, "r14", vex->guest_r14);
(*f)(tid, "r15", vex->guest_r15);
+#elif defined(VGA_mips32)
+ (*f)(tid, "r0" , vex->guest_r0 );
+ (*f)(tid, "r1" , vex->guest_r1 );
+ (*f)(tid, "r2" , vex->guest_r2 );
+ (*f)(tid, "r3" , vex->guest_r3 );
+ (*f)(tid, "r4" , vex->guest_r4 );
+ (*f)(tid, "r5" , vex->guest_r5 );
+ (*f)(tid, "r6" , vex->guest_r6 );
+ (*f)(tid, "r7" , vex->guest_r7 );
+ (*f)(tid, "r8" , vex->guest_r8 );
+ (*f)(tid, "r9" , vex->guest_r9 );
+ (*f)(tid, "r10", vex->guest_r10);
+ (*f)(tid, "r11", vex->guest_r11);
+ (*f)(tid, "r12", vex->guest_r12);
+ (*f)(tid, "r13", vex->guest_r13);
+ (*f)(tid, "r14", vex->guest_r14);
+ (*f)(tid, "r15", vex->guest_r15);
+ (*f)(tid, "r16", vex->guest_r16);
+ (*f)(tid, "r17", vex->guest_r17);
+ (*f)(tid, "r18", vex->guest_r18);
+ (*f)(tid, "r19", vex->guest_r19);
+ (*f)(tid, "r20", vex->guest_r20);
+ (*f)(tid, "r21", vex->guest_r21);
+ (*f)(tid, "r22", vex->guest_r22);
+ (*f)(tid, "r23", vex->guest_r23);
+ (*f)(tid, "r24", vex->guest_r24);
+ (*f)(tid, "r25", vex->guest_r25);
+ (*f)(tid, "r26", vex->guest_r26);
+ (*f)(tid, "r27", vex->guest_r27);
+ (*f)(tid, "r28", vex->guest_r28);
+ (*f)(tid, "r29", vex->guest_r29);
+ (*f)(tid, "r30", vex->guest_r30);
+ (*f)(tid, "r31", vex->guest_r31);
#else
# error Unknown arch
#endif
@@ -389,7 +434,7 @@
/* For hwcaps detection on ppc32/64, s390x, and arm we'll need to do SIGILL
testing, so we need a VG_MINIMAL_JMP_BUF. */
#if defined(VGA_ppc32) || defined(VGA_ppc64) \
- || defined(VGA_arm) || defined(VGA_s390x)
+ || defined(VGA_arm) || defined(VGA_s390x) || defined(VGA_mips32)
#include "pub_tool_libcsetjmp.h"
static VG_MINIMAL_JMP_BUF(env_unsup_insn);
static void handler_unsup_insn ( Int x ) {
@@ -568,6 +613,64 @@
#endif /* VGA_s390x */
+#ifdef VGA_mips32
+
+/* Read /proc/cpuinfo and return the machine model. */
+static UInt VG_(get_machine_model)(void)
+{
+ char *search_MIPS_str = "MIPS";
+ char *search_Broadcom_str = "Broadcom";
+ Int n, fh;
+ SysRes fd;
+ SizeT num_bytes, file_buf_size;
+ HChar *file_buf;
+
+ /* Slurp contents of /proc/cpuinfo into FILE_BUF */
+ fd = VG_(open)( "/proc/cpuinfo", 0, VKI_S_IRUSR );
+ if ( sr_isError(fd) ) return -1;
+
+ fh = sr_Res(fd);
+
+ /* Determine the size of /proc/cpuinfo.
+ Work around broken-ness in /proc file system implementation.
+ fstat returns a zero size for /proc/cpuinfo although it is
+ claimed to be a regular file. */
+ num_bytes = 0;
+ file_buf_size = 1000;
+ file_buf = VG_(malloc)("cpuinfo", file_buf_size + 1);
+ while (42) {
+ n = VG_(read)(fh, file_buf, file_buf_size);
+ if (n < 0) break;
+
+ num_bytes += n;
+ if (n < file_buf_size) break; /* reached EOF */
+ }
+
+ if (n < 0) num_bytes = 0; /* read error; ignore contents */
+
+ if (num_bytes > file_buf_size) {
+ VG_(free)( file_buf );
+ VG_(lseek)( fh, 0, VKI_SEEK_SET );
+ file_buf = VG_(malloc)( "cpuinfo", num_bytes + 1 );
+ n = VG_(read)( fh, file_buf, num_bytes );
+ if (n < 0) num_bytes = 0;
+ }
+
+ file_buf[num_bytes] = '\0';
+ VG_(close)(fh);
+
+ /* Parse file */
+ if (VG_(strstr) (file_buf, search_Broadcom_str) != NULL)
+ return VEX_PRID_COMP_BROADCOM;
+ if (VG_(strstr) (file_buf, search_MIPS_str) != NULL)
+ return VEX_PRID_COMP_MIPS;
+
+ /* Did not find string in the proc file. */
+ return -1;
+}
+
+#endif
+
/* Determine what insn set and insn set variant the host has, and
record it. To be called once at system startup. Returns False if
this a CPU incapable of running Valgrind. */
@@ -1249,6 +1352,17 @@
return True;
}
+#elif defined(VGA_mips32)
+ {
+ va = VexArchMIPS32;
+ UInt model = VG_(get_machine_model)();
+ if (model== -1)
+ return False;
+
+ vai.hwcaps = model;
+ return True;
+ }
+
#else
# error "Unknown arch"
#endif
@@ -1370,6 +1484,11 @@
assume we always do. */
return 16;
+# elif defined(VGA_mips32)
+ /* The guest state implies 4, but that can't really be true, can
+ it? */
+ return 8;
+
# else
# error "Unknown arch"
# endif
@@ -1383,7 +1502,7 @@
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
|| defined(VGP_arm_linux) \
|| defined(VGP_ppc32_linux) || defined(VGO_darwin) \
- || defined(VGP_s390x_linux)
+ || defined(VGP_s390x_linux) || defined(VGP_mips32_linux)
return f;
# elif defined(VGP_ppc64_linux)
/* ppc64-linux uses the AIX scheme, in which f is a pointer to a
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 71065ce..7a35112 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -1539,8 +1539,10 @@
// p: logging, plausible-stack
//--------------------------------------------------------------
VG_(debugLog)(1, "main", "Starting the address space manager\n");
- vg_assert(VKI_PAGE_SIZE == 4096 || VKI_PAGE_SIZE == 65536);
- vg_assert(VKI_MAX_PAGE_SIZE == 4096 || VKI_MAX_PAGE_SIZE == 65536);
+ vg_assert(VKI_PAGE_SIZE == 4096 || VKI_PAGE_SIZE == 65536
+ || VKI_PAGE_SIZE == 16384);
+ vg_assert(VKI_MAX_PAGE_SIZE == 4096 || VKI_MAX_PAGE_SIZE == 65536
+ || VKI_MAX_PAGE_SIZE == 16384);
vg_assert(VKI_PAGE_SIZE <= VKI_MAX_PAGE_SIZE);
vg_assert(VKI_PAGE_SIZE == (1 << VKI_PAGE_SHIFT));
vg_assert(VKI_MAX_PAGE_SIZE == (1 << VKI_MAX_PAGE_SHIFT));
@@ -1894,6 +1896,8 @@
iters = 5;
# elif defined(VGP_s390x_linux)
iters = 10;
+# elif defined(VGP_mips32_linux)
+ iters = 10;
# elif defined(VGO_darwin)
iters = 3;
# else
@@ -2473,6 +2477,10 @@
# if defined(VGP_ppc64_linux)
VG_(threads)[tid].arch.vex.guest_GPR2 = r2;
# endif
+ /* mips-linux note: we need to set t9 */
+# if defined(VGP_mips32_linux)
+ VG_(threads)[tid].arch.vex.guest_r25 = __libc_freeres_wrapper;
+# endif
/* Block all blockable signals by copying the real block state into
the thread's block state*/
@@ -2761,6 +2769,50 @@
"\t.word "VG_STRINGIFY(VG_STACK_GUARD_SZB)"\n"
"\t.word "VG_STRINGIFY(VG_STACK_ACTIVE_SZB)"\n"
);
+#elif defined(VGP_mips32_linux)
+asm("\n"
+ "\t.type _gp_disp,@object\n"
+ ".text\n"
+ "\t.globl __start\n"
+ "\t.type __start,@function\n"
+ "__start:\n"
+
+ "\tbal 1f\n"
+ "\tnop\n"
+
+ "1:\n"
+
+ "\tlui $28, %hi(_gp_disp)\n"
+ "\taddiu $28, $28, %lo(_gp_disp)\n"
+ "\taddu $28, $28, $31\n"
+ /* t1/$9 <- Addr(interim_stack) */
+ "\tlui $9, %hi(vgPlain_interim_stack)\n"
+ /* t1/$9 <- Addr(interim_stack) */
+ "\taddiu $9, %lo(vgPlain_interim_stack)\n"
+
+
+ "\tli $10, "VG_STRINGIFY(VG_STACK_GUARD_SZB)"\n"
+ "\tli $11, "VG_STRINGIFY(VG_STACK_ACTIVE_SZB)"\n"
+
+ "\taddu $9, $9, $10\n"
+ "\taddu $9, $9, $11\n"
+ "\tli $12, 0xFFFFFFF0\n"
+ "\tand $9, $9, $12\n"
+ /* now t1/$9 = &vgPlain_interim_stack + VG_STACK_GUARD_SZB +
+ VG_STACK_ACTIVE_SZB rounded down to the nearest 16-byte
+ boundary. And $29 is the original SP. Set the SP to t1 and
+ call _start_in_C, passing it the initial SP. */
+
+ "\tmove $4, $29\n" // a0 <- $sp (_start_in_C first arg)
+ "\tmove $29, $9\n" // $sp <- t1 (new sp)
+
+ "\tlui $25, %hi(_start_in_C_linux)\n"
+ "\taddiu $25, %lo(_start_in_C_linux)\n"
+
+ "\tbal _start_in_C_linux\n"
+ "\tbreak 0x7\n"
+ ".previous\n"
+);
#else
# error "Unknown linux platform"
#endif
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index fd24c1a..50e00ac 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -1358,6 +1358,17 @@
# elif defined(VGP_s390x_linux)
/* nothing so far */
+# elif defined(VGP_mips32_linux)
+ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+
+ /* this is mandatory - can't sanely continue without it */
+ add_hardwired_spec(
+ "ld.so.3", "strlen",
+ (Addr)&VG_(mips32_linux_REDIR_FOR_strlen),
+ complain_about_stripped_glibc_ldso
+ );
+ }
+
# else
# error Unknown platform
# endif
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 4c7ef60..93fa109 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -780,6 +780,10 @@
# if defined(VGA_s390x)
/* no special requirements */
# endif
+
+# if defined(VGA_mips32)
+ /* no special requirements */
+# endif
}
// NO_VGDB_POLL value ensures vgdb is not polled, while
@@ -1557,6 +1561,9 @@
#elif defined (VGA_s390x)
# define VG_CLREQ_ARGS guest_r2
# define VG_CLREQ_RET guest_r3
+#elif defined(VGA_mips32)
+# define VG_CLREQ_ARGS guest_r12
+# define VG_CLREQ_RET guest_r11
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 81a53b1..9ef6b85 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -516,6 +516,25 @@
(srP)->misc.S390X.r_lr = (uc)->uc_mcontext.regs.gprs[14]; \
}
+#elif defined(VGP_mips32_linux)
+# define VG_UCONTEXT_INSTR_PTR(uc) ((UWord)(((uc)->uc_mcontext.sc_pc)))
+# define VG_UCONTEXT_STACK_PTR(uc) ((UWord)((uc)->uc_mcontext.sc_regs[29]))
+# define VG_UCONTEXT_FRAME_PTR(uc) ((uc)->uc_mcontext.sc_regs[30])
+# define VG_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.sc_regs[2])
+# define VG_UCONTEXT_SYSCALL_SYSRES(uc) \
+ /* Convert the value in uc_mcontext.rax into a SysRes. */ \
+ VG_(mk_SysRes_mips32_linux)( (uc)->uc_mcontext.sc_regs[2], \
+ (uc)->uc_mcontext.sc_regs[3], \
+ (uc)->uc_mcontext.sc_regs[7])
+
+# define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc) \
+ { (srP)->r_pc = (uc)->uc_mcontext.sc_pc; \
+ (srP)->r_sp = (uc)->uc_mcontext.sc_regs[29]; \
+ (srP)->misc.MIPS32.r30 = (uc)->uc_mcontext.sc_regs[30]; \
+ (srP)->misc.MIPS32.r31 = (uc)->uc_mcontext.sc_regs[31]; \
+ (srP)->misc.MIPS32.r28 = (uc)->uc_mcontext.sc_regs[28]; \
+ }
+
#else
# error Unknown platform
@@ -849,6 +868,14 @@
" svc " #name "\n" \
".previous\n"
+#elif defined(VGP_mips32_linux)
+# define _MY_SIGRETURN(name) \
+ ".text\n" \
+ "my_sigreturn:\n" \
+ " li $2, " #name "\n" /* apparently $2 is v0 */ \
+ " syscall\n" \
+ ".previous\n"
+
#else
# error Unknown platform
#endif
@@ -891,7 +918,8 @@
ksa.ksa_handler = skss.skss_per_sig[sig].skss_handler;
ksa.sa_flags = skss.skss_per_sig[sig].skss_flags;
# if !defined(VGP_ppc32_linux) && \
- !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+ !defined(VGP_mips32_linux)
ksa.sa_restorer = my_sigreturn;
# endif
/* Re above ifdef (also the assertion below), PaulM says:
@@ -924,7 +952,8 @@
vg_assert(ksa_old.sa_flags
== skss_old.skss_per_sig[sig].skss_flags);
# if !defined(VGP_ppc32_linux) && \
- !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+ !defined(VGP_mips32_linux)
vg_assert(ksa_old.sa_restorer
== my_sigreturn);
# endif
@@ -1855,6 +1884,27 @@
info.si_signo = VKI_SIGTRAP;
info.si_code = VKI_TRAP_BRKPT; /* tjh: only ever called for a brkpt ins */
+# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
+ /* This is for teq on mips. Teq on mips for ins: 0xXXX1f4
+ * cases VKI_SIGFPE not VKI_SIGTRAP
+ */
+ // JRS 2012-Jun-06: commented out until we know we need it
+ // This isn't a clean solution; need something that avoids looking
+ // at the guest code.
+ //UInt *ins = (void*)(vgPlain_threads[tid].arch.vex.guest_PC-4);
+ //UInt tcode = (((*ins) >> 6) & ((1 << 10) - 1));
+ //if (tcode == VKI_BRK_OVERFLOW || tcode == VKI_BRK_DIVZERO) {
+ // if (tcode == VKI_BRK_DIVZERO)
+ // info.si_code = VKI_FPE_INTDIV;
+ // else
+ // info.si_code = VKI_FPE_INTOVF;
+ // info.si_signo = VKI_SIGFPE;
+ // info.si_errno = 0;
+ // info.VKI_SIGINFO_si_addr
+ // = (void*)(vgPlain_threads[tid].arch.vex.guest_PC-4);
+ //}
+# endif
+
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
uc.uc_mcontext.trapno = 3; /* tjh: this is the x86 trap number
for a breakpoint trap... */
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index bb76931..19b347b 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -668,7 +668,9 @@
#endif
/* ------------------------ s390x ------------------------- */
+
#if defined(VGP_s390x_linux)
+
UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
/*OUT*/Addr* ips, UInt max_n_ips,
/*OUT*/Addr* sps, /*OUT*/Addr* fps,
@@ -744,8 +746,157 @@
n_found = i;
return n_found;
}
+
#endif
+/* ------------------------ mips 32------------------------- */
+
+#if defined(VGP_mips32_linux)
+
+UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
+ /*OUT*/Addr* ips, UInt max_n_ips,
+ /*OUT*/Addr* sps, /*OUT*/Addr* fps,
+ UnwindStartRegs* startRegs,
+ Addr fp_max_orig )
+{
+ Bool debug = False;
+ Int i;
+ Addr fp_max;
+ UInt n_found = 0;
+
+ vg_assert(sizeof(Addr) == sizeof(UWord));
+ vg_assert(sizeof(Addr) == sizeof(void*));
+
+ D3UnwindRegs uregs;
+ uregs.pc = startRegs->r_pc;
+ uregs.sp = startRegs->r_sp;
+ Addr fp_min = uregs.sp;
+
+ uregs.fp = startRegs->misc.MIPS32.r30;
+ uregs.ra = startRegs->misc.MIPS32.r31;
+
+ /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1],
+ stopping when the trail goes cold, which we guess to be
+ when FP is not a reasonable stack location. */
+
+ fp_max = VG_PGROUNDUP(fp_max_orig);
+ if (fp_max >= sizeof(Addr))
+ fp_max -= sizeof(Addr);
+
+ if (debug)
+ VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, "
+ "fp_max=0x%lx pc=0x%lx sp=0x%lx fp=0x%lx\n",
+ max_n_ips, fp_min, fp_max_orig, fp_max,
+ uregs.pc, uregs.sp, uregs.fp);
+
+ if (sps) sps[0] = uregs.sp;
+ if (fps) fps[0] = uregs.fp;
+ ips[0] = uregs.pc;
+ i = 1;
+
+ /* Loop unwinding the stack. */
+
+ while (True) {
+ if (debug) {
+ VG_(printf)("i: %d, pc: 0x%lx, sp: 0x%lx, ra: 0x%lx\n",
+ i, uregs.pc, uregs.sp, uregs.ra);
+ }
+ if (i >= max_n_ips)
+ break;
+
+ if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) {
+ if (debug)
+ VG_(printf)("USING CFI: pc: 0x%lx, sp: 0x%lx, ra: 0x%lx\n",
+ uregs.pc, uregs.sp, uregs.ra);
+ if (0 == uregs.pc || 1 == uregs.pc) break;
+ if (sps) sps[i] = uregs.sp;
+ if (fps) fps[i] = uregs.fp;
+ ips[i++] = uregs.pc - 4;
+ uregs.pc = uregs.pc - 4;
+ continue;
+ }
+
+ int seen_sp_adjust = 0;
+ long frame_offset = 0;
+ PtrdiffT offset;
+ if (VG_(get_inst_offset_in_function)(uregs.pc, &offset)) {
+ Addr start_pc = uregs.pc - offset;
+ Addr limit_pc = uregs.pc;
+ Addr cur_pc;
+ for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
+ unsigned long inst, high_word, low_word;
+ unsigned long * cur_inst;
+ int reg;
+ /* Fetch the instruction. */
+ cur_inst = (unsigned long *)cur_pc;
+ inst = *((UInt *) cur_inst);
+ if(debug)
+ VG_(printf)("cur_pc: 0x%lx, inst: 0x%lx\n", cur_pc, inst);
+
+ /* Save some code by pre-extracting some useful fields. */
+ high_word = (inst >> 16) & 0xffff;
+ low_word = inst & 0xffff;
+ reg = high_word & 0x1f;
+
+ if (high_word == 0x27bd /* addiu $sp,$sp,-i */
+ || high_word == 0x23bd /* addi $sp,$sp,-i */
+ || high_word == 0x67bd) { /* daddiu $sp,$sp,-i */
+ if (low_word & 0x8000) /* negative stack adjustment? */
+ frame_offset += 0x10000 - low_word;
+ else
+ /* Exit loop if a positive stack adjustment is found, which
+ usually means that the stack cleanup code in the function
+ epilogue is reached. */
+ break;
+ seen_sp_adjust = 1;
+ }
+ }
+ if(debug)
+ VG_(printf)("offset: 0x%lx\n", frame_offset);
+ }
+ if (seen_sp_adjust) {
+ if (0 == uregs.pc || 1 == uregs.pc) break;
+ if (uregs.pc == uregs.ra - 8) break;
+ if (sps) {
+ sps[i] = uregs.sp + frame_offset;
+ }
+ uregs.sp = uregs.sp + frame_offset;
+
+ if (fps) {
+ fps[i] = fps[0];
+ uregs.fp = fps[0];
+ }
+ if (0 == uregs.ra || 1 == uregs.ra) break;
+ uregs.pc = uregs.ra - 8;
+ ips[i++] = uregs.ra - 8;
+ continue;
+ }
+
+ if (i == 1) {
+ if (sps) {
+ sps[i] = sps[0];
+ uregs.sp = sps[0];
+ }
+ if (fps) {
+ fps[i] = fps[0];
+ uregs.fp = fps[0];
+ }
+ if (0 == uregs.ra || 1 == uregs.ra) break;
+ uregs.pc = uregs.ra - 8;
+ ips[i++] = uregs.ra - 8;
+ continue;
+ }
+ /* No luck. We have to give up. */
+ break;
+ }
+
+ n_found = i;
+ return n_found;
+}
+
+#endif
+
+
/*------------------------------------------------------------*/
/*--- ---*/
/*--- END platform-dependent unwinder worker functions ---*/
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index 05083d5..a52aeb0 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -62,6 +62,7 @@
SysRes VG_(mk_SysRes_x86_linux) ( Int val ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = val >= -4095 && val <= -1;
if (res._isError) {
res._val = (UInt)(-val);
@@ -74,6 +75,7 @@
/* Similarly .. */
SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = val >= -4095 && val <= -1;
if (res._isError) {
res._val = (ULong)(-val);
@@ -87,6 +89,7 @@
/* Note this must be in the bottom bit of the second arg */
SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = (cr0so & 1) != 0;
res._val = val;
return res;
@@ -95,6 +98,7 @@
/* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = (cr0so & 1) != 0;
res._val = val;
return res;
@@ -102,6 +106,7 @@
SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = val >= -4095 && val <= -1;
if (res._isError) {
res._val = -val;
@@ -113,6 +118,7 @@
SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
SysRes res;
+ res._valEx = 0; /* unused except on mips-linux */
res._isError = val >= -4095 && val <= -1;
if (res._isError) {
res._val = (UInt)(-val);
@@ -122,9 +128,19 @@
return res;
}
+/* MIPS uses a3 != 0 to flag an error */
+SysRes VG_(mk_SysRes_mips32_linux) ( UWord v0, UWord v1, UWord a3 ) {
+ SysRes res;
+ res._isError = (a3 != (UWord)0);
+ res._val = v0;
+ res._valEx = v1;
+ return res;
+}
+
/* Generic constructors. */
SysRes VG_(mk_SysRes_Error) ( UWord err ) {
SysRes r;
+ r._valEx = 0; /* unused except on mips-linux */
r._isError = True;
r._val = err;
return r;
@@ -132,6 +148,7 @@
SysRes VG_(mk_SysRes_Success) ( UWord res ) {
SysRes r;
+ r._valEx = 0; /* unused except on mips-linux */
r._isError = False;
r._val = res;
return r;
@@ -575,6 +592,40 @@
return (UWord) (__svcres);
}
+#elif defined(VGP_mips32_linux)
+/* Incoming args (syscall number + up to 6 args) come in a0 - a3 and stack.
+
+ The syscall number goes in v0. The args are passed to the syscall in
+ the regs a0 - a3 and stack, i.e. the kernel's syscall calling convention.
+
+ (a3 != 0) flags an error.
+ We return the syscall return value in v0.
+ MIPS version
+*/
+extern int do_syscall_WRK (
+ int a1, int a2, int a3,
+ int a4, int a5, int a6, int syscall_no, UWord *err,
+ UWord *valHi, UWord* valLo
+ );
+asm(
+".globl do_syscall_WRK\n"
+".ent do_syscall_WRK\n"
+".text\n"
+"do_syscall_WRK:\n"
+" lw $2, 24($29)\n"
+" syscall\n"
+" lw $8, 28($29)\n"
+" sw $7, ($8)\n"
+" lw $8, 32($29)\n"
+" sw $3, ($8)\n" // store valHi
+" lw $8, 36($29)\n"
+" sw $2, ($8)\n" // store valLo
+" jr $31\n"
+" nop\n"
+".previous\n"
+".end do_syscall_WRK\n"
+);
+
#else
# error Unknown platform
#endif
@@ -682,6 +733,13 @@
}
return VG_(mk_SysRes_s390x_linux)( val );
+
+#elif defined(VGP_mips32_linux)
+ UWord err = 0;
+ UWord valHi = 0;
+ UWord valLo = 0;
+ (void) do_syscall_WRK(a1,a2,a3,a4,a5,a6, sysno,&err,&valHi,&valLo);
+ return VG_(mk_SysRes_mips32_linux)( valLo, valHi, (ULong)err );
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h
index 8069cbd..9040148 100644
--- a/coregrind/m_syswrap/priv_types_n_macros.h
+++ b/coregrind/m_syswrap/priv_types_n_macros.h
@@ -98,6 +98,15 @@
Int o_arg6;
Int uu_arg7;
Int uu_arg8;
+# elif defined(VGP_mips32_linux)
+ Int o_arg1;
+ Int o_arg2;
+ Int o_arg3;
+ Int o_arg4;
+ Int s_arg5;
+ Int s_arg6;
+ Int uu_arg7;
+ Int uu_arg8;
# elif defined(VGP_x86_darwin)
Int s_arg1;
Int s_arg2;
@@ -167,6 +176,16 @@
fixed sized table exposed to the caller, but that's too inflexible;
hence now use a function which can do arbitrary messing around to
find the required entry. */
+#if defined(VGP_mips32_linux)
+ /* Up to 6 parameters, 4 in registers 2 on stack. */
+# define PRA1(s,t,a) PRRAn(1,s,t,a)
+# define PRA2(s,t,a) PRRAn(2,s,t,a)
+# define PRA3(s,t,a) PRRAn(3,s,t,a)
+# define PRA4(s,t,a) PRRAn(4,s,t,a)
+# define PRA5(s,t,a) PSRAn(5,s,t,a)
+# define PRA6(s,t,a) PSRAn(6,s,t,a)
+
+#endif
#if defined(VGO_linux)
extern
SyscallTableEntry* ML_(get_linux_syscall_entry)( UInt sysno );
@@ -359,7 +378,16 @@
PRAn == "pre-read-argument"
*/
-#if defined(VGO_linux)
+#if defined(VGP_mips32_linux)
+ /* Up to 6 parameters, 4 in registers 2 on stack. */
+# define PRA1(s,t,a) PRRAn(1,s,t,a)
+# define PRA2(s,t,a) PRRAn(2,s,t,a)
+# define PRA3(s,t,a) PRRAn(3,s,t,a)
+# define PRA4(s,t,a) PRRAn(4,s,t,a)
+# define PRA5(s,t,a) PSRAn(5,s,t,a)
+# define PRA6(s,t,a) PSRAn(6,s,t,a)
+
+#elif defined(VGO_linux) && !defined(VGP_mips32_linux)
/* Up to 6 parameters, all in registers. */
# define PRA1(s,t,a) PRRAn(1,s,t,a)
# define PRA2(s,t,a) PRRAn(2,s,t,a)
@@ -480,6 +508,18 @@
since the least significant parts of the guest register are stored
in memory at the highest address.
*/
+#if (defined(VGP_mips32_linux) && defined (_MIPSEB))
+ #define PSRAn_BE(n,s,t,a) \
+ do { \
+ Addr next = layout->s_arg##n + sizeof(UWord) + \
+ VG_(threads)[tid].arch.vex.guest_r29; \
+ vg_assert(sizeof(t) <= sizeof(UWord)); \
+ VG_(tdict).track_pre_mem_read( \
+ Vg_CoreSysCallArgInMem, tid, s"("#a")", \
+ next-sizeof(t), sizeof(t) \
+ ); \
+ } while (0)
+#else
#define PSRAn_BE(n,s,t,a) \
do { \
Addr next = layout->o_arg##n + sizeof(UWord) + \
@@ -490,6 +530,7 @@
next-sizeof(t), sizeof(t) \
); \
} while (0)
+#endif
#if defined(VG_BIGENDIAN)
# define PSRAn(n,s,t,a) PSRAn_BE(n,s,t,a)
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 62eb3bf..7d97b6f 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -271,6 +271,17 @@
: "d" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
: "2"
);
+#elif defined(VGP_mips32_linux)
+ asm volatile (
+ "sw %1, %0\n\t" /* set tst->status = VgTs_Empty */
+ "li $2, %2\n\t" /* set v0 = __NR_exit */
+ "lw $4, %3\n\t" /* set a0 = tst->os_state.exitcode */
+ "syscall\n\t" /* exit(tst->os_state.exitcode) */
+ "nop"
+ : "=m" (tst->status)
+ : "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
+ : "cc", "memory" , "v0", "a0"
+ );
#else
# error Unknown platform
#endif
@@ -414,7 +425,7 @@
VG_(clone) stuff */
#if defined(VGP_x86_linux) \
|| defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \
- || defined(VGP_arm_linux)
+ || defined(VGP_arm_linux) || defined(VGP_mips32_linux)
res = VG_(do_syscall5)( __NR_clone, flags,
(UWord)NULL, (UWord)parent_tidptr,
(UWord)NULL, (UWord)child_tidptr );
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index 991e009..8c31dd1 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -68,6 +68,7 @@
ppc32 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
ppc64 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
arm r7 r0 r1 r2 r3 r4 r5 n/a n/a r0 (== ARG1)
+ mips v0 a0 a1 a2 a3 stack stack n/a n/a v0 (== NUM)
On s390x the svc instruction is used for system calls. The system call
number is encoded in the instruction (8 bit immediate field). Since Linux
@@ -462,6 +463,27 @@
canonical->arg7 = 0;
canonical->arg8 = 0;
+#elif defined(VGP_mips32_linux)
+ VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
+ canonical->sysno = gst->guest_r2; // v0
+ if (canonical->sysno != __NR_syscall) {
+ canonical->arg1 = gst->guest_r4; // a0
+ canonical->arg2 = gst->guest_r5; // a1
+ canonical->arg3 = gst->guest_r6; // a2
+ canonical->arg4 = gst->guest_r7; // a3
+ canonical->arg5 = *((UInt*) (gst->guest_r29 + 16)); // 16(guest_SP/sp)
+ canonical->arg6 = *((UInt*) (gst->guest_r29 + 20)); // 20(sp)
+ } else {
+ // Fixme hack handle syscall()
+ canonical->sysno = gst->guest_r4; // a0
+ canonical->arg1 = gst->guest_r5; // a1
+ canonical->arg2 = gst->guest_r6; // a2
+ canonical->arg3 = gst->guest_r7; // a3
+ canonical->arg4 = *((UInt*) (gst->guest_r29 + 16)); // 16(guest_SP/sp)
+ canonical->arg5 = *((UInt*) (gst->guest_r29 + 20)); // 20(guest_SP/sp)
+ canonical->arg6 = *((UInt*) (gst->guest_r29 + 24)); // 24(guest_SP/sp)
+ }
+
#elif defined(VGP_x86_darwin)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
UWord *stack = (UWord *)gst->guest_ESP;
@@ -695,6 +717,16 @@
gst->guest_r6 = canonical->arg5;
gst->guest_r7 = canonical->arg6;
+#elif defined(VGP_mips32_linux)
+ VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
+ gst->guest_r2 = canonical->sysno;
+ gst->guest_r4 = canonical->arg1;
+ gst->guest_r5 = canonical->arg2;
+ gst->guest_r6 = canonical->arg3;
+ gst->guest_r7 = canonical->arg4;
+ *((UInt*) (gst->guest_r29 + 16)) = canonical->arg5; // 16(guest_GPR29/sp)
+ *((UInt*) (gst->guest_r29 + 20)) = canonical->arg6; // 20(sp)
+
#else
# error "putSyscallArgsIntoGuestState: unknown arch"
#endif
@@ -733,6 +765,14 @@
canonical->sres = VG_(mk_SysRes_arm_linux)( gst->guest_R0 );
canonical->what = SsComplete;
+# elif defined(VGP_mips32_linux)
+ VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
+ UInt v0 = gst->guest_r2; // v0
+ UInt v1 = gst->guest_r3; // v1
+ UInt a3 = gst->guest_r7; // a3
+ canonical->sres = VG_(mk_SysRes_mips32_linux)( v0, v1, a3 );
+ canonical->what = SsComplete;
+
# elif defined(VGP_x86_darwin)
/* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
@@ -965,6 +1005,24 @@
gst->guest_r2 = sr_Res(canonical->sres);
}
+# elif defined(VGP_mips32_linux)
+ VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
+ vg_assert(canonical->what == SsComplete);
+ if (sr_isError(canonical->sres)) {
+ gst->guest_r2 = (Int)sr_Err(canonical->sres);
+ gst->guest_r7 = (Int)sr_Err(canonical->sres);
+ } else {
+ gst->guest_r2 = sr_Res(canonical->sres);
+ gst->guest_r3 = sr_ResEx(canonical->sres);
+ gst->guest_r7 = (Int)sr_Err(canonical->sres);
+ }
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_mips32_r2, sizeof(UWord) );
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_mips32_r3, sizeof(UWord) );
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_mips32_r7, sizeof(UWord) );
+
# else
# error "putSyscallStatusIntoGuestState: unknown arch"
# endif
@@ -1033,6 +1091,17 @@
layout->uu_arg7 = -1; /* impossible value */
layout->uu_arg8 = -1; /* impossible value */
+#elif defined(VGP_mips32_linux)
+ layout->o_sysno = OFFSET_mips32_r2;
+ layout->o_arg1 = OFFSET_mips32_r4;
+ layout->o_arg2 = OFFSET_mips32_r5;
+ layout->o_arg3 = OFFSET_mips32_r6;
+ layout->o_arg4 = OFFSET_mips32_r7;
+ layout->s_arg5 = sizeof(UWord) * 4;
+ layout->s_arg6 = sizeof(UWord) * 5;
+ layout->uu_arg7 = -1; /* impossible value */
+ layout->uu_arg8 = -1; /* impossible value */
+
#elif defined(VGP_x86_darwin)
layout->o_sysno = OFFSET_x86_EAX;
// syscall parameters are on stack in C convention
@@ -1887,11 +1956,45 @@
vg_assert(p[0] == 0x0A);
}
+
+#elif defined(VGP_mips32_linux)
+
+ arch->vex.guest_PC -= 4; // sizeof(mips instr)
+
+ /* Make sure our caller is actually sane, and we're really backing
+ back over a syscall.
+
+ syscall == 00 00 00 0C
+ big endian
+ syscall == 0C 00 00 00
+ */
+ {
+ UChar *p = (UChar *)(arch->vex.guest_PC);
+# if defined (VG_LITTLEENDIAN)
+ if (p[0] != 0x0c || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x00)
+ VG_(message)(Vg_DebugMsg,
+ "?! restarting over syscall at %#x %02x %02x %02x %02x\n",
+ arch->vex.guest_PC, p[0], p[1], p[2], p[3]);
+
+ vg_assert(p[0] == 0x0c && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x00);
+# elif defined (VG_BIGENDIAN)
+ if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x0c)
+ VG_(message)(Vg_DebugMsg,
+ "?! restarting over syscall at %#x %02x %02x %02x %02x\n",
+ arch->vex.guest_PC, p[0], p[1], p[2], p[3]);
+
+ vg_assert(p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x0c);
+# else
+# error "Unknown endianness"
+# endif
+ }
+
#else
# error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
#endif
}
+
/*
Fix up the guest state when a syscall is interrupted by a signal
and so has been forced to return 'sysret'.
@@ -1902,7 +2005,7 @@
1. unblock signals
2. perform syscall
- 3. save result to guest state (EAX, RAX, R3+CR0.SO)
+ 3. save result to guest state (EAX, RAX, R3+CR0.SO, R0, V0)
4. re-block signals
If a signal
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 73ef862..d10b840 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -1021,6 +1021,64 @@
VG_(trampoline_stuff_end):
.fill 2048, 2, 0x0000
+/*---------------------- mips32-linux ----------------------*/
+#else
+#if defined(VGP_mips32_linux)
+
+# define UD2_16 trap ; trap ; trap; trap
+# define UD2_64 UD2_16 ; UD2_16 ; UD2_16 ; UD2_16
+# define UD2_256 UD2_64 ; UD2_64 ; UD2_64 ; UD2_64
+# define UD2_1024 UD2_256 ; UD2_256 ; UD2_256 ; UD2_256
+# define UD2_PAGE UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024
+
+
+.global VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+.global VG_(mips32_linux_SUBST_FOR_sigreturn)
+VG_(mips32_linux_SUBST_FOR_sigreturn):
+ li $v0,__NR_sigreturn
+ syscall
+ nop
+ .long 0 /*illegal insn*/
+
+.global VG_(mips32_linux_SUBST_FOR_rt_sigreturn)
+VG_(mips32_linux_SUBST_FOR_rt_sigreturn):
+ li $v0,__NR_rt_sigreturn
+ syscall
+ nop
+ .long 0 /*illegal insn*/
+
+/* There's no particular reason that this needs to be handwritten
+ assembly, but since that's what this file contains, here's a
+ simple strlen implementation (written in C and compiled by gcc.)
+*/
+.global VG_(mips32_linux_REDIR_FOR_strlen)
+.type VG_(mips32_linux_REDIR_FOR_strlen), @function
+VG_(mips32_linux_REDIR_FOR_strlen):
+ li $v0, 0
+ //la $a0, string
+ j strlen_cond
+ strlen_loop:
+ addi $v0, $v0, 1
+ addi $a0, $a0, 1
+ strlen_cond:
+ lbu $t0, ($a0)
+ bne $t0, $zero, strlen_loop
+ jr $ra
+
+.size VG_(mips32_linux_REDIR_FOR_strlen), .-VG_(mips32_linux_REDIR_FOR_strlen)
+
+.global VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+
+# undef UD2_16
+# undef UD2_64
+# undef UD2_256
+# undef UD2_1024
+# undef UD2_PAGE
+
/*---------------- unknown ----------------*/
#else
# error Unknown platform
@@ -1032,6 +1090,7 @@
#endif
#endif
#endif
+#endif
#if defined(VGO_linux)
/* Let the linker know we don't need an executable stack */
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index d055101..fc6fa62 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -726,7 +726,7 @@
static Bool translations_allowable_from_seg ( NSegment const* seg )
{
-# if defined(VGA_x86) || defined(VGA_s390x)
+# if defined(VGA_x86) || defined(VGA_s390x) || defined(VGA_mips32)
Bool allowR = True;
# else
Bool allowR = False;
@@ -1188,6 +1188,12 @@
nraddr_szB == 8 ? mkU64(0) : mkU32(0)
)
);
+# if defined(VGP_mips32_linux)
+ // t9 needs to be set to point to the start of the redirected function.
+ VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
+ Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
+ addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
+# endif
# if defined(VG_PLAT_USES_PPCTOC)
{ VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
addStmtToIRSB(
@@ -1224,6 +1230,11 @@
: IRExpr_Const(IRConst_U32( (UInt)closure->nraddr ))
)
);
+# if defined(VGP_mips32_linux)
+ // t9 needs to be set to point to the start of the redirected function.
+ Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
+ addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
+# endif
# if defined(VGP_ppc64_linux)
addStmtToIRSB(
bb,
diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h
index 150d3be..39b5ae7 100644
--- a/coregrind/pub_core_aspacemgr.h
+++ b/coregrind/pub_core_aspacemgr.h
@@ -343,7 +343,8 @@
// stacks. The address space manager provides and suitably
// protects such stacks.
-#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \
+ || defined(VGP_mips32_linux)
# define VG_STACK_GUARD_SZB 65536 // 1 or 16 pages
# define VG_STACK_ACTIVE_SZB (4096 * 256) // 1Mb
#else
diff --git a/coregrind/pub_core_basics.h b/coregrind/pub_core_basics.h
index f0861d4..63db17f 100644
--- a/coregrind/pub_core_basics.h
+++ b/coregrind/pub_core_basics.h
@@ -60,6 +60,8 @@
# include "libvex_guest_arm.h"
#elif defined(VGA_s390x)
# include "libvex_guest_s390x.h"
+#elif defined(VGA_mips32)
+# include "libvex_guest_mips32.h"
#else
# error Unknown arch
#endif
@@ -83,8 +85,8 @@
typedef
struct {
- ULong r_pc; /* x86:EIP, amd64:RIP, ppc:CIA, arm:R15 */
- ULong r_sp; /* x86:ESP, amd64:RSP, ppc:R1, arm:R13 */
+ ULong r_pc; /* x86:EIP, amd64:RIP, ppc:CIA, arm:R15, mips:pc */
+ ULong r_sp; /* x86:ESP, amd64:RSP, ppc:R1, arm:R13, mips:sp */
union {
struct {
UInt r_ebp;
@@ -108,6 +110,11 @@
ULong r_fp;
ULong r_lr;
} S390X;
+ struct {
+ UInt r30; /* Stack frame pointer or subroutine variable */
+ UInt r31; /* Return address of the last subroutine call */
+ UInt r28;
+ } MIPS32;
} misc;
}
UnwindStartRegs;
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index fa1b129..8655260 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -93,6 +93,12 @@
extern
Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, Char* buf, Int nbuf );
+/* mips-linux only: find the offset of current address. This is needed for
+ stack unwinding for MIPS.
+*/
+extern
+Bool VG_(get_inst_offset_in_function)( Addr a, /*OUT*/PtrdiffT* offset );
+
/* Use DWARF2/3 CFA information to do one step of stack unwinding.
D3UnwindRegs holds the current register values, and is
@@ -114,6 +120,10 @@
typedef
struct { Addr ia; Addr sp; Addr fp; Addr lr;}
D3UnwindRegs;
+#elif defined(VGA_mips32)
+typedef
+ struct { Addr pc; Addr sp; Addr fp; Addr ra; }
+ D3UnwindRegs;
#else
# error "Unsupported arch"
#endif
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index b76f395..4b3ad6c 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -75,6 +75,17 @@
# define VG_ELF_MACHINE EM_S390
# define VG_ELF_CLASS ELFCLASS64
# undef VG_PLAT_USES_PPCTOC
+#elif defined(VGP_mips32_linux)
+# if defined (VG_LITTLEENDIAN)
+# define VG_ELF_DATA2XXX ELFDATA2LSB
+# elif defined (VG_BIGENDIAN)
+# define VG_ELF_DATA2XXX ELFDATA2MSB
+# else
+# error "Unknown endianness"
+# endif
+# define VG_ELF_MACHINE EM_MIPS
+# define VG_ELF_CLASS ELFCLASS32
+# undef VG_PLAT_USES_PPCTOC
#else
# error Unknown platform
#endif
@@ -104,6 +115,10 @@
# define VG_STACK_PTR guest_SP
# define VG_FRAME_PTR guest_FP
# define VG_FPC_REG guest_fpc
+#elif defined(VGA_mips32)
+# define VG_INSTR_PTR guest_PC
+# define VG_STACK_PTR guest_r29
+# define VG_FRAME_PTR guest_r30
#else
# error Unknown arch
#endif
diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h
index c192f19..508b9f3 100644
--- a/coregrind/pub_core_mallocfree.h
+++ b/coregrind/pub_core_mallocfree.h
@@ -80,6 +80,7 @@
defined(VGP_ppc32_linux) || \
defined(VGP_ppc64_linux) || \
defined(VGP_s390x_linux) || \
+ defined(VGP_mips32_linux) || \
defined(VGP_x86_darwin) || \
defined(VGP_amd64_darwin)
# define VG_MIN_MALLOC_SZB 16
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index 1b6d35f..2902001 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -79,6 +79,8 @@
extern SysRes VG_(mk_SysRes_amd64_darwin)( UChar scclass, Bool isErr,
ULong wHI, ULong wLO );
extern SysRes VG_(mk_SysRes_s390x_linux) ( Long val );
+extern SysRes VG_(mk_SysRes_mips32_linux)( UWord v0, UWord v1,
+ UWord a3 );
extern SysRes VG_(mk_SysRes_Error) ( UWord val );
extern SysRes VG_(mk_SysRes_Success) ( UWord val );
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index ccb41a1..2e80f87 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -87,6 +87,8 @@
typedef VexGuestARMState VexGuestArchState;
#elif defined(VGA_s390x)
typedef VexGuestS390XState VexGuestArchState;
+#elif defined(VGA_mips32)
+ typedef VexGuestMIPS32State VexGuestArchState;
#else
# error Unknown architecture
#endif
diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h
index 4e87792..765c7f6 100644
--- a/coregrind/pub_core_trampoline.h
+++ b/coregrind/pub_core_trampoline.h
@@ -127,6 +127,12 @@
extern Addr VG_(s390x_linux_SUBST_FOR_rt_sigreturn);
#endif
+#if defined(VGP_mips32_linux)
+extern Addr VG_(mips32_linux_SUBST_FOR_sigreturn);
+extern Addr VG_(mips32_linux_SUBST_FOR_rt_sigreturn);
+extern UInt VG_(mips32_linux_REDIR_FOR_strlen)( void* );
+#endif
+
#endif // __PUB_CORE_TRAMPOLINE_H
/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_transtab_asm.h b/coregrind/pub_core_transtab_asm.h
index 00adced..12b02de 100644
--- a/coregrind/pub_core_transtab_asm.h
+++ b/coregrind/pub_core_transtab_asm.h
@@ -62,7 +62,7 @@
#elif defined(VGA_s390x) || defined(VGA_arm)
# define VG_TT_FAST_HASH(_addr) ((((UWord)(_addr)) >> 1) & VG_TT_FAST_MASK)
-#elif defined(VGA_ppc32) || defined(VGA_ppc64)
+#elif defined(VGA_ppc32) || defined(VGA_ppc64) || defined(VGA_mips32)
# define VG_TT_FAST_HASH(_addr) ((((UWord)(_addr)) >> 2) & VG_TT_FAST_MASK)
#else
diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c
index 46b2cfd..c0f1d81 100644
--- a/coregrind/vgdb.c
+++ b/coregrind/vgdb.c
@@ -80,7 +80,8 @@
can be "waken up". PTRACEINVOKER implies some architecture
specific code and/or some OS specific code. */
#if defined(VGA_arm) || defined(VGA_x86) || defined(VGA_amd64) \
- || defined(VGA_ppc32) || defined(VGA_ppc64) || defined(VGA_s390x)
+ || defined(VGA_ppc32) || defined(VGA_ppc64) || defined(VGA_s390x) \
+ || defined(VGP_mips32_linux)
#define PTRACEINVOKER
#else
I_die_here : (PTRACEINVOKER) architecture missing in vgdb.c
@@ -923,6 +924,8 @@
sp = user_mod.regs.gpr[1];
#elif defined(VGA_s390x)
sp = user_mod.regs.gprs[15];
+#elif defined(VGA_mips32)
+ sp = user_mod.regs[29];
#else
I_die_here : (sp) architecture missing in vgdb.c
#endif
@@ -995,6 +998,12 @@
#elif defined(VGA_s390x)
XERROR(0, "(fn32) s390x has no 32bits implementation");
+#elif defined(VGA_mips32)
+ /* put check arg in register 0 */
+ user_mod.regs[4] = check;
+ /* put NULL return address in ra */
+ user_mod.regs[31] = bad_return;
+ user_mod.regs[25] = shared32->invoke_gdbserver;
#else
I_die_here : architecture missing in vgdb.c
#endif
@@ -1074,6 +1083,8 @@
user_mod.regs.gprs[15] = sp;
/* set program counter */
user_mod.regs.psw.addr = shared64->invoke_gdbserver;
+#elif defined(VGA_mips32)
+ assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
#else
I_die_here: architecture missing in vgdb.c
#endif