#include "pub_core_basics.h"
#include "pub_core_vki.h"
+#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
#include "pub_core_threadstate.h"
#include "pub_core_debuginfo.h" /* self */
#include "pub_core_demangle.h"
DebugInfo* di;
ULong di_handle;
SysRes fd;
- Int nread;
+ Int nread, oflags;
HChar buf1k[1024];
Bool debug = False;
SysRes statres;
2009 Aug 16: apply similar kludge to ppc32-linux.
See http://bugs.kde.org/show_bug.cgi?id=190820
+
+ There are two modes on s390x: with and without the noexec kernel
+ parameter. Together with some older kernels, this leads to several
+ variants:
+ executable: r and x
+ data: r and w and x
+ or
+ executable: r and x
+ data: r and w
*/
is_rx_map = False;
is_rw_map = False;
# elif defined(VGA_amd64) || defined(VGA_ppc64) || defined(VGA_arm)
is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
is_rw_map = seg->hasR && seg->hasW && !seg->hasX;
+# elif defined(VGP_s390x_linux)
+ is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
+ is_rw_map = seg->hasR && seg->hasW;
# else
# error "Unknown platform"
# endif
/* Peer at the first few bytes of the file, to see if it is an ELF */
/* object file. Ignore the file if we do not have read permission. */
VG_(memset)(buf1k, 0, sizeof(buf1k));
- fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
+ oflags = VKI_O_RDONLY;
+# if defined(VKI_O_LARGEFILE)
+ oflags |= VKI_O_LARGEFILE;
+# endif
+ fd = VG_(open)( filename, oflags, 0 );
if (sr_isError(fd)) {
if (sr_Err(fd) != VKI_EACCES) {
DebugInfo fake_di;
if (VG_(clo_verbosity) > 0) {
VG_(message)(Vg_UserMsg, "\n");
VG_(message)(Vg_UserMsg,
- "LOAD_PDB_DEBUGINFO(fd=%d, avma=%#lx, total_size=%lu, "
- "uu_reloc=%#lx)\n",
+ "LOAD_PDB_DEBUGINFO: clreq: fd=%d, avma=%#lx, total_size=%lu, "
+ "uu_reloc=%#lx\n",
fd_obj, avma_obj, total_size, unknown_purpose__reloc
);
}
goto out;
}
- /* Looks promising; go on to try and read stuff from it. */
+ /* Looks promising; go on to try and read stuff from it. But don't
+ mmap the file. Instead mmap free space and read the file into
+ it. This is because files on CIFS filesystems that are mounted
+ '-o directio' can't be mmap'd, and that mount option is needed
+ to make CIFS work reliably. (See
+ http://www.nabble.com/Corrupted-data-on-write-to-
+ Windows-2003-Server-t2782623.html)
+ This is slower, but at least it works reliably. */
fd_pdbimage = sr_Res(sres);
n_pdbimage = stat_buf.size;
- sres = VG_(am_mmap_file_float_valgrind)( n_pdbimage, VKI_PROT_READ,
- fd_pdbimage, 0 );
+ if (n_pdbimage == 0 || n_pdbimage > 0x7FFFFFFF) {
+ // 0x7FFFFFFF: why? Because the VG_(read) just below only
+ // can deal with a signed int as the size of data to read,
+ // so we can't reliably check for read failure for files
+ // greater than that size. Hence just skip them; we're
+ // unlikely to encounter a PDB that large anyway.
+ VG_(close)(fd_pdbimage);
+ goto out;
+ }
+ sres = VG_(am_mmap_anon_float_valgrind)( n_pdbimage );
if (sr_isError(sres)) {
VG_(close)(fd_pdbimage);
goto out;
}
+ void* pdbimage = (void*)sr_Res(sres);
+ r = VG_(read)( fd_pdbimage, pdbimage, (Int)n_pdbimage );
+ if (r < 0 || r != (Int)n_pdbimage) {
+ VG_(am_munmap_valgrind)( (Addr)pdbimage, n_pdbimage );
+ VG_(close)(fd_pdbimage);
+ goto out;
+ }
+
if (VG_(clo_verbosity) > 0)
VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: pdbname: %s\n", pdbname);
/* dump old info for this range, if any */
discard_syms_in_range( avma_obj, total_size );
- { void* pdbimage = (void*)sr_Res(sres);
- DebugInfo* di = find_or_create_DebugInfo_for(exename, NULL/*membername*/ );
+ { DebugInfo* di = find_or_create_DebugInfo_for(exename, NULL/*membername*/ );
/* this di must be new, since we just nuked any old stuff in the range */
vg_assert(di && !di->have_rx_map && !di->have_rw_map);
vg_assert(di->have_dinfo); // fails if PDB read failed
VG_(am_munmap_valgrind)( (Addr)pdbimage, n_pdbimage );
VG_(close)(fd_pdbimage);
+
+ if (VG_(clo_verbosity) > 0) {
+ VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: done: "
+ "%lu syms, %lu src locs, %lu fpo recs\n",
+ di->symtab_used, di->loctab_used, di->fpo_size);
+ }
}
out:
UInt lineno;
UChar ibuf[50];
Int n = 0;
+
static UChar buf_fn[BUF_LEN];
static UChar buf_obj[BUF_LEN];
static UChar buf_srcloc[BUF_LEN];
static UChar buf_dirname[BUF_LEN];
+ buf_fn[0] = buf_obj[0] = buf_srcloc[0] = buf_dirname[0] = 0;
+
Bool know_dirinfo = False;
Bool know_fnname = VG_(clo_sym_offsets)
? VG_(get_fnname_w_offset) (eip, buf_fn, BUF_LEN)
&lineno
);
+ buf_fn [ sizeof(buf_fn)-1 ] = 0;
+ buf_obj [ sizeof(buf_obj)-1 ] = 0;
+ buf_srcloc [ sizeof(buf_srcloc)-1 ] = 0;
+ buf_dirname[ sizeof(buf_dirname)-1 ] = 0;
+
if (VG_(clo_xml)) {
Bool human_readable = True;
}
if (know_srcloc) {
APPEND(" (");
- APPEND(buf_dirname);
- APPEND("/");
+ // Get the directory name, if any, possibly pruned, into dirname.
+ UChar* dirname = NULL;
+ if (VG_(clo_n_fullpath_after) > 0) {
+ Int i;
+ dirname = buf_dirname;
+ // Remove leading prefixes from the dirname.
+ // If user supplied --fullpath-after=foo, this will remove
+ // a leading string which matches '.*foo' (not greedy).
+ for (i = 0; i < VG_(clo_n_fullpath_after); i++) {
+ UChar* prefix = VG_(clo_fullpath_after)[i];
+ UChar* str = VG_(strstr)(dirname, prefix);
+ if (str) {
+ dirname = str + VG_(strlen)(prefix);
+ break;
+ }
+ }
+ /* remove leading "./" */
+ if (dirname[0] == '.' && dirname[1] == '/')
+ dirname += 2;
+ }
+ // do we have any interesting directory name to show? If so
+ // add it in.
+ if (dirname && dirname[0] != 0) {
+ APPEND(dirname);
+ APPEND("/");
+ }
APPEND(buf_srcloc);
APPEND(":");
VG_(sprintf)(ibuf,"%d",lineno);
case Creg_IA_SP: return eec->uregs->xsp;
case Creg_IA_BP: return eec->uregs->xbp;
# elif defined(VGA_arm)
- case Creg_ARM_R13: return eec->uregs->r13;
- case Creg_ARM_R12: return eec->uregs->r12;
case Creg_ARM_R15: return eec->uregs->r15;
case Creg_ARM_R14: return eec->uregs->r14;
+ case Creg_ARM_R13: return eec->uregs->r13;
+ case Creg_ARM_R12: return eec->uregs->r12;
+# elif defined(VGA_s390x)
+ case Creg_IA_IP: return eec->uregs->ia;
+ 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_ppc32) || defined(VGA_ppc64)
# else
# error "Unsupported arch"
case CFIC_ARM_R11REL:
cfa = cfsi->cfa_off + uregs->r11;
break;
+ case CFIC_ARM_R7REL:
+ cfa = cfsi->cfa_off + uregs->r7;
+ break;
+# elif defined(VGA_s390x)
+ case CFIC_IA_SPREL:
+ cfa = cfsi->cfa_off + uregs->sp;
+ break;
+ case CFIR_MEMCFAREL:
+ {
+ Addr a = uregs->sp + cfsi->cfa_off;
+ if (a < min_accessible || a > max_accessible-sizeof(Addr))
+ break;
+ cfa = *(Addr*)a;
+ 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"
{
CFSICacheEnt* ce;
DebugInfo* di;
- DiCfSI* cfsi;
+ DiCfSI* cfsi __attribute__((unused));
ce = cfsi_cache__find(ip);
return compute_cfa(&uregs,
min_accessible, max_accessible, di, cfsi);
}
+#elif defined(VGA_s390x)
+ { D3UnwindRegs uregs;
+ uregs.ia = ip;
+ uregs.sp = sp;
+ uregs.fp = fp;
+ return compute_cfa(&uregs,
+ min_accessible, max_accessible, di, cfsi);
+ }
+
# else
return 0; /* indicates failure */
# endif
For x86 and amd64, the unwound registers are: {E,R}IP,
{E,R}SP, {E,R}BP.
- For arm, the unwound registers are: R11 R12 R13 R14 R15.
+ For arm, the unwound registers are: R7 R11 R12 R13 R14 R15.
*/
Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere,
Addr min_accessible,
Addr max_accessible )
{
- Bool ok;
DebugInfo* di;
DiCfSI* cfsi = NULL;
Addr cfa, ipHere = 0;
CFSICacheEnt* ce;
- CfiExprEvalContext eec;
+ CfiExprEvalContext eec __attribute__((unused));
D3UnwindRegs uregsPrev;
# if defined(VGA_x86) || defined(VGA_amd64)
ipHere = uregsHere->xip;
# elif defined(VGA_arm)
ipHere = uregsHere->r15;
+# elif defined(VGA_s390x)
+ ipHere = uregsHere->ia;
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
# else
# error "Unknown arch"
eec.uregs = uregsHere; \
eec.min_accessible = min_accessible; \
eec.max_accessible = max_accessible; \
- ok = True; \
+ Bool ok = True; \
_prev = evalCfiExpr(di->cfsi_exprs, _off, &eec, &ok ); \
if (!ok) return False; \
break; \
COMPUTE(uregsPrev.r13, uregsHere->r13, cfsi->r13_how, cfsi->r13_off);
COMPUTE(uregsPrev.r12, uregsHere->r12, cfsi->r12_how, cfsi->r12_off);
COMPUTE(uregsPrev.r11, uregsHere->r11, cfsi->r11_how, cfsi->r11_off);
+ COMPUTE(uregsPrev.r7, uregsHere->r7, cfsi->r7_how, cfsi->r7_off);
+# elif defined(VGA_s390x)
+ 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_ppc32) || defined(VGA_ppc64)
# else
# error "Unknown arch"
UChar* basetag = "auxwhat"; /* a constant */
UChar tagL[32], tagR[32], xagL[32], xagR[32];
- vg_assert(frameNo >= -1);
+ if (frameNo < -1) {
+ vg_assert(0); /* Not allowed */
+ }
+ else if (frameNo == -1) {
+ vg_assert(tid == VG_INVALID_THREADID);
+ }
+ else /* (frameNo >= 0) */ {
+ vg_assert(tid != VG_INVALID_THREADID);
+ }
+
vg_assert(dn1 && dn2);
vg_assert(described);
vg_assert(var && var->name);
var->typeR, offset );
format_message( dname1, dname2,
data_addr, var, offset, residual_offset,
- described, -1/*frameNo*/, tid );
+ described, -1/*frameNo*/,
+ VG_INVALID_THREADID );
VG_(deleteXA)( described );
zterm_XA( dname1 );
zterm_XA( dname2 );
/* This is a derivation of consider_vars_in_frame() above. */
Word i;
DebugInfo* di;
- RegSummary regs;
Bool debug = False;
XArray* res = VG_(newXA)( ML_(dinfo_zalloc), "di.debuginfo.dgsbai.1",
variables on each such address range found are in scope right
now. Don't descend to level zero as that is the global
scope. */
- regs.ip = ip;
- regs.sp = 0;
- regs.fp = 0;
/* "for each scope, working outwards ..." */
for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {