1436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* -*- mode: C; c-basic-offset: 3; -*- */
2436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
4436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--- An abstraction that provides a file-reading mechanism.       ---*/
5436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*---                                                      image.c ---*/
6436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
7436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*
9436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This file is part of Valgrind, a dynamic binary instrumentation
10436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   framework.
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
12436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2013-2013 Mozilla Foundation
13436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
14436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This program is free software; you can redistribute it and/or
15436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   modify it under the terms of the GNU General Public License as
16436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   published by the Free Software Foundation; either version 2 of the
17436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   License, or (at your option) any later version.
18436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
19436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This program is distributed in the hope that it will be useful, but
20436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   WITHOUT ANY WARRANTY; without even the implied warranty of
21436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   General Public License for more details.
23436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
24436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   You should have received a copy of the GNU General Public License
25436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   along with this program; if not, write to the Free Software
26436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   02111-1307, USA.
28436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
29436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   The GNU General Public License is contained in the file COPYING.
30436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov*/
31436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
32436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Contributed by Julian Seward <jseward@acm.org> */
33436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
34436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* See the corresponding auxprogs/valgrind-di-server.c for a list of
35436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   cleanups for this file and itself. */
36436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
37436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_basics.h"
38436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_vki.h"
39436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcbase.h"
40436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcassert.h"
41436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcprint.h"
42436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcproc.h"     /* VG_(read_millisecond_timer) */
43436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcfile.h"
44436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "priv_misc.h"             /* dinfo_zalloc/free/strdup */
45436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "priv_image.h"            /* self */
46436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
47436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "minilzo.h"
48436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
49436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define CACHE_ENTRY_SIZE_BITS (12+1)
50436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define CACHE_N_ENTRIES       32
51436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
52436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define CACHE_ENTRY_SIZE      (1 << CACHE_ENTRY_SIZE_BITS)
53436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
54436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* An entry in the cache. */
55436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovtypedef
56436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   struct {
57436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DiOffT off; // file offset for data[0]
58436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      SizeT  used; // 1 .. sizeof(data), or 0 to denote not-in-use
59436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar  data[CACHE_ENTRY_SIZE];
60436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
61436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CEnt;
62436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
63436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Source for files */
64436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovtypedef
65436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   struct {
66436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // True: img is of local file.  False: img is from a server.
67436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Bool  is_local;
68436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // The fd for the local file, or sd for a remote server.
69436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int   fd;
70436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // The name.  In ML_(dinfo_zalloc)'d space.  Used only for printing
71436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // error messages; hence it doesn't really matter what this contains.
72436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar* name;
73436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // The rest of these fields are only valid when using remote files
74436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // (that is, using a debuginfo server; hence when is_local==False)
75436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // Session ID allocated to us by the server.  Cannot be zero.
76436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ULong session_id;
77436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
78436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Source;
79436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
80436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstruct _DiImage {
81436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // The source -- how to get hold of the file we are reading
82436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Source source;
83436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // Total size of the image.
84436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT size;
85436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // The number of entries used.  0 .. CACHE_N_ENTRIES
86436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt  ces_used;
87436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // Pointers to the entries.  ces[0 .. ces_used-1] are non-NULL.
88436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // ces[ces_used .. CACHE_N_ENTRIES-1] are NULL.
89436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // The non-NULL entries may be arranged arbitrarily.  We expect to use
90436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // a pseudo-LRU scheme though.
91436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CEnt* ces[CACHE_N_ENTRIES];
92436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov};
93436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
94436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* A frame.  The first 4 bytes of |data| give the kind of the frame,
95436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   and the rest of it is kind-specific data. */
96436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovtypedef  struct { UChar* data; SizeT n_data; }  Frame;
97436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
98436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void write_UInt_le ( /*OUT*/UChar* dst, UInt n )
99436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
100436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int i;
101436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i <= 3; i++) {
102436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      dst[i] = (UChar)(n & 0xFF);
103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      n >>= 8;
104436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
105436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
106436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
107436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UInt read_UInt_le ( UChar* src )
108436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
109436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt r = 0;
110436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int i;
111436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 3; i >= 0; i--) {
112436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      r <<= 8;
113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      r += (UInt)src[i];
114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return r;
116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void write_ULong_le ( /*OUT*/UChar* dst, ULong n )
119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
120436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int i;
121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i <= 7; i++) {
122436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      dst[i] = (UChar)(n & 0xFF);
123436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      n >>= 8;
124436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
125436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
126436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
127436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic ULong read_ULong_le ( UChar* src )
128436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong r = 0;
130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int i;
131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 7; i >= 0; i--) {
132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      r <<= 8;
133436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      r += (ULong)src[i];
134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
135436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return r;
136436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
137436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Set |sd| to be blocking.  Returns True on success. */
140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool set_blocking ( int sd )
141436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
142436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int res;
143436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res = VG_(fcntl)(sd, VKI_F_GETFL, 0/*ignored*/);
144436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (res != -1)
145436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      res = VG_(fcntl)(sd, VKI_F_SETFL, res & ~VKI_O_NONBLOCK);
146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return (res != -1);
147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
149436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Tries to read 'len' bytes from fd, blocking if necessary.  Assumes
150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   fd has been set in blocking mode.  If it returns with the number of
151436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   bytes read < len, it means that either fd was closed, or there was
152436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   an error on it. */
153436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int my_read ( Int fd, UChar* buf, Int len )
154436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
155436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int nRead = 0;
156436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (1) {
157436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (nRead == len) return nRead;
158436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(nRead < len);
159436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int nNeeded = len - nRead;
160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(nNeeded > 0);
161436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int n = VG_(read)(fd, &buf[nRead], nNeeded);
162436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (n <= 0) return nRead; /* error or EOF */
163436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      nRead += n;
164436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
165436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
166436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
167436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Tries to write 'len' bytes to fd, blocking if necessary.  Assumes
168436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   fd has been set in blocking mode.  If it returns with the number of
169436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   bytes written < len, it means that either fd was closed, or there was
170436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   an error on it. */
171436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int my_write ( Int fd, UChar* buf, Int len )
172436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
173436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int nWritten = 0;
174436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (1) {
175436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (nWritten == len) return nWritten;
176436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(nWritten < len);
177436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int nStillToDo = len - nWritten;
178436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(nStillToDo > 0);
179436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int n = VG_(write_socket)(fd, &buf[nWritten], nStillToDo);
180436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (n < 0) return nWritten; /* error or EOF */
181436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      nWritten += n;
182436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
183436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
184436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
185436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* If we lost communication with the remote server, just give up.
186436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Recovering is too difficult. */
187436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void give_up__comms_lost(void)
188436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
189436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("\n");
190436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)(
191436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      "Valgrind: debuginfo reader: Lost communication with the remote\n");
192436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)(
193436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      "Valgrind: debuginfo server.  I can't recover.  Giving up.  Sorry.\n");
194436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("\n");
195436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(exit)(1);
196436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /*NOTREACHED*/
197436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
198436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
199436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void give_up__image_overrun(void)
200436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
201436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("\n");
202436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)(
203436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      "Valgrind: debuginfo reader: Possibly corrupted debuginfo file.\n");
204436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)(
205436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      "Valgrind: I can't recover.  Giving up.  Sorry.\n");
206436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("\n");
207436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(exit)(1);
208436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /*NOTREACHED*/
209436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
211436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* "Do" a transaction: that is, send the given frame to the server and
212436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return the frame it sends back.  Caller owns the resulting frame
213436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   and must free it.  A NULL return means the transaction failed for
214436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   some reason. */
215436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Frame* do_transaction ( Int sd, Frame* req )
216436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
217436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0) VG_(printf)("CLIENT: send %c%c%c%c\n",
218436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      req->data[0], req->data[1], req->data[2], req->data[3]);
219436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
220436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* What goes on the wire is:
221436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         adler(le32) n_data(le32) data[0 .. n_data-1]
222436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      where the checksum covers n_data as well as data[].
223436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   */
224436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* The initial Adler-32 value */
225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt adler = VG_(adler32)(0, NULL, 0);
226436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
227436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Fold in the length field, encoded as le32. */
228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UChar wr_first8[8];
229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   write_UInt_le(&wr_first8[4], req->n_data);
230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   adler = VG_(adler32)(adler, &wr_first8[4], 4);
231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Fold in the data values */
232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   adler = VG_(adler32)(adler, req->data, req->n_data);
233436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   write_UInt_le(&wr_first8[0], adler);
234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
235436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int r = my_write(sd, &wr_first8[0], 8);
236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (r != 8) return NULL;
237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(req->n_data >= 4); // else ill formed -- no KIND field
238436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   r = my_write(sd, req->data, req->n_data);
239436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (r != req->n_data) return NULL;
240436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
241436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* So, the request is sent.  Now get a request of the same format
242436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      out of the channel. */
243436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UChar rd_first8[8];  // adler32; length32
244436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   r = my_read(sd, &rd_first8[0], 8);
245436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (r != 8) return NULL;
246436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt rd_adler = read_UInt_le(&rd_first8[0]);
247436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt rd_len   = read_UInt_le(&rd_first8[4]);
248436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Allocate a Frame to hold the result data, and read into it. */
249436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // Reject obviously-insane length fields.
250436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (rd_len < 4 || rd_len > 4*1024*1024) return NULL;
251436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* res = ML_(dinfo_zalloc)("di.do_transaction.1", sizeof(Frame));
252436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res->n_data = rd_len;
253436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res->data = ML_(dinfo_zalloc)("di.do_transaction.2", rd_len);
254436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   r = my_read(sd, res->data, res->n_data);
255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (r != rd_len) return NULL;
256436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
257436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0) VG_(printf)("CLIENT: recv %c%c%c%c\n",
258436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      res->data[0], res->data[1], res->data[2], res->data[3]);
259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
260436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Compute the checksum for the received data, and check it. */
261436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   adler = VG_(adler32)(0, NULL, 0); // initial value
262436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   adler = VG_(adler32)(adler, &rd_first8[4], 4);
263436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (res->n_data > 0)
264436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      adler = VG_(adler32)(adler, res->data, res->n_data);
265436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
266436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (adler/*computed*/ != rd_adler/*expected*/) return NULL;
267436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return res;
268436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
269436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
270436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void free_Frame ( Frame* fr )
271436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
272436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(fr && fr->data);
273436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(dinfo_free)(fr->data);
274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(dinfo_free)(fr);
275436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
277436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Frame* mk_Frame_noargs ( const HChar* tag )
278436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
279436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
280436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* f = ML_(dinfo_zalloc)("di.mFn.1", sizeof(Frame));
281436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->n_data = 4;
282436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->data = ML_(dinfo_zalloc)("di.mFn.2", f->n_data);
283436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memcpy)(&f->data[0], tag, 4);
284436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return f;
285436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
286436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
287436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Frame* mk_Frame_le64_le64_le64 ( const HChar* tag,
288436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                        ULong n1, ULong n2, ULong n3 )
289436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
291436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* f = ML_(dinfo_zalloc)("di.mFlll.1", sizeof(Frame));
292436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->n_data = 4 + 3*8;
293436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->data = ML_(dinfo_zalloc)("di.mFlll.2", f->n_data);
294436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memcpy)(&f->data[0], tag, 4);
295436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   write_ULong_le(&f->data[4 + 0*8], n1);
296436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   write_ULong_le(&f->data[4 + 1*8], n2);
297436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   write_ULong_le(&f->data[4 + 2*8], n3);
298436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return f;
299436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
300436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
301436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Frame* mk_Frame_asciiz ( const HChar* tag, const HChar* str )
302436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
303436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
304436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* f = ML_(dinfo_zalloc)("di.mFa.1", sizeof(Frame));
305436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT n_str = VG_(strlen)(str);
306436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->n_data = 4 + n_str + 1;
307436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   f->data = ML_(dinfo_zalloc)("di.mFa.2", f->n_data);
308436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memcpy)(&f->data[0], tag, 4);
309436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memcpy)(&f->data[4], str, n_str);
310436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(f->data[4 + n_str] == 0);
311436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return f;
312436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
314436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool parse_Frame_le64 ( Frame* fr, const HChar* tag, /*OUT*/ULong* n1 )
315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
316436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
317436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!fr || !fr->data) return False;
318436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 4) return False;
319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
320436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data != 4 + 1*8) return False;
321436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n1 = read_ULong_le(&fr->data[4 + 0*8]);
322436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return True;
323436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
324436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
325436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool parse_Frame_le64_le64 ( Frame* fr, const HChar* tag,
326436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    /*OUT*/ULong* n1, /*OUT*/ULong* n2 )
327436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
328436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
329436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!fr || !fr->data) return False;
330436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 4) return False;
331436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
332436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data != 4 + 2*8) return False;
333436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n1 = read_ULong_le(&fr->data[4 + 0*8]);
334436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n2 = read_ULong_le(&fr->data[4 + 1*8]);
335436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return True;
336436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
337436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
338436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool parse_Frame_asciiz ( Frame* fr, const HChar* tag,
339436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 /*OUT*/UChar** str )
340436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
341436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
342436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!fr || !fr->data) return False;
343436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 4) return False;
344436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
345436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 5) return False; // else there isn't even enough
346436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                     // space for the terminating zero
347436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Find the terminating zero and ensure it's right at the end
348436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      of the data.  If not, the frame is malformed. */
349436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT i = 4;
350436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (True) {
351436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (i >= fr->n_data) break;
352436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (fr->data[i] == 0) break;
353436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      i++;
354436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
355436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(i <= fr->n_data);
356436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (i == fr->n_data-1 && fr->data[i] == 0) {
357436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *str = &fr->data[4];
358436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return True;
359436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
360436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return False;
361436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
362436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
363436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
364436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool parse_Frame_le64_le64_le64_bytes (
365436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               Frame* fr, const HChar* tag,
366436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               /*OUT*/ULong* n1, /*OUT*/ULong* n2, /*OUT*/ULong* n3,
367436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               /*OUT*/UChar** data, /*OUT*/ULong* n_data
368436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            )
369436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
370436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(strlen)(tag) == 4);
371436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!fr || !fr->data) return False;
372436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 4) return False;
373436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(memcmp)(&fr->data[0], tag, 4) != 0) return False;
374436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (fr->n_data < 4 + 3*8) return False;
375436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n1 = read_ULong_le(&fr->data[4 + 0*8]);
376436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n2 = read_ULong_le(&fr->data[4 + 1*8]);
377436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n3 = read_ULong_le(&fr->data[4 + 2*8]);
378436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *data   = &fr->data[4 + 3*8];
379436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   *n_data = fr->n_data - (4 + 3*8);
380436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(fr->n_data >= 4 + 3*8);
381436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return True;
382436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
383436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
384436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic DiOffT block_round_down ( DiOffT i )
385436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
386436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return i & ((DiOffT)~(CACHE_ENTRY_SIZE-1));
387436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
388436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
389436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Is this offset inside this CEnt? */
390436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic inline Bool is_in_CEnt ( CEnt* cent, DiOffT off )
391436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
392436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* This assertion is checked by set_CEnt, so checking it here has
393436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      no benefit, whereas skipping it does remove it from the hottest
394436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      path. */
395436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* vg_assert(cent->used > 0 && cent->used <= CACHE_ENTRY_SIZE); */
396436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return cent->off <= off && off < cent->off + cent->used;
397436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
398436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
399436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Allocate a new CEnt, connect it to |img|, and return its index. */
400436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UInt alloc_CEnt ( DiImage* img )
401436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
402436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
403436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces_used < CACHE_N_ENTRIES);
404436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt entNo = img->ces_used;
405436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->ces_used++;
406436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces[entNo] == NULL);
407436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->ces[entNo] = ML_(dinfo_zalloc)("di.alloc_CEnt.1", sizeof(CEnt));
408436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return entNo;
409436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
410436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
411436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Move the given entry to the top and slide those above it down by 1,
412436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   to make space. */
413436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void move_CEnt_to_top ( DiImage* img, UInt entNo )
414436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
415436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces_used <= CACHE_N_ENTRIES);
416436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(entNo > 0 && entNo < img->ces_used);
417436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CEnt* tmp = img->ces[entNo];
418436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (entNo > 0) {
419436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      img->ces[entNo] = img->ces[entNo-1];
420436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      entNo--;
421436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
422436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->ces[0] = tmp;
423436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
424436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
425436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Set the given entry so that it has a chunk of the file containing
426436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   the given offset.  It is this function that brings data into the
427436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   cache, either by reading the local file or pulling it from the
428436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   remote server. */
429436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void set_CEnt ( DiImage* img, UInt entNo, DiOffT off )
430436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
431436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT len;
432436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   DiOffT off_orig = off;
433436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
434436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces_used <= CACHE_N_ENTRIES);
435436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(entNo >= 0 && entNo < img->ces_used);
436436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(off < img->size);
437436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces[entNo] != NULL);
438436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Compute [off, +len) as the slice we are going to read. */
439436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   off = block_round_down(off);
440436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   len = img->size - off;
441436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (len > CACHE_ENTRY_SIZE) len = CACHE_ENTRY_SIZE;
442436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* It is conceivable that the 'len > 0' bit could fail if we make
443436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      an image with a zero sized file.  But then no 'get' request on
444436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      that image would be valid. */
445436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(len > 0 && len <= CACHE_ENTRY_SIZE);
446436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(off + len <= img->size);
447436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(off <= off_orig && off_orig < off+len);
448436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* So, read  off .. off+len-1  into the entry. */
449436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CEnt* ce = img->ces[entNo];
450436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
451436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0) {
452436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      static UInt t_last = 0;
453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      static ULong nread = 0;
454436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UInt now = VG_(read_millisecond_timer)();
455436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UInt delay = now - t_last;
456436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      t_last = now;
457436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      nread += len;
458436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(printf)("XXXXXXXX (tot %lld) read %ld offset %lld  %u\n",
459436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  nread, len, off, delay);
460436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
461436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
462436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (img->source.is_local) {
463436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // Simple: just read it
464436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      SysRes sr = VG_(pread)(img->source.fd, &ce->data[0], (Int)len, off);
465436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(!sr_isError(sr));
466436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
467436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // Not so simple: poke the server
468436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(img->source.session_id > 0);
469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Frame* req
470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         = mk_Frame_le64_le64_le64("READ", img->source.session_id, off, len);
471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Frame* res = do_transaction(img->source.fd, req);
472436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      free_Frame(req); req = NULL;
473436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!res) goto server_fail;
474436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ULong  rx_session_id = 0, rx_off = 0, rx_len = 0, rx_zdata_len = 0;
475436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar* rx_data = NULL;
476436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Pretty confusing.  rx_sessionid, rx_off and rx_len are copies
477436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         of the values that we requested in the READ frame just above,
478436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         so we can be sure that the server is responding to the right
479436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         request.  It just copies them from the request into the
480436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         response.  rx_data is the actual data, and rx_zdata_len is
481436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         its compressed length.  Hence rx_len must equal len, but
482436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         rx_zdata_len can be different -- smaller, hopefully.. */
483436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!parse_Frame_le64_le64_le64_bytes
484436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          (res, "RDOK", &rx_session_id, &rx_off,
485436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        &rx_len, &rx_data, &rx_zdata_len))
486436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto server_fail;
487436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (rx_session_id != img->source.session_id
488436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          || rx_off != off || rx_len != len || rx_data == NULL)
489436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto server_fail;
490436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
491436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      //VG_(memcpy)(&ce->data[0], rx_data, len);
492436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // Decompress into the destination buffer
493436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // Tell the lib the max number of output bytes it can write.
494436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // After the call, this holds the number of bytes actually written,
495436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // and it's an error if it is different.
496436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UInt out_len = len;
497436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int lzo_rc = lzo1x_decompress_safe(rx_data, rx_zdata_len,
498436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         &ce->data[0], (lzo_uint*)&out_len,
499436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         NULL);
500436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Bool ok = lzo_rc == LZO_E_OK && out_len == len;
501436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!ok) goto server_fail;
502436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
503436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      free_Frame(res); res = NULL;
504436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto end_of_else_clause;
505436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     server_fail:
506436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* The server screwed up somehow.  Now what? */
507436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (res) {
508436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         UChar* reason = NULL;
509436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (parse_Frame_asciiz(res, "FAIL", &reason)) {
510436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(umsg)("set_CEnt (reading data from DI server): fail: "
511436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "%s\n", reason);
512436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         } else {
513436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(umsg)("set_CEnt (reading data from DI server): fail: "
514436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "unknown reason\n");
515436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
516436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         free_Frame(res); res = NULL;
517436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
518436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(umsg)("set_CEnt (reading data from DI server): fail: "
519436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   "server unexpectedly closed the connection\n");
520436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
521436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      give_up__comms_lost();
522436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* NOTREACHED */
523436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(0);
524436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     end_of_else_clause:
525436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      {}
526436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
527436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
528436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ce->off  = off;
529436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ce->used = len;
530436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(ce->used > 0 && ce->used <= CACHE_ENTRY_SIZE);
531436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
532436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
533436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov__attribute__((noinline))
534436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UChar get_slowcase ( DiImage* img, DiOffT off )
535436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
536436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Stay sane .. */
537436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(off < img->size);
538436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces_used <= CACHE_N_ENTRIES);
539436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt i;
540436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Start the search at entry 1, since the fast-case function
541436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      checked slot zero already. */
542436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 1; i < img->ces_used; i++) {
543436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(img->ces[i]);
544436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (is_in_CEnt(img->ces[i], off))
545436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
546436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
547436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(i <= img->ces_used);
548436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (i == img->ces_used) {
549436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* It's not in any entry.  Either allocate a new entry or
550436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         recycle the LRU one. */
551436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (img->ces_used == CACHE_N_ENTRIES) {
552436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* All entries in use.  Recycle the (ostensibly) LRU one. */
553436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         set_CEnt(img, CACHE_N_ENTRIES-1, off);
554436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         i = CACHE_N_ENTRIES-1;
555436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
556436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* Allocate a new one, and fill it in. */
557436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         UInt entNo = alloc_CEnt(img);
558436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         set_CEnt(img, entNo, off);
559436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         i = entNo;
560436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
561436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
562436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* We found it at position 'i'. */
563436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(i > 0);
564436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
565436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (i > 0) {
566436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      move_CEnt_to_top(img, i);
567436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      i = 0;
568436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
569436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(is_in_CEnt(img->ces[i], off));
570436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return img->ces[i]->data[ off - img->ces[i]->off ];
571436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
572436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
573436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// This is called a lot, so do the usual fast/slow split stuff on it. */
574436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UChar get ( DiImage* img, DiOffT off )
575436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
576436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Most likely case is, it's in the ces[0] position. */
577436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ML_(img_from_local_file) requests a read for ces[0] when
578436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      creating the image.  Hence slot zero is always non-NULL, so we
579436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      can skip this test. */
580436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (LIKELY(/* img->ces[0] != NULL && */
581436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              is_in_CEnt(img->ces[0], off))) {
582436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return img->ces[0]->data[ off - img->ces[0]->off ];
583436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
584436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Else we'll have to fish around for it. */
585436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return get_slowcase(img, off);
586436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
587436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
588436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Create an image from a file in the local filesystem.  This is
589436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   relatively straightforward. */
590436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovDiImage* ML_(img_from_local_file)(const HChar* fullpath)
591436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
592436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SysRes         fd;
593436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   struct vg_stat stat_buf;
594436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   DiOffT         size;
595436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
596436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   fd = VG_(open)(fullpath, VKI_O_RDONLY, 0);
597436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sr_isError(fd))
598436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
599436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
600436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(fstat)(sr_Res(fd), &stat_buf) != 0) {
601436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(close)(sr_Res(fd));
602436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
603436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
604436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
605436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   size = stat_buf.size;
606436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (size == 0 || size == DiOffT_INVALID
607436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       || /* size is unrepresentable as a SizeT */
608436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          size != (DiOffT)(SizeT)(size)) {
609436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(close)(sr_Res(fd));
610436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
611436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
612436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
613436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   DiImage* img = ML_(dinfo_zalloc)("di.image.ML_iflf.1", sizeof(DiImage));
614436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.is_local = True;
615436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.fd       = sr_Res(fd);
616436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->size            = size;
617436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->ces_used        = 0;
618436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.name     = ML_(dinfo_strdup)("di.image.ML_iflf.2", fullpath);
619436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* img->ces is already zeroed out */
620436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->source.fd >= 0);
621436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
622436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Force the zeroth entry to be the first chunk of the file.
623436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      That's likely to be the first part that's requested anyway, and
624436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      loading it at this point forcing img->cent[0] to always be
625436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      non-empty, thereby saving us an is-it-empty check on the fast
626436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      path in get(). */
627436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt entNo = alloc_CEnt(img);
628436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(entNo == 0);
629436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   set_CEnt(img, 0, 0);
630436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
631436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return img;
632436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
633436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
634436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
635436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Create an image from a file on a remote debuginfo server.  This is
636436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   more complex.  There are lots of ways in which it can fail. */
637436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovDiImage* ML_(img_from_di_server)(const HChar* filename,
638436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 const HChar* serverAddr)
639436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
640436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (filename == NULL || serverAddr == NULL)
641436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
642436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
643436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* The filename must be a plain filename -- no slashes at all. */
644436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(strchr)(filename, '/') != NULL)
645436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
646436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
647436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Try to connect to the server.  A side effect of this is to parse
648436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      and reject, if syntactically invalid, |serverAddr|.  Reasons why
649436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      this could fail:
650436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      - serverAddr is not of the form d.d.d.d:d or d.d.d.d
651436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      - attempt to connect to that address:port failed
652436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   */
653436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int sd = VG_(connect_via_socket)(serverAddr);
654436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sd < 0)
655436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
656436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!set_blocking(sd))
657436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return NULL;
658436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int one = 1;
659436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int sr = VG_(setsockopt)(sd, VKI_IPPROTO_TCP, VKI_TCP_NODELAY,
660436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            &one, sizeof(one));
661436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(sr == 0);
662436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
663436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Ok, we got a connection.  Ask it for version string, so as to be
664436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      reasonably sure we're talking to an instance of
665436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      auxprogs/valgrind-di-server and not to some other random program
666436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      that happens to be listening on that port. */
667436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* req = mk_Frame_noargs("VERS");
668436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Frame* res = do_transaction(sd, req);
669436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (res == NULL)
670436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto fail; // do_transaction failed?!
671436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UChar* vstr = NULL;
672436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!parse_Frame_asciiz(res, "VEOK", &vstr))
673436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto fail; // unexpected response kind, or invalid ID string
674436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(vstr);
675436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(strcmp)("Valgrind Debuginfo Server, Version 1",
676436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   (const HChar*)vstr) != 0)
677436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto fail; // wrong version string
678436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free_Frame(req);
679436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free_Frame(res);
680436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   req = NULL;
681436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res = NULL;
682436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
683436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Server seems plausible.  Present it with the name of the file we
684436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      want and see if it'll give us back a session ID for it. */
685436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   req = mk_Frame_asciiz("OPEN", filename);
686436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res = do_transaction(sd, req);
687436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (res == NULL)
688436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto fail;
689436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong session_id = 0, size = 0;
690436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!parse_Frame_le64_le64(res, "OPOK", &session_id, &size))
691436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto fail;
692436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free_Frame(req);
693436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free_Frame(res);
694436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   req = NULL;
695436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   res = NULL;
696436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
697436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* We have a session ID.  We're ready to roll. */
698436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   DiImage* img = ML_(dinfo_zalloc)("di.image.ML_ifds.1", sizeof(DiImage));
699436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.is_local   = False;
700436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.fd         = sd;
701436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.session_id = session_id;
702436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->size              = size;
703436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->ces_used          = 0;
704436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   img->source.name       = ML_(dinfo_zalloc)("di.image.ML_ifds.2",
705436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                              20 + VG_(strlen)(filename)
706436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                                 + VG_(strlen)(serverAddr));
707436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(sprintf)(img->source.name, "%s at %s", filename, serverAddr);
708436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
709436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* img->ces is already zeroed out */
710436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->source.fd >= 0);
711436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
712436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* See comment on equivalent bit in ML_(img_from_local_file) for
713436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      rationale. */
714436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt entNo = alloc_CEnt(img);
715436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(entNo == 0);
716436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   set_CEnt(img, 0, 0);
717436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
718436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return img;
719436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
720436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov  fail:
721436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (req) free_Frame(req);
722436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (res) {
723436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar* reason = NULL;
724436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (parse_Frame_asciiz(res, "FAIL", &reason)) {
725436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         // HACK: if it's just telling us that the file can't
726436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         // be opened, don't print it, else we'll get flooded with
727436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         // such complaints, one for each main object for which there
728436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         // isn't a debuginfo file on the server.
729436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (0 != VG_(strcmp)((const HChar*)reason, "OPEN: cannot open file"))
730436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(umsg)("ML_(img_from_di_server): fail: %s\n", reason);
731436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
732436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(umsg)("ML_(img_from_di_server): fail: unknown reason\n");
733436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
734436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      free_Frame(res);
735436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
736436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(close)(sd);
737436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return NULL;
738436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
739436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
740436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid ML_(img_done)(DiImage* img)
741436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
742436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
743436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (img->source.is_local) {
744436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Close the file; nothing else to do. */
745436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(img->source.session_id == 0);
746436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(close)(img->source.fd);
747436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
748436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Close the socket.  The server can detect this and will scrub
749436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         the connection when it happens, so there's no need to tell it
750436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         explicitly by sending it a "CLOSE" message, or any such. */
751436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(img->source.session_id != 0);
752436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(close)(img->source.fd);
753436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
754436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
755436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Free up the cache entries, ultimately |img| itself. */
756436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt i;
757436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img->ces_used <= CACHE_N_ENTRIES);
758436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < img->ces_used; i++) {
759436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ML_(dinfo_free)(img->ces[i]);
760436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
761436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Take the opportunity to sanity check the rest. */
762436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = i; i < img->ces_used; i++) {
763436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(img->ces[i] == NULL);
764436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
765436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(dinfo_free)(img->source.name);
766436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(dinfo_free)(img);
767436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
768436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
769436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovDiOffT ML_(img_size)(DiImage* img)
770436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
771436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
772436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return img->size;
773436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
774436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
775436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovinline Bool ML_(img_valid)(DiImage* img, DiOffT offset, SizeT size)
776436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
777436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
778436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(offset != DiOffT_INVALID);
779436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return img->size > 0 && offset + size <= (DiOffT)img->size;
780436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
781436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
782436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Check the given range is valid, and if not, shut down the system.
783436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   An invalid range would imply that we're trying to read outside the
784436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   image, which normally means the image is corrupted somehow, or the
785436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   caller is buggy.  Recovering is too complex, and we have
786436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   probably-corrupt debuginfo, so just give up. */
787436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void ensure_valid(DiImage* img, DiOffT offset, SizeT size,
788436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         const HChar* caller)
789436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
790436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (LIKELY(ML_(img_valid)(img, offset, size)))
791436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return;
792436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("Valgrind: debuginfo reader: ensure_valid failed:\n");
793436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("Valgrind:   during call to %s\n", caller);
794436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("Valgrind:   request for range [%llu, +%llu) exceeds\n",
795436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             (ULong)offset, (ULong)size);
796436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("Valgrind:   valid image size of %llu for image:\n",
797436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             (ULong)img->size);
798436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(umsg)("Valgrind:   \"%s\"\n", img->source.name);
799436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   give_up__image_overrun();
800436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
801436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
802436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
803436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid ML_(img_get)(/*OUT*/void* dst,
804436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  DiImage* img, DiOffT offset, SizeT size)
805436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
806436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
807436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(size > 0);
808436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, offset, size, "ML_(img_get)");
809436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT i;
810436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < size; i++) {
811436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ((UChar*)dst)[i] = get(img, offset + i);
812436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
813436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
814436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
815436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovSizeT ML_(img_get_some)(/*OUT*/void* dst,
816436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        DiImage* img, DiOffT offset, SizeT size)
817436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
818436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
819436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(size > 0);
820436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, offset, size, "ML_(img_get_some)");
821436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UChar* dstU = (UChar*)dst;
822436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Use |get| in the normal way to get the first byte of the range.
823436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      This guarantees to put the cache entry containing |offset| in
824436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      position zero. */
825436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   dstU[0] = get(img, offset);
826436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Now just read as many bytes as we can (or need) directly out of
827436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      entry zero, without bothering to call |get| each time. */
828436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CEnt* ce = img->ces[0];
829436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(ce && ce->used >= 1);
830436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(is_in_CEnt(ce, offset));
831436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT nToCopy = size - 1;
832436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT nAvail  = (SizeT)(ce->used - (offset + 1 - ce->off));
833436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(nAvail >= 0 && nAvail <= ce->used-1);
834436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (nAvail < nToCopy) nToCopy = nAvail;
835436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memcpy)(&dstU[1], &ce->data[offset + 1 - ce->off], nToCopy);
836436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return nToCopy + 1;
837436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
838436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
839436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
840436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovSizeT ML_(img_strlen)(DiImage* img, DiOffT off)
841436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
842436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, off, 1, "ML_(img_strlen)");
843436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT i = 0;
844436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (get(img, off + i) != 0) i++;
845436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return i;
846436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
847436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
848436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovHChar* ML_(img_strdup)(DiImage* img, const HChar* cc, DiOffT offset)
849436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
850436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, offset, 1, "ML_(img_strdup)");
851436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT  len = ML_(img_strlen)(img, offset);
852436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar* res = ML_(dinfo_zalloc)(cc, len+1);
853436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   SizeT  i;
854436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < len; i++) {
855436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      res[i] = get(img, offset+i);
856436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
857436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(res[len] == 0);
858436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return res;
859436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
860436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
861436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovInt ML_(img_strcmp)(DiImage* img, DiOffT off1, DiOffT off2)
862436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
863436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, off1, 1, "ML_(img_strcmp)(first arg)");
864436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, off2, 1, "ML_(img_strcmp)(second arg)");
865436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (True) {
866436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar c1 = get(img, off1);
867436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar c2 = get(img, off2);
868436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 < c2) return -1;
869436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 > c2) return 1;
870436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 == 0) return 0;
871436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      off1++; off2++;
872436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
873436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
874436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
875436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovInt ML_(img_strcmp_c)(DiImage* img, DiOffT off1, const HChar* str2)
876436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
877436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, off1, 1, "ML_(img_strcmp_c)");
878436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   while (True) {
879436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar c1 = get(img, off1);
880436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar c2 = *(UChar*)str2;
881436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 < c2) return -1;
882436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 > c2) return 1;
883436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (c1 == 0) return 0;
884436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      off1++; str2++;
885436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
886436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
887436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
888436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUChar ML_(img_get_UChar)(DiImage* img, DiOffT offset)
889436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
890436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ensure_valid(img, offset, 1, "ML_(img_get_UChar)");
891436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return get(img, offset);
892436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
893436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
894436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUShort ML_(img_get_UShort)(DiImage* img, DiOffT offset)
895436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
896436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UShort r;
897436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(img_get)(&r, img, offset, sizeof(r));
898436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return r;
899436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
900436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
901436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt ML_(img_get_UInt)(DiImage* img, DiOffT offset)
902436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
903436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt r;
904436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(img_get)(&r, img, offset, sizeof(r));
905436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return r;
906436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
907436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
908436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovULong ML_(img_get_ULong)(DiImage* img, DiOffT offset)
909436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
910436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong r;
911436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ML_(img_get)(&r, img, offset, sizeof(r));
912436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return r;
913436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
914436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
915436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
916436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*
917436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * This routine for calculating the CRC for a separate debug file
918436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * is GPLed code borrowed from GNU binutils.
919436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov */
920436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt ML_(img_calc_gnu_debuglink_crc32)(DiImage* img)
921436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
922436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov  static const UInt crc32_table[256] =
923436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    {
924436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
925436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
926436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
927436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
928436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
929436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
930436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
931436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
932436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
933436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
934436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
935436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
936436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
937436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
938436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
939436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
940436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
941436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
942436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
943436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
944436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
945436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
946436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
947436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
948436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
949436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
950436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
951436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
952436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
953436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
954436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
955436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
956436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
957436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
958436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
959436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
960436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
961436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
962436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
963436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
964436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
965436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
966436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
967436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
968436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
969436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
970436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
971436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
972436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
973436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
974436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
975436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      0x2d02ef8d
976436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    };
977436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
978436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(img);
979436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
980436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* If the image is local, calculate the CRC here directly.  If it's
981436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      remote, forward the request to the server. */
982436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (img->source.is_local) {
983436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Work through the image in 1 KB chunks. */
984436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UInt   crc      = 0xFFFFFFFF;
985436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DiOffT img_szB  = ML_(img_size)(img);
986436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DiOffT curr_off = 0;
987436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      while (1) {
988436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         vg_assert(curr_off >= 0 && curr_off <= img_szB);
989436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (curr_off == img_szB) break;
990436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DiOffT avail = img_szB - curr_off;
991436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         vg_assert(avail > 0 && avail <= img_szB);
992436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (avail > 1024) avail = 1024;
993436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         UChar buf[1024];
994436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         SizeT nGot = ML_(img_get_some)(buf, img, curr_off, avail);
995436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         vg_assert(nGot >= 1 && nGot <= avail);
996436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         UInt i;
997436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         for (i = 0; i < (UInt)nGot; i++)
998436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            crc = crc32_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
999436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         curr_off += nGot;
1000436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
1001436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return ~crc & 0xFFFFFFFF;
1002436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
1003436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Frame* req = mk_Frame_noargs("CRC3");
1004436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Frame* res = do_transaction(img->source.fd, req);
1005436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!res) goto remote_crc_fail;
1006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ULong crc32 = 0;
1007436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!parse_Frame_le64(res, "CROK", &crc32)) goto remote_crc_fail;
1008436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if ((crc32 & ~0xFFFFFFFFULL) != 0) goto remote_crc_fail;
1009436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (req) free_Frame(req);
1010436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (res) free_Frame(res);
1011436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return (UInt)crc32;
1012436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     remote_crc_fail:
1013436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1014436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // XXXX common this up with the READ diagnostic cases
1015436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (res) {
1016436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         UChar* reason = NULL;
1017436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (parse_Frame_asciiz(res, "FAIL", &reason)) {
1018436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
1019436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "%s\n", reason);
1020436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         } else {
1021436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
1022436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "unknown reason\n");
1023436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
1024436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
1025436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(umsg)("img_calc_gnu_debuglink_crc32: fail: "
1026436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   "server unexpectedly closed the connection\n");
1027436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
1028436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1029436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (req) free_Frame(req);
1030436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (res) free_Frame(res);
1031436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // FIXME: now what?
1032436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      give_up__comms_lost();
1033436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* NOTREACHED */
1034436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(0);
1035436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
1036436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /*NOTREACHED*/
1037436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(0);
1038436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
1039436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1040436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov////////////////////////////////////////////////////
1041436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "minilzo-inl.c"
1042436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1043436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
1044436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--- end                                                  image.c ---*/
1045436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
1046