#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h" // VG_(getenv)
#include "pub_core_seqmatch.h"
#include "pub_core_options.h"
#include "pub_core_redir.h" // VG_(redir_notify_{new,delete}_SegInfo)
SizeT total_size,
PtrdiffT unknown_purpose__reloc )
{
- Int r, sz_exename;
+ Int i, r, sz_exename;
ULong obj_mtime, pdb_mtime;
Char exename[VKI_PATH_MAX];
Char* pdbname = NULL;
VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: objname: %s\n", exename);
}
- /* Try to find a matching PDB file from which to read debuginfo.
- Windows PE files have symbol tables and line number information,
- but MSVC doesn't seem to use them. */
- /* Why +5 ? Because in the worst case, we could find a dot as the
- last character of pdbname, and we'd then put "pdb" right after
- it, hence extending it a bit. */
- pdbname = ML_(dinfo_zalloc)("di.debuginfo.lpd1", sz_exename+5);
- VG_(strcpy)(pdbname, exename);
- vg_assert(pdbname[sz_exename+5-1] == 0);
- dot = VG_(strrchr)(pdbname, '.');
- if (!dot)
- goto out; /* there's no dot in the exe's name ?! */
- if (dot[1] == 0)
- goto out; /* hmm, path ends in "." */
-
- if ('A' <= dot[1] && dot[1] <= 'Z')
- VG_(strcpy)(dot, ".PDB");
- else
- VG_(strcpy)(dot, ".pdb");
+ /* Try to get the PDB file name from the executable. */
+ pdbname = ML_(find_name_of_pdb_file)(exename);
+ if (pdbname) {
+ vg_assert(VG_(strlen)(pdbname) >= 5); /* 5 = strlen("X.pdb") */
+ /* So we successfully extracted a name from the PE file. But it's
+ likely to be of the form
+ e:\foo\bar\xyzzy\wibble.pdb
+ and we need to change it into something we can actually open
+ in Wine-world, which basically means turning it into
+ $HOME/.wine/drive_e/foo/bar/xyzzy/wibble.pdb
+ We also take into account $WINEPREFIX, if it is set.
+ For the moment, if the name isn't fully qualified, just forget it
+ (we'd have to root around to find where the pdb actually is)
+ */
+ /* Change all the backslashes to forward slashes */
+ for (i = 0; pdbname[i]; i++) {
+ if (pdbname[i] == '\\')
+ pdbname[i] = '/';
+ }
+ Bool is_quald
+ = ('a' <= VG_(tolower)(pdbname[0]) && VG_(tolower)(pdbname[0]) <= 'z')
+ && pdbname[1] == ':'
+ && pdbname[2] == '/';
+ HChar* home = VG_(getenv)("HOME");
+ HChar* wpfx = VG_(getenv)("WINEPREFIX");
+ if (is_quald && wpfx) {
+ /* Change e:/foo/bar/xyzzy/wibble.pdb
+ to $WINEPREFIX/drive_e/foo/bar/xyzzy/wibble.pdb
+ */
+ Int mashedSzB = VG_(strlen)(pdbname) + VG_(strlen)(wpfx) + 50/*misc*/;
+ HChar* mashed = ML_(dinfo_zalloc)("di.debuginfo.dnpdi.1", mashedSzB);
+ VG_(sprintf)(mashed, "%s/drive_%c%s",
+ wpfx, pdbname[0], &pdbname[2]);
+ vg_assert(mashed[mashedSzB-1] == 0);
+ ML_(dinfo_free)(pdbname);
+ pdbname = mashed;
+ }
+ else if (is_quald && home && !wpfx) {
+ /* Change e:/foo/bar/xyzzy/wibble.pdb
+ to $HOME/.wine/drive_e/foo/bar/xyzzy/wibble.pdb
+ */
+ Int mashedSzB = VG_(strlen)(pdbname) + VG_(strlen)(home) + 50/*misc*/;
+ HChar* mashed = ML_(dinfo_zalloc)("di.debuginfo.dnpdi.2", mashedSzB);
+ VG_(sprintf)(mashed, "%s/.wine/drive_%c%s",
+ home, pdbname[0], &pdbname[2]);
+ vg_assert(mashed[mashedSzB-1] == 0);
+ ML_(dinfo_free)(pdbname);
+ pdbname = mashed;
+ } else {
+ /* It's not a fully qualified path, or neither $HOME nor $WINE
+ are set (strange). Give up. */
+ ML_(dinfo_free)(pdbname);
+ pdbname = NULL;
+ }
+ }
- vg_assert(pdbname[sz_exename+5-1] == 0);
+ /* Try s/exe/pdb/ if we don't have a valid pdbname. */
+ if (!pdbname) {
+ /* Try to find a matching PDB file from which to read debuginfo.
+ Windows PE files have symbol tables and line number information,
+ but MSVC doesn't seem to use them. */
+ /* Why +5 ? Because in the worst case, we could find a dot as the
+ last character of pdbname, and we'd then put "pdb" right after
+ it, hence extending it a bit. */
+ pdbname = ML_(dinfo_zalloc)("di.debuginfo.lpd1", sz_exename+5);
+ VG_(strcpy)(pdbname, exename);
+ vg_assert(pdbname[sz_exename+5-1] == 0);
+ dot = VG_(strrchr)(pdbname, '.');
+ if (!dot)
+ goto out; /* there's no dot in the exe's name ?! */
+ if (dot[1] == 0)
+ goto out; /* hmm, path ends in "." */
+
+ if ('A' <= dot[1] && dot[1] <= 'Z')
+ VG_(strcpy)(dot, ".PDB");
+ else
+ VG_(strcpy)(dot, ".pdb");
+
+ vg_assert(pdbname[sz_exename+5-1] == 0);
+ }
/* See if we can find it, and check it's in-dateness. */
sres = VG_(stat)(pdbname, &stat_buf);
#include "pub_core_vki.h" // VKI_PAGE_SIZE
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h" // VG_(open), read, lseek, close
#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h" // VG_(getpid), system
#include "pub_core_options.h" // VG_(clo_verbosity)
#include "pub_core_xarray.h" // keeps priv_storage.h happy
#include "pub_core_redir.h"
/*--- ---*/
/*------------------------------------------------------------*/
+/* Read line, symbol and unwind information from a PDB file.
+*/
Bool ML_(read_pdb_debug_info)(
DebugInfo* di,
Addr obj_avma,
return True;
}
+
+/* Examine a PE file to see if it states the path of an associated PDB
+ file; if so return that. Caller must deallocate with
+ ML_(dinfo_free).
+*/
+
+HChar* ML_(find_name_of_pdb_file)( HChar* pename )
+{
+ /* This is a giant kludge, of the kind "you did WTF?!?", but it
+ works. */
+ Bool do_cleanup = False;
+ HChar tmpname[100], tmpnameroot[50];
+ Int fd, r;
+ HChar* res = NULL;
+
+ if (!pename)
+ goto out;
+
+ fd = -1;
+ VG_(memset)(tmpnameroot, 0, sizeof(tmpnameroot));
+ VG_(sprintf)(tmpnameroot, "petmp%d", VG_(getpid)());
+ VG_(memset)(tmpname, 0, sizeof(tmpname));
+ fd = VG_(mkstemp)( tmpnameroot, tmpname );
+ if (fd == -1) {
+ VG_(message)(Vg_UserMsg,
+ "Find PDB file: Can't create /tmp file %s\n", tmpname);
+ goto out;
+ }
+ do_cleanup = True;
+
+ /* Make up the command to run, essentially:
+ sh -c "strings (pename) | egrep '\.pdb|\.PDB' > (tmpname)"
+ */
+ HChar* sh = "/bin/sh";
+ HChar* strings = "/usr/bin/strings";
+ HChar* egrep = "/usr/bin/egrep";
+
+ /* (sh) -c "(strings) (pename) | (egrep) 'pdb' > (tmpname) */
+ Int cmdlen = VG_(strlen)(strings) + VG_(strlen)(pename)
+ + VG_(strlen)(egrep) + VG_(strlen)(tmpname)
+ + 100/*misc*/;
+ HChar* cmd = ML_(dinfo_zalloc)("di.readpe.fnopf.cmd", cmdlen);
+ vg_assert(cmd);
+ VG_(sprintf)(cmd, "%s -c \"%s %s | %s '\\.pdb|\\.PDB' >> %s\"",
+ sh, strings, pename, egrep, tmpname);
+ vg_assert(cmd[cmdlen-1] == 0);
+ if (0) VG_(printf)("QQQQQQQQ: %s\n", cmd);
+
+ r = VG_(system)( cmd );
+ if (r) {
+ VG_(message)(Vg_DebugMsg,
+ "Find PDB file: Command failed:\n %s\n", cmd);
+ goto out;
+ }
+
+ /* Find out how big the file is, and get it aboard. */
+ struct vg_stat stat_buf;
+ VG_(memset)(&stat_buf, 0, sizeof(stat_buf));
+
+ SysRes sr = VG_(stat)(tmpname, &stat_buf);
+ if (sr_isError(sr)) {
+ VG_(umsg)("Find PDB file: can't stat %s\n", tmpname);
+ goto out;
+ }
+
+ Int szB = (Int)stat_buf.size;
+ if (szB == 0) {
+ VG_(umsg)("Find PDB file: %s is empty\n", tmpname);
+ goto out;
+ }
+ /* 6 == strlen("X.pdb\n") */
+ if (szB < 6 || szB > 1024/*let's say*/) {
+ VG_(umsg)("Find PDB file: %s has implausible size %d\n",
+ tmpname, szB);
+ goto out;
+ }
+
+ HChar* pdbname = ML_(dinfo_zalloc)("di.readpe.fnopf.pdbname", szB + 1);
+ vg_assert(pdbname);
+ pdbname[szB] = 0;
+
+ Int nread = VG_(read)(fd, pdbname, szB);
+ if (nread != szB) {
+ VG_(umsg)("Find PDB file: read of %s failed\n", tmpname);
+ goto out;
+ }
+ vg_assert(pdbname[szB] == 0);
+
+ /* Check we've got something remotely sane -- must have one dot and
+ one \n in it, and the \n must be at the end */
+ Bool saw_dot = False;
+ Int saw_n_crs = 0;
+ Int i;
+ for (i = 0; pdbname[i]; i++) {
+ if (pdbname[i] == '.') saw_dot = True;
+ if (pdbname[i] == '\n') saw_n_crs++;
+ }
+ if (!saw_dot || saw_n_crs != 1 || pdbname[szB-1] != '\n') {
+ VG_(umsg)("Find PDB file: can't make sense of: %s\n", pdbname);
+ goto out;
+ }
+ /* Change the \n to a terminating zero, so we have a "normal" string */
+ pdbname[szB-1] = 0;
+
+ if (0) VG_(printf)("QQQQQQQQ: got %s\n", pdbname);
+
+ res = pdbname;
+ goto out;
+
+ out:
+ if (do_cleanup) {
+ VG_(close)(fd);
+ VG_(unlink)( tmpname );
+ }
+ return res;
+}
+
#endif // defined(VGO_linux) || defined(VGO_darwin)
/*--------------------------------------------------------------------*/