http://code.google.com/p/valgrind-variant/source/detail?r=118
Added:
/trunk/valgrind/coregrind/fixup_macho_loadcmds.c
/trunk/valgrind/drd/drd_darwin_intercepts.c
Modified:
/trunk/valgrind/coregrind/m_debuginfo/readmacho.c
=======================================
--- /dev/null
+++ /trunk/valgrind/coregrind/fixup_macho_loadcmds.c Fri Oct 28 06:00:35
2011
@@ -0,0 +1,609 @@
+
+/* Derived from Valgrind sources, coregrind/m_debuginfo/readmacho.c.
+ GPL 2+ therefore.
+
+ Can be compiled as either a 32- or 64-bit program (doesn't matter).
+*/
+
+/* What does this program do? In short it postprocesses tool
+ executables on MacOSX, after linking using /usr/bin/ld. This is so
+ as to work around a bug in the linker on Xcode 4.0.0 and Xcode
+ 4.0.1. Xcode versions prior to 4.0.0 are unaffected.
+
+ The tracking bug is https://bugs.kde.org/show_bug.cgi?id=267997
+
+ The bug causes 64-bit tool executables to segfault at startup,
+ because:
+
+ Comparing the MachO load commands vs a (working) tool executable
+ that was created by Xcode 3.2.x, it appears that the new linker has
+ partially ignored the build system's request to place the tool
+ executable's stack at a non standard location. The build system
+ tells the linker "-stack_addr 0x134000000 -stack_size 0x800000".
+
+ With the Xcode 3.2 linker those flags produce two results:
+
+ (1) A load command to allocate the stack at the said location:
+ Load command 3
+ cmd LC_SEGMENT_64
+ cmdsize 72
+ segname __UNIXSTACK
+ vmaddr 0x0000000133800000
+ vmsize 0x0000000000800000
+ fileoff 2285568
+ filesize 0
+ maxprot 0x00000007
+ initprot 0x00000003
+ nsects 0
+ flags 0x0
+
+ (2) A request (in LC_UNIXTHREAD) to set %rsp to the correct value
+ at process startup, 0x134000000.
+
+ With Xcode 4.0.1, (1) is missing but (2) is still present. The
+ tool executable therefore starts up with %rsp pointing to unmapped
+ memory and faults almost instantly.
+
+ The workaround implemented by this program is documented in comment
+ 8 of bug 267997, viz:
+
+ One really sick workaround is to observe that the executables
+ contain a redundant MachO load command:
+
+ Load command 2
+ cmd LC_SEGMENT_64
+ cmdsize 72
+ segname __LINKEDIT
+ vmaddr 0x0000000138dea000
+ vmsize 0x00000000000ad000
+ fileoff 2658304
+ filesize 705632
+ maxprot 0x00000007
+ initprot 0x00000001
+ nsects 0
+ flags 0x0
+
+ The described section presumably contains information intended for
+ the dynamic linker, but is irrelevant because this is a statically
+ linked executable. Hence it might be possible to postprocess the
+ executables after linking, to overwrite this entry with the
+ information that would have been in the missing __UNIXSTACK entry.
+ I tried this by hand (with a binary editor) earlier and got
+ something that worked.
+*/
+
+#define DEBUGPRINTING 0
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+
+#if defined(__APPLE__) && defined(__i386__)
+# define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+# define PLAT_amd64_darwin 1
+#else
+# error "Can't be compiled on this platform"
+#endif
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/fat.h>
+#include <mach/i386/thread_status.h>
+
+
+typedef unsigned char UChar;
+typedef signed char Char;
+typedef char HChar; /* signfulness depends on host */
+
+typedef unsigned int UInt;
+typedef signed int Int;
+
+typedef unsigned char Bool;
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+typedef unsigned long UWord;
+
+typedef UWord SizeT;
+typedef UWord Addr;
+
+typedef unsigned long long int ULong;
+typedef signed long long int Long;
+
+
+
+__attribute__((noreturn))
+void fail ( HChar* msg )
+{
+ fprintf(stderr, "fixup_macho_loadcmds: fail: %s\n", msg);
+ exit(1);
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Mach-O file mapping/unmapping helpers ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+typedef
+ struct {
+ /* These two describe the entire mapped-in ("primary") image,
+ fat headers, kitchen sink, whatnot: the entire file. The
+ image is mapped into img[0 .. img_szB-1]. */
+ UChar* img;
+ SizeT img_szB;
+ /* These two describe the Mach-O object of interest, which is
+ presumably somewhere inside the primary image.
+ map_image_aboard() below, which generates this info, will
+ carefully check that the macho_ fields denote a section of
+ memory that falls entirely inside img[0 .. img_szB-1]. */
+ UChar* macho_img;
+ SizeT macho_img_szB;
+ }
+ ImageInfo;
+
+
+Bool is_macho_object_file( const void* buf, SizeT szB )
+{
+ /* (JRS: the Mach-O headers might not be in this mapped data,
+ because we only mapped a page for this initial check,
+ or at least not very much, and what's at the start of the file
+ is in general a so-called fat header. The Mach-O object we're
+ interested in could be arbitrarily far along the image, and so
+ we can't assume its header will fall within this page.) */
+
+ /* But we can say that either it's a fat object, in which case it
+ begins with a fat header, or it's unadorned Mach-O, in which
+ case it starts with a normal header. At least do what checks we
+ can to establish whether or not we're looking at something
+ sane. */
+
+ const struct fat_header* fh_be = buf;
+ const struct mach_header_64* mh = buf;
+
+ assert(buf);
+ if (szB < sizeof(struct fat_header))
+ return False;
+ if (ntohl(fh_be->magic) == FAT_MAGIC)
+ return True;
+
+ if (szB < sizeof(struct mach_header_64))
+ return False;
+ if (mh->magic == MH_MAGIC_64)
+ return True;
+
+ return False;
+}
+
+
+/* Unmap an image mapped in by map_image_aboard. */
+static void unmap_image ( /*MOD*/ImageInfo* ii )
+{
+ Int r;
+ assert(ii->img);
+ assert(ii->img_szB > 0);
+ r = munmap( ii->img, ii->img_szB );
+ /* Do we care if this fails? I suppose so; it would indicate
+ some fairly serious snafu with the mapping of the file. */
+ assert( !r );
+ memset(ii, 0, sizeof(*ii));
+}
+
+
+/* Map a given fat or thin object aboard, find the thin part if
+ necessary, do some checks, and write details of both the fat and
+ thin parts into *ii. Returns 32 (and leaves the file unmapped) if
+ the thin part is a 32 bit file. Returns 64 if it's a 64 bit file.
+ Does not return on failure. Guarantees to return pointers to a
+ valid(ish) Mach-O image if it succeeds. */
+static Int map_image_aboard ( /*OUT*/ImageInfo* ii, HChar* filename )
+{
+ memset(ii, 0, sizeof(*ii));
+
+ /* First off, try to map the thing in. */
+ { SizeT size;
+ Int r, fd;
+ struct stat stat_buf;
+
+ r = stat(filename, &stat_buf);
+ if (r)
+ fail("Can't stat image (to determine its size)?!");
+ size = stat_buf.st_size;
+
+ fd = open(filename, O_RDWR, 0);
+ if (fd == -1)
+ fail("Can't open image for possible modification!");
+ if (DEBUGPRINTING)
+ printf("size %lu fd %d\n", size, fd);
+ void* v = mmap ( NULL, size, PROT_READ|PROT_WRITE,
+ MAP_FILE|MAP_SHARED, fd, 0 );
+ if (v == MAP_FAILED) {
+ perror("mmap failed");
+ fail("Can't mmap image for possible modification!");
+ }
+
+ close(fd);
+
+ ii->img = (UChar*)v;
+ ii->img_szB = size;
+ }
+
+ /* Now it's mapped in and we have .img and .img_szB set. Look for
+ the embedded Mach-O object. If not findable, unmap and fail. */
+ { struct fat_header* fh_be;
+ struct fat_header fh;
+ struct mach_header_64* mh;
+
+ // Assume initially that we have a thin image, and update
+ // these if it turns out to be fat.
+ ii->macho_img = ii->img;
+ ii->macho_img_szB = ii->img_szB;
+
+ // Check for fat header.
+ if (ii->img_szB < sizeof(struct fat_header))
+ fail("Invalid Mach-O file (0 too small).");
+
+ // Fat header is always BIG-ENDIAN
+ fh_be = (struct fat_header *)ii->img;
+ fh.magic = ntohl(fh_be->magic);
+ fh.nfat_arch = ntohl(fh_be->nfat_arch);
+ if (fh.magic == FAT_MAGIC) {
+ // Look for a good architecture.
+ struct fat_arch *arch_be;
+ struct fat_arch arch;
+ Int f;
+ if (ii->img_szB < sizeof(struct fat_header)
+ + fh.nfat_arch * sizeof(struct fat_arch))
+ fail("Invalid Mach-O file (1 too small).");
+
+ for (f = 0, arch_be = (struct fat_arch *)(fh_be+1);
+ f < fh.nfat_arch;
+ f++, arch_be++) {
+ Int cputype;
+# if defined(PLAT_x86_darwin)
+ cputype = CPU_TYPE_X86;
+# elif defined(PLAT_amd64_darwin)
+ cputype = CPU_TYPE_X86_64;
+# else
+# error "unknown architecture"
+# endif
+ arch.cputype = ntohl(arch_be->cputype);
+ arch.cpusubtype = ntohl(arch_be->cpusubtype);
+ arch.offset = ntohl(arch_be->offset);
+ arch.size = ntohl(arch_be->size);
+ if (arch.cputype == cputype) {
+ if (ii->img_szB < arch.offset + arch.size)
+ fail("Invalid Mach-O file (2 too small).");
+ ii->macho_img = ii->img + arch.offset;
+ ii->macho_img_szB = arch.size;
+ break;
+ }
+ }
+ if (f == fh.nfat_arch)
+ fail("No acceptable architecture found in fat file.");
+ }
+
+ /* Sanity check what we found. */
+
+ /* assured by logic above */
+ assert(ii->img_szB >= sizeof(struct fat_header));
+
+ if (ii->macho_img_szB < sizeof(struct mach_header_64))
+ fail("Invalid Mach-O file (3 too small).");
+
+ if (ii->macho_img_szB > ii->img_szB)
+ fail("Invalid Mach-O file (thin bigger than fat).");
+
+ if (ii->macho_img >= ii->img
+ && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) {
+ /* thin entirely within fat, as expected */
+ } else {
+ fail("Invalid Mach-O file (thin not inside fat).");
+ }
+
+ mh = (struct mach_header_64 *)ii->macho_img;
+ if (mh->magic == MH_MAGIC) {
+ assert(ii->img);
+ assert(ii->macho_img);
+ assert(ii->img_szB > 0);
+ assert(ii->macho_img_szB > 0);
+ assert(ii->macho_img >= ii->img);
+ assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB);
+ return 32;
+ }
+ if (mh->magic != MH_MAGIC_64)
+ fail("Invalid Mach-O file (bad magic).");
+
+ if (ii->macho_img_szB < sizeof(struct mach_header_64) +
mh->sizeofcmds)
+ fail("Invalid Mach-O file (4 too small).");
+ }
+
+ assert(ii->img);
+ assert(ii->macho_img);
+ assert(ii->img_szB > 0);
+ assert(ii->macho_img_szB > 0);
+ assert(ii->macho_img >= ii->img);
+ assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB);
+ return 64;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Mach-O top-level processing ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+void modify_macho_loadcmds ( HChar* filename,
+ ULong expected_stack_start,
+ ULong expected_stack_size )
+{
+ ImageInfo ii;
+ memset(&ii, 0, sizeof(ii));
+
+ Int size = map_image_aboard( &ii, filename );
+ if (size == 32) {
+ fprintf(stderr, "fixup_macho_loadcmds: Is 32-bit MachO file;"
+ " no modifications needed.\n");
+ goto out;
+ }
+
+ assert(size == 64);
+
+ assert(ii.macho_img != NULL && ii.macho_img_szB > 0);
+
+ /* Poke around in the Mach-O header, to find some important
+ stuff.
+ * the location of the __UNIXSTACK load command, if any
+ * the location of the __LINKEDIT load command, if any
+ * the initial RSP value as stated in the LC_UNIXTHREAD
+ */
+
+ /* The collected data */
+ ULong init_rsp = 0;
+ Bool have_rsp = False;
+ struct segment_command_64* seg__unixstack = NULL;
+ struct segment_command_64* seg__linkedit = NULL;
+
+ /* Loop over the load commands and fill in the above 4 variables. */
+
+ { struct mach_header_64 *mh = (struct mach_header_64 *)ii.macho_img;
+ struct load_command *cmd;
+ Int c;
+
+ for (c = 0, cmd = (struct load_command *)(mh+1);
+ c < mh->ncmds;
+ c++, cmd = (struct load_command *)(cmd->cmdsize
+ + (unsigned long)cmd)) {
+ if (DEBUGPRINTING)
+ printf("load cmd: offset %4lu size %3d kind %2d = ",
+ (unsigned long)((UChar*)cmd - (UChar*)ii.macho_img),
+ cmd->cmdsize, cmd->cmd);
+
+ switch (cmd->cmd) {
+ case LC_SEGMENT_64:
+ if (DEBUGPRINTING)
+ printf("LC_SEGMENT_64");
+ break;
+ case LC_SYMTAB:
+ if (DEBUGPRINTING)
+ printf("LC_SYMTAB");
+ break;
+ case LC_DYSYMTAB:
+ if (DEBUGPRINTING)
+ printf("LC_DYSYMTAB");
+ break;
+ case LC_UUID:
+ if (DEBUGPRINTING)
+ printf("LC_UUID");
+ break;
+ case LC_UNIXTHREAD:
+ if (DEBUGPRINTING)
+ printf("LC_UNIXTHREAD");
+ break;
+ default:
+ printf("???");
+ fail("unexpected load command in Mach header");
+ break;
+ }
+ if (DEBUGPRINTING)
+ printf("\n");
+
+ /* Note what the stated initial RSP value is, so we can
+ check it is as expected. */
+ if (cmd->cmd == LC_UNIXTHREAD) {
+ struct thread_command* tcmd = (struct thread_command*)cmd;
+ UInt* w32s = (UInt*)( (UChar*)tcmd + sizeof(*tcmd) );
+ if (DEBUGPRINTING)
+ printf("UnixThread: flavor %u = ", w32s[0]);
+ if (w32s[0] == x86_THREAD_STATE64 && !have_rsp) {
+ if (DEBUGPRINTING)
+ printf("x86_THREAD_STATE64\n");
+ x86_thread_state64_t* state64
+ = (x86_thread_state64_t*)(&w32s[2]);
+ have_rsp = True;
+ init_rsp = state64->__rsp;
+ if (DEBUGPRINTING)
+ printf("rsp = 0x%llx\n", init_rsp);
+ } else {
+ if (DEBUGPRINTING)
+ printf("???");
+ }
+ if (DEBUGPRINTING)
+ printf("\n");
+ }
+
+ if (cmd->cmd == LC_SEGMENT_64) {
+ struct segment_command_64 *seg = (struct segment_command_64
*)cmd;
+ if (0 == strcmp(seg->segname, "__LINKEDIT"))
+ seg__linkedit = seg;
+ if (0 == strcmp(seg->segname, "__UNIXSTACK"))
+ seg__unixstack = seg;
+ }
+
+ }
+ }
+
+ /*
+ Actions are then as follows:
+
+ * (always) check the RSP value is as expected, and abort if not
+
+ * if there's a UNIXSTACK load command, check it is as expected.
+ If not abort, if yes, do nothing more.
+
+ * (so there's no UNIXSTACK load command). if there's a LINKEDIT
+ load command, check if it is minimally usable (has 0 for
+ nsects and flags). If yes, convert it to a UNIXSTACK load
+ command. If there is none, or is unusable, then we're out of
+ options and have to abort.
+ */
+ if (!have_rsp)
+ fail("Can't find / check initial RSP setting");
+ if (init_rsp != expected_stack_start + expected_stack_size)
+ fail("Initial RSP value not as expected");
+
+ fprintf(stderr, "fixup_macho_loadcmds: "
+ "initial RSP is as expected (0x%llx)\n",
+ expected_stack_start + expected_stack_size );
+
+ if (seg__unixstack) {
+ struct segment_command_64 *seg = seg__unixstack;
+ if (seg->vmaddr != expected_stack_start)
+ fail("has __UNIXSTACK, but wrong ::vmaddr");
+ if (seg->vmsize != expected_stack_size)
+ fail("has __UNIXSTACK, but wrong ::vmsize");
+ if (seg->maxprot != 7)
+ fail("has __UNIXSTACK, but wrong ::maxprot (should be 7)");
+ if (seg->initprot != 3)
+ fail("has __UNIXSTACK, but wrong ::initprot (should be 3)");
+ if (seg->nsects != 0)
+ fail("has __UNIXSTACK, but wrong ::nsects (should be 0)");
+ if (seg->flags != 0)
+ fail("has __UNIXSTACK, but wrong ::flags (should be 0)");
+ /* looks ok */
+ fprintf(stderr, "fixup_macho_loadcmds: "
+ "acceptable __UNIXSTACK present; no modifications.\n" );
+ goto out;
+ }
+
+ if (seg__linkedit) {
+ struct segment_command_64 *seg = seg__linkedit;
+ if (seg->nsects != 0)
+ fail("has __LINKEDIT, but wrong ::nsects (should be 0)");
+ if (seg->flags != 0)
+ fail("has __LINKEDIT, but wrong ::flags (should be 0)");
+ fprintf(stderr, "fixup_macho_loadcmds: "
+ "no __UNIXSTACK present.\n" );
+ fprintf(stderr, "fixup_macho_loadcmds: "
+ "converting __LINKEDIT to __UNIXSTACK.\n" );
+ strcpy(seg->segname, "__UNIXSTACK");
+ seg->vmaddr = expected_stack_start;
+ seg->vmsize = expected_stack_size;
+ seg->fileoff = 0;
+ seg->filesize = 0;
+ seg->maxprot = 7;
+ seg->initprot = 3;
+ /* success */
+ goto out;
+ }
+
+ /* out of options */
+ fail("no __UNIXSTACK found and no usable __LINKEDIT found; "
+ "out of options.");
+ /* NOTREACHED */
+
+ out:
+ if (ii.img)
+ unmap_image(&ii);
+}
+
+
+static Bool is_plausible_tool_exe_name ( HChar* nm )
+{
+ HChar* p;
+ if (!nm)
+ return False;
+
+ // Does it end with this string?
+ p = strstr(nm, "-x86-darwin");
+ if (p && 0 == strcmp(p, "-x86-darwin"))
+ return True;
+
+ p = strstr(nm, "-amd64-darwin");
+ if (p && 0 == strcmp(p, "-amd64-darwin"))
+ return True;
+
+ return False;
+}
+
+
+int main ( int argc, char** argv )
+{
+ Int r;
+ ULong req_stack_addr = 0;
+ ULong req_stack_size = 0;
+
+ if (argc != 4)
+ fail("args: -stack_addr-arg -stack_size-arg "
+ "name-of-tool-executable-to-modify");
+
+ r= sscanf(argv[1], "0x%llx", &req_stack_addr);
+ if (r != 1) fail("invalid stack_addr arg");
+
+ r= sscanf(argv[2], "0x%llx", &req_stack_size);
+ if (r != 1) fail("invalid stack_size arg");
+
+ fprintf(stderr, "fixup_macho_loadcmds: "
+ "requested stack_addr (top) 0x%llx, "
+ "stack_size 0x%llx\n", req_stack_addr, req_stack_size );
+
+ if (!is_plausible_tool_exe_name(argv[3]))
+ fail("implausible tool exe name -- not of the form
*-{x86,amd64}-darwin");
+
+ fprintf(stderr, "fixup_macho_loadcmds: examining tool exe: %s\n",
+ argv[3] );
+ modify_macho_loadcmds( argv[3], req_stack_addr - req_stack_size,
+ req_stack_size );
+
+ return 0;
+}
+
+/*
+ cmd LC_SEGMENT_64
+ cmdsize 72
+ segname __LINKEDIT
+ vmaddr 0x0000000138dea000
+ vmsize 0x00000000000ad000
+ fileoff 2658304
+ filesize 705632
+ maxprot 0x00000007
+ initprot 0x00000001
+ nsects 0
+ flags 0x0
+*/
+
+/*
+ cmd LC_SEGMENT_64
+ cmdsize 72
+ segname __UNIXSTACK
+ vmaddr 0x0000000133800000
+ vmsize 0x0000000000800000
+ fileoff 2498560
+ filesize 0
+ maxprot 0x00000007
+ initprot 0x00000003
+ nsects 0
+ flags 0x0
+*/
=======================================
--- /dev/null
+++ /trunk/valgrind/drd/drd_darwin_intercepts.c Fri Oct 28 06:00:35 2011
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
+/*
+ This file is part of drd, a thread error detector.
+
+ Copyright (C) 2006-2011 Bart Van Assche <bvana...@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 <stdint.h>
+#include <stdio.h>
+#include "valgrind.h"
+#include "drd.h"
+#include "pub_tool_redir.h"
+
+/*
+ * On Mac OS X shared library functions are lazily bound. The binding
mechanism
+ * uses self-modifying code. Intercept fastBindLazySymbol() in order to
suppress
+ * the data accesses involved in this mechanism.
+ *
+ * See also the Mac OS X ABI Dynamic Loader Reference
(http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/MachOReference/Reference/reference.html#//apple_ref/c/func/dyld_stub_binding_helper).
+ * See also the dyld_stub_binder() source code
(http://www.opensource.apple.com/source/dyld/dyld-132.13/src/dyld_stub_binder.s).
+ * See also the dyld::fastBindLazySymbol() source code
(http://opensource.apple.com/source/dyld/dyld-132.13/src/dyld.cpp).
+ */
+void* VG_WRAP_FUNCTION_ZZ(dyld,
ZuZZN4dyld18fastBindLazySymbolEPP11ImageLoaderm)
+ (void** imageLoaderCache, uintptr_t lazyBindingInfoOffset);
+void* VG_WRAP_FUNCTION_ZZ(dyld,
ZuZZN4dyld18fastBindLazySymbolEPP11ImageLoaderm)
+ (void** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
+{
+ void* res;
+ OrigFn fn;
+
+ VALGRIND_GET_ORIG_FN(fn);
+
+ ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+ CALL_FN_W_WW(res, fn, imageLoaderCache, lazyBindingInfoOffset);
+ ANNOTATE_IGNORE_READS_AND_WRITES_END();
+
+ return res;
+}
=======================================
--- /trunk/valgrind/coregrind/m_debuginfo/readmacho.c Tue Oct 25 09:11:36
2011
+++ /trunk/valgrind/coregrind/m_debuginfo/readmacho.c Fri Oct 28 06:00:35
2011
@@ -8,7 +8,7 @@
This file is part of Valgrind, a dynamic binary instrumentation
framework.
- Copyright (C) 2005-2010 Apple Inc.
+ Copyright (C) 2005-2011 Apple Inc.
Greg Parker gpa...@apple.com
This program is free software; you can redistribute it and/or
@@ -325,7 +325,7 @@
{
Int i;
Addr sym_addr;
- DiSym risym;
+ DiSym disym;
UChar* name;
static UChar* s_a_t_v = NULL; /* do not make non-static */
@@ -363,43 +363,45 @@
if (*name == 0)
continue;
- risym.tocptr = 0;
- risym.addr = sym_addr;
- risym.size = // let canonicalize fix it
- di->text_avma+di->text_size - sym_addr;
- risym.name = ML_(addStr)(di, name, -1);
- risym.isText = True;
- risym.isIFunc = False;
+ disym.addr = sym_addr;
+ disym.tocptr = 0;
+ disym.pri_name = ML_(addStr)(di, name, -1);
+ disym.sec_names = NULL;
+ disym.size = // let canonicalize fix it
+ di->text_avma+di->text_size - sym_addr;
+ disym.isText = True;
+ disym.isIFunc = False;
// Lots of user function names get prepended with an underscore.
Eg. the
// function 'f' becomes the symbol '_f'. And the "below main"
// function is called "start". So we skip the leading underscore,
and
// if we see 'start' and --show-below-main=no, we rename it as
// "start_according_to_valgrind", which makes it easy to spot later
// and display as "(below main)".
- if (risym.name[0] == '_') {
- risym.name++;
- } else if (!VG_(clo_show_below_main) &&
VG_STREQ(risym.name, "start")) {
+ if (disym.pri_name[0] == '_') {
+ disym.pri_name++;
+ }
+ else if (!VG_(clo_show_below_main) &&
VG_STREQ(disym.pri_name, "start")) {
if (s_a_t_v == NULL)
s_a_t_v = ML_(addStr)(di, "start_according_to_valgrind", -1);
vg_assert(s_a_t_v);
- risym.name = s_a_t_v;
+ disym.pri_name = s_a_t_v;
}
- vg_assert(risym.name);
- VG_(addToXA)( syms, &risym );
+ vg_assert(disym.pri_name);
+ VG_(addToXA)( syms, &disym );
}
}
/* Compare DiSyms by their start address, and for equal addresses, use
- the name as a secondary sort key. */
+ the primary name as a secondary sort key. */
static Int cmp_DiSym_by_start_then_name ( void* v1, void* v2 )
{
DiSym* s1 = (DiSym*)v1;
DiSym* s2 = (DiSym*)v2;
if (s1->addr < s2->addr) return -1;
if (s1->addr > s2->addr) return 1;
- return VG_(strcmp)(s1->name, s2->name);
+ return VG_(strcmp)(s1->pri_name, s2->pri_name);
}
/* 'cand' is a bunch of candidate symbols obtained by reading
@@ -468,13 +470,13 @@
s_i = (DiSym*)VG_(indexXA)(syms, i);
if (s_i->addr != s_j1->addr
|| s_i->size != s_j1->size
- || 0 != VG_(strcmp)(s_i->name, s_j1->name)) {
+ || 0 != VG_(strcmp)(s_i->pri_name, s_j1->pri_name)) {
*s_j = *s_i;
j++;
} else {
if (trace_symtab)
VG_(printf)("nlist cleanup: dump duplicate
avma %010lx %s\n",
- s_i->addr, s_i->name );
+ s_i->addr, s_i->pri_name );
}
}
}
@@ -680,17 +682,18 @@
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_DebugMsg,
- "%s (%#lx)\n", di->filename, di->rx_map_avma );
-
- /* This should be ensured by our caller. */
- vg_assert(di->have_rx_map);
- vg_assert(di->have_rw_map);
+ "%s (%#lx)\n", di->fsm.filename, di->fsm.rx_map_avma );
+
+ /* This should be ensured by our caller (that we're in the accept
+ state). */
+ vg_assert(di->fsm.have_rx_map);
+ vg_assert(di->fsm.have_rw_map);
VG_(memset)(&ii, 0, sizeof(ii));
VG_(memset)(&iid, 0, sizeof(iid));
VG_(memset)(&uuid, 0, sizeof(uuid));
- ok = map_image_aboard( di, &ii, di->filename );
+ ok = map_image_aboard( di, &ii, di->fsm.filename );
if (!ok) goto fail;
vg_assert(ii.macho_img != NULL && ii.macho_img_szB > 0);
@@ -776,7 +779,7 @@
&& seg->fileoff == 0 && seg->filesize != 0) {
di->text_present = True;
di->text_svma = (Addr)seg->vmaddr;
- di->text_avma = di->rx_map_avma;
+ di->text_avma = di->fsm.rx_map_avma;
di->text_size = seg->vmsize;
di->text_bias = di->text_avma - di->text_svma;
/* Make the _debug_ values be the same as the
@@ -793,7 +796,7 @@
/* && DDD:seg->fileoff == 0 */ && seg->filesize != 0) {
di->data_present = True;
di->data_svma = (Addr)seg->vmaddr;
- di->data_avma = di->rw_map_avma;
+ di->data_avma = di->fsm.rw_map_avma;
di->data_size = seg->vmsize;
di->data_bias = di->data_avma - di->data_svma;
di->data_debug_svma = di->data_svma;
@@ -811,6 +814,12 @@
if (!di->soname) {
di->soname = ML_(dinfo_strdup)("di.readmacho.noname", "NONE");
}
+
+ if (di->trace_symtab) {
+ VG_(printf)("\n");
+ VG_(printf)("SONAME = %s\n", di->soname);
+ VG_(printf)("\n");
+ }
/* Now we have the base object to hand. Read symbols from it. */
@@ -870,9 +879,12 @@
nCandSyms = VG_(sizeXA)( candSyms );
for (i = 0; i < nCandSyms; i++) {
DiSym* cand = (DiSym*) VG_(indexXA)( candSyms, i );
+ vg_assert(cand->pri_name != NULL);
+ vg_assert(cand->sec_names == NULL);
if (di->trace_symtab)
VG_(printf)("nlist final: acquire avma %010lx-%010lx %s\n",
- cand->addr, cand->addr + cand->size - 1,
cand->name );
+ cand->addr, cand->addr + cand->size - 1,
+ cand->pri_name );
ML_(addSym)( di, cand );
}
VG_(deleteXA)( candSyms );
@@ -892,7 +904,7 @@
/* mmap the dSYM file to look for DWARF debug info. If successful,
use the .macho_img and .macho_img_szB in iid. */
- dsymfilename = find_separate_debug_file( di->filename );
+ dsymfilename = find_separate_debug_file( di->fsm.filename );
/* Try to load it. */
if (dsymfilename) {
@@ -925,13 +937,13 @@
give up. (possible reasons: is system lib, or in /usr etc, or
the dsym dir would not be writable by the user, or we're running
as root) */
- vg_assert(di->filename);
- if (is_systemish_library_name(di->filename))
+ vg_assert(di->fsm.filename);
+ if (is_systemish_library_name(di->fsm.filename))
goto success;
if (!VG_(clo_dsymutil)) {
if (VG_(clo_verbosity) == 1) {
- VG_(message)(Vg_DebugMsg, "%s:\n", di->filename);
+ VG_(message)(Vg_DebugMsg, "%s:\n", di->fsm.filename);
}
if (VG_(clo_verbosity) > 0)
VG_(message)(Vg_DebugMsg, "%sdSYM directory %s; consider using "
@@ -947,19 +959,19 @@
HChar* dsymutil = "/usr/bin/dsymutil ";
HChar* cmd = ML_(dinfo_zalloc)( "di.readmacho.tmp1",
VG_(strlen)(dsymutil)
- + VG_(strlen)(di->filename)
+ + VG_(strlen)(di->fsm.filename)
+ 32 /* misc */ );
VG_(strcpy)(cmd, dsymutil);
if (0) VG_(strcat)(cmd, "--verbose ");
VG_(strcat)(cmd, "\"");
- VG_(strcat)(cmd, di->filename);
+ VG_(strcat)(cmd, di->fsm.filename);
VG_(strcat)(cmd, "\"");
VG_(message)(Vg_DebugMsg, "run: %s\n", cmd);
r = VG_(system)( cmd );
if (r)
VG_(message)(Vg_DebugMsg, "run: %s FAILED\n", dsymutil);
ML_(dinfo_free)(cmd);
- dsymfilename = find_separate_debug_file(di->filename);
+ dsymfilename = find_separate_debug_file(di->fsm.filename);
}
/* Try again to load it. */
@@ -989,7 +1001,7 @@
(UInt)uuid[11], (UInt)uuid[12], (UInt)uuid[13],
(UInt)uuid[14], (UInt)uuid[15] );
VG_(message)(Vg_DebugMsg,
- "WARNING: for %s\n", di->filename);
+ "WARNING: for %s\n", di->fsm.filename);
}
unmap_image( &iid );
/* unmap_image zeroes the fields, so the following test makes
@@ -1046,7 +1058,7 @@
VG_(message)(Vg_DebugMsg,
"Reading dwarf3 for %s (%#lx) from %s"
" (%ld %ld %ld %ld %ld %ld)\n",
- di->filename, di->text_avma, dsymfilename,
+ di->fsm.filename, di->text_avma, dsymfilename,
debug_info_sz, debug_abbv_sz, debug_line_sz,
debug_str_sz, debug_ranges_sz, debug_loc_sz
);