|
From: <sv...@va...> - 2013-06-07 16:16:04
|
sewardj 2013-06-07 17:15:48 +0100 (Fri, 07 Jun 2013)
New Revision: 13423
Log:
Initial code for remote debuginfo server. Handles all ELF/Dwarf{2,3,4}
on Linux. No Dwarf1, no Stabs, and MacOSX probably won't build.
Added files:
branches/DISRV/auxprogs/valgrind-di-server.c
branches/DISRV/coregrind/m_debuginfo/image.c
branches/DISRV/coregrind/m_debuginfo/lzoconf.h
branches/DISRV/coregrind/m_debuginfo/lzodefs.h
branches/DISRV/coregrind/m_debuginfo/minilzo-inl.c
branches/DISRV/coregrind/m_debuginfo/minilzo.h
branches/DISRV/coregrind/m_debuginfo/priv_image.h
Modified files:
branches/DISRV/auxprogs/Makefile.am
branches/DISRV/coregrind/Makefile.am
branches/DISRV/coregrind/m_debuginfo/d3basics.c
branches/DISRV/coregrind/m_debuginfo/debuginfo.c
branches/DISRV/coregrind/m_debuginfo/priv_readdwarf.h
branches/DISRV/coregrind/m_debuginfo/priv_readdwarf3.h
branches/DISRV/coregrind/m_debuginfo/priv_storage.h
branches/DISRV/coregrind/m_debuginfo/readdwarf.c
branches/DISRV/coregrind/m_debuginfo/readdwarf3.c
branches/DISRV/coregrind/m_debuginfo/readelf.c
branches/DISRV/coregrind/m_debuginfo/readpdb.c
branches/DISRV/coregrind/m_debuginfo/readstabs.c
branches/DISRV/coregrind/m_debuginfo/storage.c
branches/DISRV/coregrind/m_libcbase.c
branches/DISRV/coregrind/m_libcfile.c
branches/DISRV/coregrind/m_main.c
branches/DISRV/coregrind/m_options.c
branches/DISRV/coregrind/pub_core_libcfile.h
branches/DISRV/coregrind/pub_core_options.h
branches/DISRV/include/pub_tool_libcbase.h
branches/DISRV/include/vki/vki-linux.h
Modified: branches/DISRV/coregrind/m_debuginfo/storage.c (+16 -0)
===================================================================
--- branches/DISRV/coregrind/m_debuginfo/storage.c 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_debuginfo/storage.c 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -47,6 +47,7 @@
#include "pub_core_oset.h"
#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
+#include "priv_image.h"
#include "priv_d3basics.h" /* ML_(pp_GX) */
#include "priv_tytypes.h"
#include "priv_storage.h" /* self */
@@ -249,6 +250,21 @@
}
+/* Add a string to the string table of a DebugInfo, by copying the
+ string from the given DiCursor. Measures the length of the string
+ itself. */
+HChar* ML_(addStrFromCursor)( struct _DebugInfo* di, DiCursor c )
+{
+ /* This is a less-than-stellar implementation, but it should
+ work. */
+ vg_assert(ML_(cur_is_valid)(c));
+ HChar* str = ML_(cur_read_strdup)(c, "di.addStrFromCursor.1");
+ HChar* res = ML_(addStr)(di, str, -1);
+ ML_(dinfo_free)(str);
+ return res;
+}
+
+
/* Add a symbol to the symbol table, by copying *sym. 'sym' may only
have one name, so there's no complexities to do with deep vs
shallow copying of the sec_name array. This is checked.
Modified: branches/DISRV/coregrind/m_debuginfo/priv_storage.h (+7 -1)
===================================================================
--- branches/DISRV/coregrind/m_debuginfo/priv_storage.h 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_debuginfo/priv_storage.h 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -845,6 +845,11 @@
ML_(addStr) will itself measure the length of the string. */
extern HChar* ML_(addStr) ( struct _DebugInfo* di, const HChar* str, Int len );
+/* Add a string to the string table of a DebugInfo, by copying the
+ string from the given DiCursor. Measures the length of the string
+ itself. */
+extern HChar* ML_(addStrFromCursor)( struct _DebugInfo* di, DiCursor c );
+
extern void ML_(addVar)( struct _DebugInfo* di,
Int level,
Addr aMin,
@@ -908,8 +913,9 @@
extern void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si );
+#define TRACE_SYMTAB_ENABLED (di->trace_symtab)
#define TRACE_SYMTAB(format, args...) \
- if (di->trace_symtab) { VG_(printf)(format, ## args); }
+ if (TRACE_SYMTAB_ENABLED) { VG_(printf)(format, ## args); }
#endif /* ndef __PRIV_STORAGE_H */
Added: branches/DISRV/coregrind/m_debuginfo/minilzo.h (+109 -0)
===================================================================
--- branches/DISRV/coregrind/m_debuginfo/minilzo.h 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_debuginfo/minilzo.h 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -0,0 +1,109 @@
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <ma...@ob...>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __MINILZO_H
+#define __MINILZO_H 1
+
+#define MINILZO_VERSION 0x2060
+
+#ifdef __LZOCONF_H
+# error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+# error "version mismatch in header files"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS (0)
+
+
+/* compression */
+LZO_EXTERN(int)
+lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem );
+
+/* decompression */
+LZO_EXTERN(int)
+lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+LZO_EXTERN(int)
+lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
Added: branches/DISRV/coregrind/m_debuginfo/image.c (+956 -0)
===================================================================
--- branches/DISRV/coregrind/m_debuginfo/image.c 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_debuginfo/image.c 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -0,0 +1,956 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
+
+/*--------------------------------------------------------------------*/
+/*--- An abstraction that provides a file-reading mechanism. ---*/
+/*--- image.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2013-2013 Mozilla Foundation
+
+ 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.
+*/
+
+/* Contributed by Julian Seward <js...@ac...> */
+
+/* See the corresponding auxprogs/valgrind-di-server.c for a list of
+ cleanups for this file and itself. */
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcfile.h"
+#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
+#include "priv_image.h" /* self */
+
+#include "pub_tool_libcproc.h" // RMME
+#include "minilzo.h"
+
+#define CACHE_ENTRY_SIZE_BITS (12+1)
+#define CACHE_N_ENTRIES 32
+
+#define CACHE_ENTRY_SIZE (1 << CACHE_ENTRY_SIZE_BITS)
+
+/* An entry in the cache. */
+typedef
+ struct {
+ DiOffT off; // file offset for data[0]
+ SizeT used; // 1 .. sizeof(data), or 0 to denote not-in-use
+ UChar data[CACHE_ENTRY_SIZE];
+ }
+ CEnt;
+
+/* Source for files */
+typedef
+ struct {
+ // True: img is of local file. False: img is from a server.
+ Bool is_local;
+ // The fd for the local file, or sd for a remote server.
+ Int fd;
+ // The rest of these fields are only valid when using remote files
+ // (that is, using a debuginfo server; hence when is_local==False)
+ // Session ID allocated to us by the server. Cannot be zero.
+ ULong session_id;
+ }
+ Source;
+
+struct _DiImage {
+ // The source -- how to get hold of the file we are reading
+ Source source;
+ // Total size of the image.
+ SizeT size;
+ // The number of entries used. 0 .. CACHE_N_ENTRIES
+ UInt ces_used;
+ // Pointers to the entries. ces[0 .. ces_used-1] are non-NULL.
+ // ces[ces_used .. CACHE_N_ENTRIES-1] are NULL.
+ // The non-NULL entries may be arranged arbitrarily. We expect to use
+ // a pseudo-LRU scheme though.
+ CEnt* ces[CACHE_N_ENTRIES];
+};
+
+/* A frame. The first 4 bytes of |data| give the kind of the frame,
+ and the rest of it is kind-specific data. */
+typedef struct { UChar* data; SizeT n_data; } Frame;
+
+static void write_UInt_le ( /*OUT*/UChar* dst, UInt n )
+{
+ Int i;
+ for (i = 0; i <= 3; i++) {
+ dst[i] = (UChar)(n & 0xFF);
+ n >>= 8;
+ }
+}
+
+static UInt read_UInt_le ( UChar* src )
+{
+ UInt r = 0;
+ Int i;
+ for (i = 3; i >= 0; i--) {
+ r <<= 8;
+ r += (UInt)src[i];
+ }
+ return r;
+}
+
+static void write_ULong_le ( /*OUT*/UChar* dst, ULong n )
+{
+ Int i;
+ for (i = 0; i <= 7; i++) {
+ dst[i] = (UChar)(n & 0xFF);
+ n >>= 8;
+ }
+}
+
+static ULong read_ULong_le ( UChar* src )
+{
+ ULong r = 0;
+ Int i;
+ for (i = 7; i >= 0; i--) {
+ r <<= 8;
+ r += (ULong)src[i];
+ }
+ return r;
+}
+
+
+/* Set |sd| to be blocking. Returns True on success. */
+static Bool set_blocking ( int sd )
+{
+ Int res;
+ res = VG_(fcntl)(sd, VKI_F_GETFL, 0/*ignored*/);
+ if (res != -1)
+ res = VG_(fcntl)(sd, VKI_F_SETFL, res & ~VKI_O_NONBLOCK);
+ return (res != -1);
+}
+
+/* Tries to read 'len' bytes from fd, blocking if necessary. Assumes
+ fd has been set in blocking mode. If it returns with the number of
+ bytes read < len, it means that either fd was closed, or there was
+ an error on it. */
+static Int my_read ( Int fd, UChar* buf, Int len )
+{
+ Int nRead = 0;
+ while (1) {
+ if (nRead == len) return nRead;
+ vg_assert(nRead < len);
+ Int nNeeded = len - nRead;
+ vg_assert(nNeeded > 0);
+ Int n = VG_(read)(fd, &buf[nRead], nNeeded);
+ if (n <= 0) return nRead; /* error or EOF */
+ nRead += n;
+ }
+}
+
+/* Tries to write 'len' bytes to fd, blocking if necessary. Assumes
+ fd has been set in blocking mode. If it returns with the number of
+ bytes written < len, it means that either fd was closed, or there was
+ an error on it. */
+static Int my_write ( Int fd, UChar* buf, Int len )
+{
+ Int nWritten = 0;
+ while (1) {
+ if (nWritten == len) return nWritten;
+ vg_assert(nWritten < len);
+ Int nStillToDo = len - nWritten;
+ vg_assert(nStillToDo > 0);
+ Int n = VG_(write_socket)(fd, &buf[nWritten], nStillToDo);
+ if (n < 0) return nWritten; /* error or EOF */
+ nWritten += n;
+ }
+}
+
+
+/* "Do" a transaction: that is, send the given frame to the server and
+ return the frame it sends back. Caller owns the resulting frame
+ and must free it. A NULL return means the transaction failed for
+ some reason. */
+static Frame* do_transaction ( Int sd, Frame* req )
+{
+if (0) VG_(printf)("CLIENT: send %c%c%c%c\n", req->data[0], req->data[1], req->data[2], req->data[3]);
+ /* What goes on the wire is:
+ adler(le32) n_data(le32) data[0 .. n_data-1]
+ where the checksum covers n_data as well as data[].
+ */
+ /* The initial Adler-32 value */
+ UInt adler = VG_(adler32)(0, NULL, 0);
+
+ /* Fold in the length field, encoded as le32. */
+ UChar wr_first8[8];
+ write_UInt_le(&wr_first8[4], req->n_data);
+ adler = VG_(adler32)(adler, &wr_first8[4], 4);
+ /* Fold in the data values */
+ adler = VG_(adler32)(adler, req->data, req->n_data);
+ write_UInt_le(&wr_first8[0], adler);
+
+ Int r = my_write(sd, &wr_first8[0], 8);
+ if (r != 8) return NULL;
+ vg_assert(req->n_data >= 4); // else ill formed -- no KIND field
+ r = my_write(sd, req->data, req->n_data);
+ if (r != req->n_data) return NULL;
+
+ /* So, the request is sent. Now get a request of the same format
+ out of the channel. */
+ UChar rd_first8[8]; // adler32; length32
+ r = my_read(sd, &rd_first8[0], 8);
+ if (r != 8) return NULL;
+ UInt rd_adler = read_UInt_le(&rd_first8[0]);
+ UInt rd_len = read_UInt_le(&rd_first8[4]);
+ /* Allocate a Frame to hold the result data, and read into it. */
+ // Reject obviously-insane length fields.
+ if (rd_len < 4 || rd_len > 4*1024*1024) return NULL;
+ Frame* res = ML_(dinfo_zalloc)("di.do_transaction.1", sizeof(Frame));
+ res->n_data = rd_len;
+ res->data = ML_(dinfo_zalloc)("di.do_transaction.2", rd_len);
+ r = my_read(sd, res->data, res->n_data);
+ if (r != rd_len) return NULL;
+
+if (0) VG_(printf)("CLIENT: recv %c%c%c%c\n", res->data[0], res->data[1], res->data[2], res->data[3]);
+
+ /* Compute the checksum for the received data, and check it. */
+ adler = VG_(adler32)(0, NULL, 0); // initial value
+ adler = VG_(adler32)(adler, &rd_first8[4], 4);
+ if (res->n_data > 0)
+ adler = VG_(adler32)(adler, res->data, res->n_data);
+
+ if (adler/*computed*/ != rd_adler/*expected*/) return NULL;
+ return res;
+}
+
+static void free_Frame ( Frame* fr )
+{
+ vg_assert(fr && fr->data);
+ ML_(dinfo_free)(fr->data);
+ ML_(dinfo_free)(fr);
+}
+
+static Frame* mk_Frame_noargs ( const HChar* tag )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ Frame* f = ML_(dinfo_zalloc)("di.mFn.1", sizeof(Frame));
+ f->n_data = 4;
+ f->data = ML_(dinfo_zalloc)("di.mFn.2", f->n_data);
+ VG_(memcpy)(&f->data[0], tag, 4);
+ return f;
+}
+
+static Frame* mk_Frame_le64_le64_le64 ( const HChar* tag,
+ ULong n1, ULong n2, ULong n3 )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ Frame* f = ML_(dinfo_zalloc)("di.mFlll.1", sizeof(Frame));
+ f->n_data = 4 + 3*8;
+ f->data = ML_(dinfo_zalloc)("di.mFlll.2", f->n_data);
+ VG_(memcpy)(&f->data[0], tag, 4);
+ write_ULong_le(&f->data[4 + 0*8], n1);
+ write_ULong_le(&f->data[4 + 1*8], n2);
+ write_ULong_le(&f->data[4 + 2*8], n3);
+ return f;
+}
+
+static Frame* mk_Frame_asciiz ( const HChar* tag, const HChar* str )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ Frame* f = ML_(dinfo_zalloc)("di.mFa.1", sizeof(Frame));
+ SizeT n_str = VG_(strlen)(str);
+ f->n_data = 4 + n_str + 1;
+ f->data = ML_(dinfo_zalloc)("di.mFa.2", f->n_data);
+ VG_(memcpy)(&f->data[0], tag, 4);
+ VG_(memcpy)(&f->data[4], str, n_str);
+ vg_assert(f->data[4 + n_str] == 0);
+ return f;
+}
+
+static Bool parse_Frame_le64 ( Frame* fr, const HChar* tag, /*OUT*/ULong* n1 )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data != 4 + 1*8) return False;
+ *n1 = read_ULong_le(&fr->data[4 + 0*8]);
+ return True;
+}
+
+static Bool parse_Frame_le64_le64 ( Frame* fr, const HChar* tag,
+ /*OUT*/ULong* n1, /*OUT*/ULong* n2 )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data != 4 + 2*8) return False;
+ *n1 = read_ULong_le(&fr->data[4 + 0*8]);
+ *n2 = read_ULong_le(&fr->data[4 + 1*8]);
+ return True;
+}
+
+static Bool parse_Frame_asciiz ( Frame* fr, const HChar* tag,
+ /*OUT*/UChar** str )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data < 5) return False; // else there isn't even enough
+ // space for the terminating zero
+ /* Find the terminating zero and ensure it's right at the end
+ of the data. If not, the frame is malformed. */
+ SizeT i = 4;
+ while (True) {
+ if (i >= fr->n_data) break;
+ if (fr->data[i] == 0) break;
+ i++;
+ }
+ vg_assert(i <= fr->n_data);
+ if (i == fr->n_data-1 && fr->data[i] == 0) {
+ *str = &fr->data[4];
+ return True;
+ } else {
+ return False;
+ }
+}
+
+static Bool parse_Frame_le64_le64_le64_bytes (
+ Frame* fr, const HChar* tag,
+ /*OUT*/ULong* n1, /*OUT*/ULong* n2, /*OUT*/ULong* n3,
+ /*OUT*/UChar** data, /*OUT*/ULong* n_data
+ )
+{
+ vg_assert(VG_(strlen)(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data < 4 + 3*8) return False;
+ *n1 = read_ULong_le(&fr->data[4 + 0*8]);
+ *n2 = read_ULong_le(&fr->data[4 + 1*8]);
+ *n3 = read_ULong_le(&fr->data[4 + 2*8]);
+ *data = &fr->data[4 + 3*8];
+ *n_data = fr->n_data - (4 + 3*8);
+ vg_assert(fr->n_data >= 4 + 3*8);
+ return True;
+}
+
+static DiOffT block_round_down ( DiOffT i )
+{
+ return i & ((DiOffT)~(CACHE_ENTRY_SIZE-1));
+}
+
+/* Is this offset inside this CEnt? */
+static inline Bool is_in_CEnt ( CEnt* cent, DiOffT off )
+{
+ /* This assertion is checked by set_CEnt, so checking it here has
+ no benefit, whereas skipping it does remove it from the hottest
+ path. */
+ /* vg_assert(cent->used > 0 && cent->used <= CACHE_ENTRY_SIZE); */
+ return cent->off <= off && off < cent->off + cent->used;
+}
+
+/* Allocate a new CEnt, connect it to |img|, and return its index. */
+static UInt alloc_CEnt ( DiImage* img )
+{
+ vg_assert(img);
+ vg_assert(img->ces_used < CACHE_N_ENTRIES);
+ UInt entNo = img->ces_used;
+ img->ces_used++;
+ vg_assert(img->ces[entNo] == NULL);
+ img->ces[entNo] = ML_(dinfo_zalloc)("di.alloc_CEnt.1", sizeof(CEnt));
+ return entNo;
+}
+
+/* Move the given entry to the top and slide those above it down by 1,
+ to make space. */
+static void move_CEnt_to_top ( DiImage* img, UInt entNo )
+{
+ vg_assert(img->ces_used <= CACHE_N_ENTRIES);
+ vg_assert(entNo > 0 && entNo < img->ces_used);
+ CEnt* tmp = img->ces[entNo];
+ while (entNo > 0) {
+ img->ces[entNo] = img->ces[entNo-1];
+ entNo--;
+ }
+ img->ces[0] = tmp;
+}
+
+/* Set the given entry so that it has a chunk of the file containing
+ the given offset. It is this function that brings data into the
+ cache, either by reading the local file or pulling it from the
+ remote server. */
+static void set_CEnt ( DiImage* img, UInt entNo, DiOffT off )
+{
+ SizeT len;
+ DiOffT off_orig = off;
+ vg_assert(img);
+ vg_assert(img->ces_used <= CACHE_N_ENTRIES);
+ vg_assert(entNo >= 0 && entNo < img->ces_used);
+ vg_assert(off < img->size);
+ vg_assert(img->ces[entNo] != NULL);
+ /* Compute [off, +len) as the slice we are going to read. */
+ off = block_round_down(off);
+ len = img->size - off;
+ if (len > CACHE_ENTRY_SIZE) len = CACHE_ENTRY_SIZE;
+ /* It is conceivable that the 'len > 0' bit could fail if we make
+ an image with a zero sized file. But then no 'get' request on
+ that image would be valid. */
+ vg_assert(len > 0 && len <= CACHE_ENTRY_SIZE);
+ vg_assert(off + len <= img->size);
+ vg_assert(off <= off_orig && off_orig < off+len);
+ /* So, read off .. off+len-1 into the entry. */
+ CEnt* ce = img->ces[entNo];
+
+if (0) {
+static UInt t_last = 0;
+static ULong nread = 0;
+UInt now = VG_(read_millisecond_timer)();
+UInt delay = now - t_last;
+t_last = now;
+nread += len;
+VG_(printf)("XXXXXXXX (tot %lld) read %ld offset %lld %u\n",
+ nread, len, off, delay);
+}
+
+ if (img->source.is_local) {
+ // Simple: just read it
+ SysRes sr = VG_(pread)(img->source.fd, &ce->data[0], (Int)len, off);
+ vg_assert(!sr_isError(sr));
+ } else {
+ // Not so simple: poke the server
+ vg_assert(img->source.session_id > 0);
+ Frame* req
+ = mk_Frame_le64_le64_le64("READ", img->source.session_id, off, len);
+ Frame* res = do_transaction(img->source.fd, req);
+ free_Frame(req); req = NULL;
+ if (!res) goto server_fail;
+ ULong rx_session_id = 0, rx_off = 0, rx_len = 0, rx_zdata_len = 0;
+ UChar* rx_data = NULL;
+ /* Pretty confusing. rx_sessionid, rx_off and rx_len are copies
+ of the values that we requested in the READ frame just above,
+ so we can be sure that the server is responding to the right
+ request. It just copies them from the request into the
+ response. rx_data is the actual data, and rx_zdata_len is
+ its compressed length. Hence rx_len must equal len, but
+ rx_zdata_len can be different -- smaller, hopefully.. */
+ if (!parse_Frame_le64_le64_le64_bytes
+ (res, "RDOK", &rx_session_id, &rx_off,
+ &rx_len, &rx_data, &rx_zdata_len))
+ goto server_fail;
+ if (rx_session_id != img->source.session_id
+ || rx_off != off || rx_len != len || rx_data == NULL)
+ goto server_fail;
+
+ //VG_(memcpy)(&ce->data[0], rx_data, len);
+ // Decompress into the destination buffer
+ // Tell the lib the max number of output bytes it can write.
+ // After the call, this holds the number of bytes actually written,
+ // and it's an error if it is different.
+ UInt out_len = len;
+ Int lzo_rc = lzo1x_decompress_safe(rx_data, rx_zdata_len,
+ &ce->data[0], (lzo_uint*)&out_len,
+ NULL);
+ Bool ok = lzo_rc == LZO_E_OK && out_len == len;
+ if (!ok) goto server_fail;
+
+ free_Frame(res); res = NULL;
+ goto end_of_else_clause;
+ server_fail:
+ /* The server screwed up somehow. Now what? */
+ if (res) {
+ UChar* reason = NULL;
+ if (parse_Frame_asciiz(res, "FAIL", &reason)) {
+ VG_(umsg)("set_CEnt (reading data from DI server): fail: "
+ "%s\n", reason);
+ } else {
+ VG_(umsg)("set_CEnt (reading data from DI server): fail: "
+ "unknown reason\n");
+ }
+ free_Frame(res); res = NULL;
+ } else {
+ VG_(umsg)("set_CEnt (reading data from DI server): fail: "
+ "server unexpectedly closed the connection\n");
+ }
+ vg_assert(0);
+ end_of_else_clause:
+ {}
+ }
+
+ ce->off = off;
+ ce->used = len;
+ vg_assert(ce->used > 0 && ce->used <= CACHE_ENTRY_SIZE);
+}
+
+__attribute__((noinline))
+static UChar get_slowcase ( DiImage* img, DiOffT off )
+{
+ /* Stay sane .. */
+ vg_assert(off < img->size);
+ vg_assert(img->ces_used <= CACHE_N_ENTRIES);
+ UInt i;
+ /* Start the search at entry 1, since the fast-case function
+ checked slot zero already. */
+ for (i = 1; i < img->ces_used; i++) {
+ vg_assert(img->ces[i]);
+ if (is_in_CEnt(img->ces[i], off))
+ break;
+ }
+ vg_assert(i <= img->ces_used);
+ if (i == img->ces_used) {
+ /* It's not in any entry. Either allocate a new entry or
+ recycle the LRU one. */
+ if (img->ces_used == CACHE_N_ENTRIES) {
+ /* All entries in use. Recycle the (ostensibly) LRU one. */
+ set_CEnt(img, CACHE_N_ENTRIES-1, off);
+ i = CACHE_N_ENTRIES-1;
+ } else {
+ /* Allocate a new one, and fill it in. */
+ UInt entNo = alloc_CEnt(img);
+ set_CEnt(img, entNo, off);
+ i = entNo;
+ }
+ } else {
+ /* We found it at position 'i'. */
+ vg_assert(i > 0);
+ }
+ if (i > 0) {
+ move_CEnt_to_top(img, i);
+ i = 0;
+ }
+ vg_assert(is_in_CEnt(img->ces[i], off));
+ return img->ces[i]->data[ off - img->ces[i]->off ];
+}
+
+// This is called a lot, so do the usual fast/slow split stuff on it. */
+static UChar get ( DiImage* img, DiOffT off )
+{
+ /* Most likely case is, it's in the ces[0] position. */
+ /* ML_(img_from_local_file) requests a read for ces[0] when
+ creating the image. Hence slot zero is always non-NULL, so we
+ can skip this test. */
+ if (LIKELY(/* img->ces[0] != NULL && */
+ is_in_CEnt(img->ces[0], off))) {
+ return img->ces[0]->data[ off - img->ces[0]->off ];
+ }
+ /* Else we'll have to fish around for it. */
+ return get_slowcase(img, off);
+}
+
+/* Create an image from a file in the local filesystem. This is
+ relatively straightforward. */
+DiImage* ML_(img_from_local_file)(const HChar* fullpath)
+{
+ SysRes fd;
+ struct vg_stat stat_buf;
+ DiOffT size;
+
+ fd = VG_(open)(fullpath, VKI_O_RDONLY, 0);
+ if (sr_isError(fd))
+ return NULL;
+
+ if (VG_(fstat)(sr_Res(fd), &stat_buf) != 0) {
+ VG_(close)(sr_Res(fd));
+ return NULL;
+ }
+
+ size = stat_buf.size;
+ if (size == 0 || size == DiOffT_INVALID
+ || /* size is unrepresentable as a SizeT */
+ size != (DiOffT)(SizeT)(size)) {
+ VG_(close)(sr_Res(fd));
+ return NULL;
+ }
+
+ DiImage* img = ML_(dinfo_zalloc)("di.image.ML_iflf.1", sizeof(DiImage));
+ img->source.is_local = True;
+ img->source.fd = sr_Res(fd);
+ img->size = size;
+ img->ces_used = 0;
+ /* img->ces is already zeroed out */
+ vg_assert(img->source.fd >= 0);
+
+ /* Force the zeroth entry to be the first chunk of the file.
+ That's likely to be the first part that's requested anyway, and
+ loading it at this point forcing img->cent[0] to always be
+ non-empty, thereby saving us an is-it-empty check on the fast
+ path in get(). */
+ UInt entNo = alloc_CEnt(img);
+ vg_assert(entNo == 0);
+ set_CEnt(img, 0, 0);
+
+ return img;
+}
+
+
+/* Create an image from a file on a remote debuginfo server. This is
+ more complex. There are lots of ways in which it can fail. */
+DiImage* ML_(img_from_di_server)(const HChar* filename,
+ const HChar* serverAddr)
+{
+ if (filename == NULL || serverAddr == NULL)
+ return NULL;
+
+ /* The filename must be a plain filename -- no slashes at all. */
+ if (VG_(strchr)(filename, '/') != NULL)
+ return NULL;
+
+ /* Try to connect to the server. A side effect of this is to parse
+ and reject, if syntactically invalid, |serverAddr|. Reasons why
+ this could fail:
+ - serverAddr is not of the form d.d.d.d:d or d.d.d.d
+ - attempt to connect to that address:port failed
+ */
+ Int sd = VG_(connect_via_socket)(serverAddr);
+ if (sd < 0)
+ return NULL;
+ if (!set_blocking(sd))
+ return NULL;
+ Int one = 1;
+ Int sr = VG_(setsockopt)(sd, VKI_IPPROTO_TCP, VKI_TCP_NODELAY,
+ &one, sizeof(one));
+ vg_assert(sr == 0);
+
+ /* Ok, we got a connection. Ask it for version string, so as to be
+ reasonably sure we're talking to an instance of
+ auxprogs/valgrind-di-server and not to some other random program
+ that happens to be listening on that port. */
+ Frame* req = mk_Frame_noargs("VERS");
+ Frame* res = do_transaction(sd, req);
+ if (res == NULL)
+ goto fail; // do_transaction failed?!
+ UChar* vstr = NULL;
+ if (!parse_Frame_asciiz(res, "VEOK", &vstr))
+ goto fail; // unexpected response kind, or invalid ID string
+ vg_assert(vstr);
+ if (VG_(strcmp)("Valgrind Debuginfo Server, Version 1",
+ (const HChar*)vstr) != 0)
+ goto fail; // wrong version string
+ free_Frame(req);
+ free_Frame(res);
+ req = NULL;
+ res = NULL;
+
+ /* Server seems plausible. Present it with the name of the file we
+ want and see if it'll give us back a session ID for it. */
+ req = mk_Frame_asciiz("OPEN", filename);
+ res = do_transaction(sd, req);
+ if (res == NULL)
+ goto fail;
+ ULong session_id = 0, size = 0;
+ if (!parse_Frame_le64_le64(res, "OPOK", &session_id, &size))
+ goto fail;
+ free_Frame(req);
+ free_Frame(res);
+ req = NULL;
+ res = NULL;
+
+ /* We have a session ID. We're ready to roll. */
+ DiImage* img = ML_(dinfo_zalloc)("di.image.ML_ifds.1", sizeof(DiImage));
+ img->source.is_local = False;
+ img->source.fd = sd;
+ img->source.session_id = session_id;
+ img->size = size;
+ img->ces_used = 0;
+ /* img->ces is already zeroed out */
+ vg_assert(img->source.fd >= 0);
+
+ /* See comment on equivalent bit in ML_(img_from_local_file) for
+ rationale. */
+ UInt entNo = alloc_CEnt(img);
+ vg_assert(entNo == 0);
+ set_CEnt(img, 0, 0);
+
+ return img;
+
+ fail:
+ if (req) free_Frame(req);
+ if (res) {
+ UChar* reason = NULL;
+ if (parse_Frame_asciiz(res, "FAIL", &reason)) {
+ // HACK: if it's just telling us that the file can't
+ // be opened, don't print it, else we'll get flooded with
+ // such complaints, one for each main object for which there
+ // isn't a debuginfo file on the server.
+ if (0 != VG_(strcmp)((const HChar*)reason, "OPEN: cannot open file"))
+ VG_(umsg)("ML_(img_from_di_server): fail: %s\n", reason);
+ } else {
+ VG_(umsg)("ML_(img_from_di_server): fail: unknown reason\n");
+ }
+ free_Frame(res);
+ }
+ VG_(close)(sd);
+ return NULL;
+}
+
+void ML_(img_done)(DiImage* img)
+{
+ vg_assert(img);
+ if (img->source.is_local) {
+ /* Close the file; nothing else to do. */
+ vg_assert(img->source.session_id == 0);
+ VG_(close)(img->source.fd);
+ } else {
+ /* Close the socket. The server can detect this and will scrub
+ the connection when it happens, so there's no need to tell it
+ explicitly by sending it a "CLOSE" message, or any such. */
+ vg_assert(img->source.session_id != 0);
+ VG_(close)(img->source.fd);
+ }
+
+ /* Free up the cache entries, ultimately |img| itself. */
+ UInt i;
+ vg_assert(img->ces_used <= CACHE_N_ENTRIES);
+ for (i = 0; i < img->ces_used; i++) {
+ ML_(dinfo_free)(img->ces[i]);
+ }
+ /* Take the opportunity to sanity check the rest. */
+ for (i = i; i < img->ces_used; i++) {
+ vg_assert(img->ces[i] == NULL);
+ }
+ ML_(dinfo_free)(img);
+}
+
+DiOffT ML_(img_size)(DiImage* img)
+{
+ vg_assert(img);
+ return img->size;
+}
+
+Bool ML_(img_valid)(DiImage* img, DiOffT offset, SizeT size)
+{
+ vg_assert(img);
+ vg_assert(offset != DiOffT_INVALID);
+ return img->size > 0 && offset + size <= (DiOffT)img->size;
+}
+
+void ML_(img_get)(/*OUT*/void* dst,
+ DiImage* img, DiOffT offset, SizeT size)
+{
+ vg_assert(img);
+ vg_assert(size > 0);
+ vg_assert(ML_(img_valid)(img, offset, size));
+ SizeT i;
+ for (i = 0; i < size; i++) {
+ ((UChar*)dst)[i] = get(img, offset + i);
+ }
+}
+
+SizeT ML_(img_strlen)(DiImage* img, DiOffT off)
+{
+ vg_assert(ML_(img_valid)(img, off, 1));
+ SizeT i = 0;
+ while (get(img, off + i) != 0) i++;
+ return i;
+}
+
+HChar* ML_(img_strdup)(DiImage* img, const HChar* cc, DiOffT offset)
+{
+ vg_assert(ML_(img_valid)(img, offset, 1));
+ SizeT len = ML_(img_strlen)(img, offset);
+ HChar* res = ML_(dinfo_zalloc)(cc, len+1);
+ SizeT i;
+ for (i = 0; i < len; i++) {
+ res[i] = get(img, offset+i);
+ }
+ vg_assert(res[len] == 0);
+ return res;
+}
+
+Int ML_(img_strcmp)(DiImage* img, DiOffT off1, DiOffT off2)
+{
+ vg_assert(ML_(img_valid)(img, off1, 1));
+ vg_assert(ML_(img_valid)(img, off2, 1));
+ while (True) {
+ UChar c1 = get(img, off1);
+ UChar c2 = get(img, off2);
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ off1++; off2++;
+ }
+}
+
+Int ML_(img_strcmp_c)(DiImage* img, DiOffT off1, const HChar* str2)
+{
+ vg_assert(ML_(img_valid)(img, off1, 1));
+ while (True) {
+ UChar c1 = get(img, off1);
+ UChar c2 = *(UChar*)str2;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ off1++; str2++;
+ }
+}
+
+UChar ML_(img_get_UChar)(DiImage* img, DiOffT offset)
+{
+ vg_assert(ML_(img_valid)(img, offset, 1));
+ return get(img, offset);
+}
+
+UShort ML_(img_get_UShort)(DiImage* img, DiOffT offset)
+{
+ UShort r;
+ ML_(img_get)(&r, img, offset, sizeof(r));
+ return r;
+}
+
+UInt ML_(img_get_UInt)(DiImage* img, DiOffT offset)
+{
+ UInt r;
+ ML_(img_get)(&r, img, offset, sizeof(r));
+ return r;
+}
+
+ULong ML_(img_get_ULong)(DiImage* img, DiOffT offset)
+{
+ ULong r;
+ ML_(img_get)(&r, img, offset, sizeof(r));
+ return r;
+}
+
+
+/*
+ * This routine for calculating the CRC for a separate debug file
+ * is GPLed code borrowed from GNU binutils.
+ */
+UInt ML_(img_calc_gnu_debuglink_crc32)(DiImage* img)
+{
+ static const UInt crc32_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+
+ vg_assert(img);
+
+ /* If the image is local, calculate the CRC here directly. If it's
+ remote, forward the request to the server. */
+ if (img->source.is_local) {
+ /* Work through the image in 1 KB chunks. */
+ UInt crc = 0xFFFFFFFF;
+ DiOffT img_szB = ML_(img_size)(img);
+ DiOffT curr_off = 0;
+ while (1) {
+ vg_assert(curr_off >= 0 && curr_off <= img_szB);
+ if (curr_off == img_szB) break;
+ DiOffT avail = img_szB - curr_off;
+ vg_assert(avail > 0 && avail <= img_szB);
+ if (avail > 1024) avail = 1024;
+ UChar buf[1024];
+ ML_(img_get)(buf, img, curr_off, avail);
+ UInt i;
+ for (i = 0; i < (UInt)avail; i++)
+ crc = crc32_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
+ curr_off += avail;
+ }
+ return ~crc & 0xFFFFFFFF;
+ } else {
+ Frame* req = mk_Frame_noargs("CRC3");
+ Frame* res = do_transaction(img->source.fd, req);
+ if (!res) goto remote_crc_fail;
+ ULong crc32 = 0;
+ if (!parse_Frame_le64(res, "CROK", &crc32)) goto remote_crc_fail;
+ if ((crc32 & ~0xFFFFFFFFULL) != 0) goto remote_crc_fail;
+ if (req) free_Frame(req);
+ if (res) free_Frame(res);
+ return (UInt)crc32;
+ remote_crc_fail:
+
+ // XXXX common this up with the READ diagnostic cases
+ if (res) {
+ UChar* reason = NULL;
+ if (parse_Frame_asciiz(res, "FAIL", &reason)) {
+ VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
+ "%s\n", reason);
+ } else {
+ VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
+ "unknown reason\n");
+ }
+ } else {
+ VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
+ "server unexpectedly closed the connection\n");
+ }
+
+ if (req) free_Frame(req);
+ if (res) free_Frame(res);
+ // FIXME: now what?
+ vg_assert(0);
+ }
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+////////////////////////////////////////////////////
+#include "minilzo-inl.c"
+
+/*--------------------------------------------------------------------*/
+/*--- end image.c ---*/
+/*--------------------------------------------------------------------*/
Modified: branches/DISRV/coregrind/m_libcfile.c (+36 -0)
===================================================================
--- branches/DISRV/coregrind/m_libcfile.c 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_libcfile.c 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -1069,6 +1069,42 @@
}
+Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
+ Int optlen)
+{
+# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
+ || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
+ SysRes res;
+ UWord args[5];
+ args[0] = sd;
+ args[1] = level;
+ args[2] = optname;
+ args[3] = (UWord)optval;
+ args[4] = (UWord)optlen;
+ res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
+ return sr_isError(res) ? -1 : sr_Res(res);
+
+# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
+ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
+ SysRes res;
+ res = VG_(do_syscall5)( __NR_setsockopt,
+ (UWord)sd, (UWord)level, (UWord)optname,
+ (UWord)optval, (UWord)optlen );
+ return sr_isError(res) ? -1 : sr_Res(res);
+
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall5)( __NR_setsockopt,
+ (UWord)sd, (UWord)level, (UWord)optname,
+ (UWord)optval, (UWord)optlen );
+ return sr_isError(res) ? -1 : sr_Res(res);
+
+# else
+# error "Unknown platform"
+# endif
+}
+
+
const HChar *VG_(basename)(const HChar *path)
{
static HChar buf[VKI_PATH_MAX];
Modified: branches/DISRV/coregrind/m_debuginfo/readstabs.c (+1 -0)
===================================================================
--- branches/DISRV/coregrind/m_debuginfo/readstabs.c 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/coregrind/m_debuginfo/readstabs.c 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -46,6 +46,7 @@
#include "pub_core_libcprint.h"
#include "pub_core_xarray.h"
#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
+#include "priv_image.h"
#include "priv_tytypes.h"
#include "priv_d3basics.h"
#include "priv_storage.h"
Added: branches/DISRV/auxprogs/valgrind-di-server.c (+1209 -0)
===================================================================
--- branches/DISRV/auxprogs/valgrind-di-server.c 2013-06-07 17:02:32 +01:00 (rev 13422)
+++ branches/DISRV/auxprogs/valgrind-di-server.c 2013-06-07 17:15:48 +01:00 (rev 13423)
@@ -0,0 +1,1209 @@
+
+/*--------------------------------------------------------------------*/
+/*--- A simple debuginfo server for Valgrind. ---*/
+/*--- valgrind-di-server.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2013-2013 Mozilla Foundation
+
+ 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.
+*/
+
+/* Contributed by Julian Seward <js...@ac...> */
+
+/* This code works (just), but it's a mess. Cleanups (also for
+ coregrind/m_debuginfo/image.c):
+
+ * Change the use of pread w/ fd to FILE*, for the file we're
+ serving. Or, at least, put a loop around the pread uses
+ so that it works correctly in the case where pread reads more
+ than zero but less than we asked for.
+
+ * CRC3 request/response: pass session-IDs back and forth and
+ check them
+
+ * Check that all error cases result in a FAIL frame being returned.
+
+ * image.c: don't assert in cases where a FAIL frame is returned;
+ instead cause the debuginfo reading to fail gracefully. (Not
+ sure how to do this)
+
+ * Improve diagnostic printing
+
+ * image.c: do we need to do VG_(write_socket) ? Will it work
+ just to use ordinary VG_(write) ?
+
+ * Both files: document the reason for setting TCP_NODELAY
+
+ * Add a command line argument saying where the served-from
+ directory is -- changes clo_serverpath.
+
+ * Fix up (common up) massive code duplication between client and
+ server.
+
+ * Tidy up the LZO source files; integrate properly in the build
+ system.
+*/
+
+/*---------------------------------------------------------------*/
+
+/* Include valgrind headers before system headers to avoid problems
+ with the system headers #defining things which are used as names
+ of structure members in vki headers. */
+
+#include "pub_core_basics.h"
+#include "pub_core_libcassert.h" // For VG_BUGS_TO
+#include "pub_core_vki.h" // Avoids warnings from
+ // pub_core_libcfile.h
+#include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <netinet/tcp.h>
+
+#include "../coregrind/m_debuginfo/minilzo.h"
+
+/*---------------------------------------------------------------*/
+
+/* The maximum allowable number concurrent connections. */
+#define M_CONNECTIONS 50
+
+static const char* clo_serverpath = ".";
+
+
+/*---------------------------------------------------------------*/
+
+__attribute__ ((noreturn))
+static void panic ( const char* str )
+{
+ fprintf(stderr,
+ "\nvalgrind-di-server: the "
+ "'impossible' happened:\n %s\n", str);
+ fprintf(stderr,
+ "Please report this bug at: %s\n\n", VG_BUGS_TO);
+ exit(1);
+}
+
+__attribute__ ((noreturn))
+static void my_assert_fail ( const char* expr, const char* file, int line, const char* fn )
+{
+ fprintf(stderr,
+ "\nvalgrind-di-server: %s:%d (%s): Assertion '%s' failed.\n",
+ file, line, fn, expr );
+ fprintf(stderr,
+ "Please report this bug at: %s\n\n", VG_BUGS_TO);
+ exit(1);
+}
+
+#undef assert
+
+#define assert(expr) \
+ ((void) ((expr) ? 0 : \
+ (my_assert_fail (VG_STRINGIFY(expr), \
+ __FILE__, __LINE__, \
+ __PRETTY_FUNCTION__), 0)))
+
+
+/*---------------------------------------------------------------*/
+
+/* Holds the state that we need to track, for each connection. */
+typedef
+ struct {
+ // is this entry in use?
+ Bool in_use;
+ // socket descriptor to communicate with client. Initialised as
+ // soon as this entry is created.
+ int conn_sd;
+ // fd for the file that we are connected to. Zero if not
+ // currently connected to any file.
+ int file_fd;
+ ULong file_size;
+ // Session ID
+ ULong session_id;
+ // How many bytes and chunks sent?
+ ULong stats_n_rdok_frames;
+ ULong stats_n_read_unz_bytes; // bytes via READ (uncompressed)
+ ULong stats_n_read_z_bytes; // bytes via READ (compressed)
+ }
+ ConnState;
+
+/* The state itself. */
+static int conn_count = 0;
+static ConnState conn_state[M_CONNECTIONS];
+
+/* Issues unique session ID values. */
+static ULong next_session_id = 1;
+
+
+/*---------------------------------------------------------------*/
+
+// Code that is duplicated with the client :-(
+
+/* The following Adler-32 checksum code is taken from zlib-1.2.3, which
+ has the following copyright notice. */
+/*
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jl...@gz... ma...@al...
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
+*/
+
+/* Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum. An Adler-32 checksum is
+ almost as reliable as a CRC32 but can be computed much faster. */
+static
+UInt adler32( UInt adler, const UChar* buf, UInt len )
+{
+# define BASE 65521UL /* largest prime smaller than 65536 */
+# define NMAX 5552
+ /* NMAX is the largest n such that
+ 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+# define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+# define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+# define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+# define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+# define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+ /* The zlib sources recommend this definition of MOD if the
+ processor cannot do integer division in hardware. */
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+
+ UInt sum2;
+ UInt n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+
+# undef MOD4
+# undef MOD
+# undef DO16
+# undef DO8
+# undef DO4
+# undef DO2
+# undef DO1
+# undef NMAX
+# undef BASE
+}
+
+
+/* A frame. The first 4 bytes of |data| give the kind of the frame,
+ and the rest of it is kind-specific data. */
+typedef struct { UChar* data; SizeT n_data; } Frame;
+
+
+static void write_UInt_le ( /*OUT*/UChar* dst, UInt n )
+{
+ Int i;
+ for (i = 0; i <= 3; i++) {
+ dst[i] = (UChar)(n & 0xFF);
+ n >>= 8;
+ }
+}
+
+static UInt read_UInt_le ( UChar* src )
+{
+ UInt r = 0;
+ Int i;
+ for (i = 3; i >= 0; i--) {
+ r <<= 8;
+ r += (UInt)src[i];
+ }
+ return r;
+}
+
+static void write_ULong_le ( /*OUT*/UChar* dst, ULong n )
+{
+ Int i;
+ for (i = 0; i <= 7; i++) {
+ dst[i] = (UChar)(n & 0xFF);
+ n >>= 8;
+ }
+}
+
+static ULong read_ULong_le ( UChar* src )
+{
+ ULong r = 0;
+ Int i;
+ for (i = 7; i >= 0; i--) {
+ r <<= 8;
+ r += (ULong)src[i];
+ }
+ return r;
+}
+
+static Frame* mk_Frame_asciiz ( const char* tag, const char* str )
+{
+ assert(strlen(tag) == 4);
+ Frame* f = calloc(sizeof(Frame), 1);
+ size_t n_str = strlen(str);
+ f->n_data = 4 + n_str + 1;
+ f->data = calloc(f->n_data, 1);
+ memcpy(&f->data[0], tag, 4);
+ memcpy(&f->data[4], str, n_str);
+ assert(f->data[4 + n_str] == 0);
+ return f;
+}
+
+static Bool parse_Frame_noargs ( Frame* fr, const HChar* tag )
+{
+ assert(strlen(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (memcmp(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data != 4) return False;
+ return True;
+}
+
+static Bool parse_Frame_asciiz ( Frame* fr, const HChar* tag,
+ /*OUT*/UChar** str )
+{
+ assert(strlen(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (memcmp(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data < 5) return False; // else there isn't even enough
+ // space for the terminating zero
+ /* Find the terminating zero and ensure it's right at the end
+ of the data. If not, the frame is malformed. */
+ SizeT i = 4;
+ while (True) {
+ if (i >= fr->n_data) break;
+ if (fr->data[i] == 0) break;
+ i++;
+ }
+ assert(i <= fr->n_data);
+ if (i == fr->n_data-1 && fr->data[i] == 0) {
+ *str = &fr->data[4];
+ return True;
+ } else {
+ return False;
+ }
+}
+
+static Frame* mk_Frame_le64 ( const HChar* tag, ULong n1 )
+{
+ assert(strlen(tag) == 4);
+ Frame* f = calloc(sizeof(Frame), 1);
+ f->n_data = 4 + 1*8;
+ f->data = calloc(f->n_data, 1);
+ memcpy(&f->data[0], tag, 4);
+ write_ULong_le(&f->data[4 + 0*8], n1);
+ return f;
+}
+
+static Frame* mk_Frame_le64_le64 ( const HChar* tag, ULong n1, ULong n2 )
+{
+ assert(strlen(tag) == 4);
+ Frame* f = calloc(sizeof(Frame), 1);
+ f->n_data = 4 + 2*8;
+ f->data = calloc(f->n_data, 1);
+ memcpy(&f->data[0], tag, 4);
+ write_ULong_le(&f->data[4 + 0*8], n1);
+ write_ULong_le(&f->data[4 + 1*8], n2);
+ return f;
+}
+
+static Bool parse_Frame_le64_le64_le64 ( Frame* fr, const HChar* tag,
+ /*OUT*/ULong* n1, /*OUT*/ULong* n2,
+ /*OUT*/ULong* n3 )
+{
+ assert(strlen(tag) == 4);
+ if (!fr || !fr->data) return False;
+ if (fr->n_data < 4) return False;
+ if (memcmp(&fr->data[0], tag, 4) != 0) return False;
+ if (fr->n_data != 4 + 3*8) return False;
+ *n1 = read_ULong_le(&fr->data[4 + 0*8]);
+ *n2 = read_ULong_le(&fr->data[4 + 1*8]);
+ *n3 = read_ULong_le(&fr->data[4 + 2*8]);
+ return True;
+}
+
+static Frame* mk_Frame_le64_le64_le64_bytes (
+ const HChar* tag,
+ ULong n1, ULong n2, ULong n3, ULong n_data,
+ /*OUT*/UChar** data )
+{
+ assert(strlen(tag) == 4);
+ Frame* f = calloc(sizeof(Frame), 1);
+ f->n_data = 4 + 3*8 + n_data;
+ f->data = calloc(f->n_data, 1);
+ memcpy(&f->data[0], tag, 4);
+ write_ULong_le(&f->data[4 + 0*8], n1);
+ write_ULong_le(&f->data[4 + 1*8], n2);
+ write_ULong_le(&f->data[4 + 2*8], n3);
+ *data = &f->data[4 + 3*8];
+ return f;
+}
+
+static void free_Frame ( Frame* fr )
+{
+ assert(fr && fr->data);
+ free(fr->data);
+ free(fr);
+}
+
+
+static void set_blocking ( int sd )
+{
+ int res;
+ res = fcntl(sd, F_GETFL);
+ res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
+ if (res != 0) {
+ perror("fcntl failed");
+ panic("set_blocking");
+ }
+}
+
+
+#if 0
+static void set_nonblocking ( int sd )
+{
+ int res;
+ res = fcntl(sd, F_GETFL);
+ res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
+ if (res != 0) {
+ perror("fcntl failed");
+ panic("set_nonblocking");
+ }
+}
+#endif
+
+
+/* Tries to read 'len' bytes from fd, blocking if necessary. Assumes
+ fd has been set in blocking mode. If it returns with the number of
+ bytes read < len, it means that either fd was closed, or there was
+ an error on it. */
+static SizeT...
[truncated message content] |