blob: fa0a8683c5ff68c6161659d1f27dfb5caebb4c13 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management of the translation table and cache. ---*/
njn8bddf582005-05-13 23:40:55 +00004/*--- m_transtab.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00005/*--------------------------------------------------------------------*/
6
7/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardjde4a1d02002-03-22 01:27:54 +000010
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright (C) 2000-2017 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_core_basics.h"
sewardj45f4e7c2005-09-27 19:20:21 +000033#include "pub_core_debuglog.h"
sewardj291849f2012-04-20 23:58:55 +000034#include "pub_core_machine.h" // For VG_(machine_get_VexArchInfo)
njn97405b22005-06-02 03:39:33 +000035#include "pub_core_libcbase.h"
sewardj291849f2012-04-20 23:58:55 +000036#include "pub_core_vki.h" // to keep pub_core_libproc.h happy, sigh
37#include "pub_core_libcproc.h" // VG_(invalidate_icache)
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000039#include "pub_core_libcprint.h"
njn20242342005-05-16 23:31:24 +000040#include "pub_core_options.h"
sewardj10f08cf2005-06-29 10:16:14 +000041#include "pub_core_tooliface.h" // For VG_(details).avg_translation_sizeB
njn8bddf582005-05-13 23:40:55 +000042#include "pub_core_transtab.h"
sewardj45f4e7c2005-09-27 19:20:21 +000043#include "pub_core_aspacemgr.h"
44#include "pub_core_mallocfree.h" // VG_(out_of_memory_NORETURN)
sewardj291849f2012-04-20 23:58:55 +000045#include "pub_core_xarray.h"
46#include "pub_core_dispatch.h" // For VG_(disp_cp*) addresses
sewardj59570ff2010-01-01 11:59:33 +000047
48
philippe3a532202013-02-24 23:16:58 +000049#define DEBUG_TRANSTAB 0
sewardj18d75132002-05-16 11:06:21 +000050
sewardjde4a1d02002-03-22 01:27:54 +000051
sewardj6c3769f2002-11-29 01:02:45 +000052/*-------------------------------------------------------------*/
53/*--- Management of the FIFO-based translation table+cache. ---*/
54/*-------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +000055
philippe8e1bee42013-10-18 00:08:20 +000056/* Nr of sectors provided via command line parameter. */
57UInt VG_(clo_num_transtab_sectors) = N_SECTORS_DEFAULT;
58/* Nr of sectors.
59 Will be set by VG_(init_tt_tc) to VG_(clo_num_transtab_sectors). */
philippe523b5b82015-03-23 21:49:32 +000060static SECno n_sectors = 0;
philippe8e1bee42013-10-18 00:08:20 +000061
philippe924c8522015-03-15 12:24:19 +000062/* Average size of a transtab code entry. 0 means to use the tool
63 provided default. */
64UInt VG_(clo_avg_transtab_entry_size) = 0;
65
sewardj6c3769f2002-11-29 01:02:45 +000066/*------------------ CONSTANTS ------------------*/
philippebece82e2015-03-19 22:17:08 +000067/* Number of entries in hash table of each sector. This needs to be a prime
68 number to work properly, it must be <= 65535 (so that a TTE index
69 fits in a UShort, leaving room for 0xFFFF(EC2TTE_DELETED, HTT_DELETED)
70 to denote 'deleted') and 0xFFFE (HTT_EMPTY) to denote 'Empty' in the
71 hash table.
72 It is strongly recommended not to change this.
sewardj6c1bbbb2005-10-18 02:30:42 +000073 65521 is the largest prime <= 65535. */
philippebece82e2015-03-19 22:17:08 +000074#define N_HTTES_PER_SECTOR /*10007*/ /*30011*/ /*40009*/ 65521
75
76#define EC2TTE_DELETED 0xFFFF /* 16-bit special value */
77#define HTT_DELETED EC2TTE_DELETED
78#define HTT_EMPTY 0XFFFE
sewardjde4a1d02002-03-22 01:27:54 +000079
philippe523b5b82015-03-23 21:49:32 +000080// HTTno is the Sector->htt hash table index. Must be the same type as TTEno.
81typedef UShort HTTno;
82
sewardjfa8ec112005-01-19 11:55:34 +000083/* Because each sector contains a hash table of TTEntries, we need to
84 specify the maximum allowable loading, after which the sector is
85 deemed full. */
sewardj5d0d1f32010-03-14 15:09:27 +000086#define SECTOR_TT_LIMIT_PERCENT 65
sewardjde4a1d02002-03-22 01:27:54 +000087
sewardjfa8ec112005-01-19 11:55:34 +000088/* The sector is deemed full when this many entries are in it. */
philippebece82e2015-03-19 22:17:08 +000089#define N_TTES_PER_SECTOR \
90 ((N_HTTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
sewardjde4a1d02002-03-22 01:27:54 +000091
sewardj6c1bbbb2005-10-18 02:30:42 +000092/* Equivalence classes for fast address range deletion. There are 1 +
93 2^ECLASS_WIDTH bins. The highest one, ECLASS_MISC, describes an
94 address range which does not fall cleanly within any specific bin.
philipped28615c2015-03-31 20:38:52 +000095 Note that ECLASS_SHIFT + ECLASS_WIDTH must be < 32.
96 ECLASS_N must fit in a EclassNo. */
Elliott Hughesa0664b92017-04-18 17:46:52 -070097#define ECLASS_SHIFT 13
98#define ECLASS_WIDTH 9
sewardj6c1bbbb2005-10-18 02:30:42 +000099#define ECLASS_MISC (1 << ECLASS_WIDTH)
100#define ECLASS_N (1 + ECLASS_MISC)
philipped28615c2015-03-31 20:38:52 +0000101STATIC_ASSERT(ECLASS_SHIFT + ECLASS_WIDTH < 32);
sewardj6c1bbbb2005-10-18 02:30:42 +0000102
philipped28615c2015-03-31 20:38:52 +0000103typedef UShort EClassNo;
sewardjde4a1d02002-03-22 01:27:54 +0000104
sewardj6c3769f2002-11-29 01:02:45 +0000105/*------------------ TYPES ------------------*/
106
sewardj291849f2012-04-20 23:58:55 +0000107/* In edges ("to-me") in the graph created by chaining. */
108typedef
109 struct {
philippe523b5b82015-03-23 21:49:32 +0000110 SECno from_sNo; /* sector number */
111 TTEno from_tteNo; /* TTE number in given sector */
philipped28615c2015-03-31 20:38:52 +0000112 UInt from_offs: (sizeof(UInt)*8)-1; /* code offset from TCEntry::tcptr
113 where the patch is */
114 Bool to_fastEP:1; /* Is the patch to a fast or slow entry point? */
sewardj291849f2012-04-20 23:58:55 +0000115 }
116 InEdge;
117
118
119/* Out edges ("from-me") in the graph created by chaining. */
120typedef
121 struct {
philippe523b5b82015-03-23 21:49:32 +0000122 SECno to_sNo; /* sector number */
123 TTEno to_tteNo; /* TTE number in given sector */
124 UInt from_offs; /* code offset in owning translation where patch is */
sewardj291849f2012-04-20 23:58:55 +0000125 }
126 OutEdge;
127
128
129#define N_FIXED_IN_EDGE_ARR 3
130typedef
131 struct {
philipped28615c2015-03-31 20:38:52 +0000132 Bool has_var:1; /* True if var is used (then n_fixed must be 0) */
133 UInt n_fixed: (sizeof(UInt)*8)-1; /* 0 .. N_FIXED_IN_EDGE_ARR */
134 union {
135 InEdge fixed[N_FIXED_IN_EDGE_ARR]; /* if !has_var */
136 XArray* var; /* XArray* of InEdgeArr */ /* if has_var */
137 } edges;
sewardj291849f2012-04-20 23:58:55 +0000138 }
139 InEdgeArr;
140
141#define N_FIXED_OUT_EDGE_ARR 2
142typedef
143 struct {
philipped28615c2015-03-31 20:38:52 +0000144 Bool has_var:1; /* True if var is used (then n_fixed must be 0) */
145 UInt n_fixed: (sizeof(UInt)*8)-1; /* 0 .. N_FIXED_OUT_EDGE_ARR */
146 union {
147 OutEdge fixed[N_FIXED_OUT_EDGE_ARR]; /* if !has_var */
148 XArray* var; /* XArray* of OutEdgeArr */ /* if has_var */
149 } edges;
sewardj291849f2012-04-20 23:58:55 +0000150 }
151 OutEdgeArr;
152
153
sewardjfa8ec112005-01-19 11:55:34 +0000154/* A translation-table entry. This indicates precisely which areas of
155 guest code are included in the translation, and contains all other
Elliott Hughesa0664b92017-04-18 17:46:52 -0700156 auxiliary info too. These are split into hold and cold parts,
157 TTEntryH and TTEntryC, so as to be more cache-friendly
158 (a.k.a. "faster") when searching for translations that intersect
159 with a certain guest code address range, for deletion. In the
160 worst case this can involve a sequential scan through all the hot
161 parts, so they are packed as compactly as possible -- 32 bytes on a
162 64-bit platform, 20 bytes on a 32-bit platform.
163
164 Each TTEntry is logically a matching cold-and-hot pair, and in fact
165 it was originally one structure. First, the cold part.
166*/
sewardjfa8ec112005-01-19 11:55:34 +0000167typedef
168 struct {
philippebece82e2015-03-19 22:17:08 +0000169 union {
170 struct {
171 /* Profiling only: the count and weight (arbitrary meaning) for
172 this translation. Weight is a property of the translation
173 itself and computed once when the translation is created.
174 Count is an entry count for the translation and is
175 incremented by 1 every time the translation is used, if we
176 are profiling. */
177 ULong count;
178 UShort weight;
179 } prof; // if status == InUse
philippe523b5b82015-03-23 21:49:32 +0000180 TTEno next_empty_tte; // if status != InUse
philippebece82e2015-03-19 22:17:08 +0000181 } usage;
sewardjfa8ec112005-01-19 11:55:34 +0000182
sewardj5f76de02007-02-11 05:08:06 +0000183 /* 64-bit aligned pointer to one or more 64-bit words containing
184 the corresponding host code (must be in the same sector!)
185 This is a pointer into the sector's tc (code) area. */
186 ULong* tcptr;
sewardjfa8ec112005-01-19 11:55:34 +0000187
188 /* This is the original guest address that purportedly is the
189 entry point of the translation. You might think that .entry
190 should be the same as .vge->base[0], and most of the time it
191 is. However, when doing redirections, that is not the case.
192 .vge must always correctly describe the guest code sections
193 from which this translation was made. However, .entry may or
194 may not be a lie, depending on whether or not we're doing
195 redirection. */
florianddd61ff2015-01-04 17:20:45 +0000196 Addr entry;
sewardjfa8ec112005-01-19 11:55:34 +0000197
sewardj6c1bbbb2005-10-18 02:30:42 +0000198 /* Address range summary info: these are pointers back to
199 eclass[] entries in the containing Sector. Those entries in
200 turn point back here -- the two structures are mutually
201 redundant but both necessary to make fast deletions work.
202 The eclass info is similar to, and derived from, this entry's
203 'vge' field, but it is not the same */
Elliott Hughesa0664b92017-04-18 17:46:52 -0700204 UShort n_tte2ec; // # tte2ec pointers (1 to 3)
philipped28615c2015-03-31 20:38:52 +0000205 EClassNo tte2ec_ec[3]; // for each, the eclass #
206 UInt tte2ec_ix[3]; // and the index within the eclass.
sewardj6c1bbbb2005-10-18 02:30:42 +0000207 // for i in 0 .. n_tte2ec-1
208 // sec->ec2tte[ tte2ec_ec[i] ][ tte2ec_ix[i] ]
209 // should be the index
210 // of this TTEntry in the containing Sector's tt array.
sewardj291849f2012-04-20 23:58:55 +0000211
212 /* Admin information for chaining. 'in_edges' is a set of the
213 patch points which jump to this translation -- hence are
214 predecessors in the control flow graph. 'out_edges' points
215 to successors in the control flow graph -- translations to
216 which this one has a patched jump. In short these are just
217 backwards and forwards edges in the graph of patched-together
218 blocks. The 'in_edges' contain slightly more info, enough
219 that we can undo the chaining of each mentioned patch point.
220 The 'out_edges' list exists only so that we can visit the
221 'in_edges' entries of all blocks we're patched through to, in
222 order to remove ourselves from then when we're deleted. */
223
224 /* A translation can disappear for two reasons:
225 1. erased (as part of the oldest sector cleanup) when the
226 youngest sector is full.
227 2. discarded due to calls to VG_(discard_translations).
228 VG_(discard_translations) sets the status of the
229 translation to 'Deleted'.
230 A.o., the gdbserver discards one or more translations
231 when a breakpoint is inserted or removed at an Addr,
232 or when single stepping mode is enabled/disabled
233 or when a translation is instrumented for gdbserver
234 (all the target jumps of this translation are
235 invalidated).
236
237 So, it is possible that the translation A to be patched
238 (to obtain a patched jump from A to B) is invalidated
239 after B is translated and before A is patched.
240 In case a translation is erased or discarded, the patching
241 cannot be done. VG_(tt_tc_do_chaining) and find_TTEntry_from_hcode
242 are checking the 'from' translation still exists before
243 doing the patching.
244
245 Is it safe to erase or discard the current translation E being
246 executed ? Amazing, but yes, it is safe.
247 Here is the explanation:
248
249 The translation E being executed can only be erased if a new
250 translation N is being done. A new translation is done only
251 if the host addr is a not yet patched jump to another
252 translation. In such a case, the guest address of N is
253 assigned to the PC in the VEX state. Control is returned
254 to the scheduler. N will be translated. This can erase the
255 translation E (in case of sector full). VG_(tt_tc_do_chaining)
256 will not do the chaining to a non found translation E.
257 The execution will continue at the current guest PC
258 (i.e. the translation N).
259 => it is safe to erase the current translation being executed.
260
261 The current translation E being executed can also be discarded
262 (e.g. by gdbserver). VG_(discard_translations) will mark
263 this translation E as Deleted, but the translation itself
264 is not erased. In particular, its host code can only
265 be overwritten or erased in case a new translation is done.
266 A new translation will only be done if a not yet translated
267 jump is to be executed. The execution of the Deleted translation
268 E will continue till a non patched jump is encountered.
269 This situation is then similar to the 'erasing' case above :
270 the current translation E can be erased or overwritten, as the
271 execution will continue at the new translation N.
sewardj291849f2012-04-20 23:58:55 +0000272 */
273
274 /* It is possible, although very unlikely, that a block A has
275 more than one patched jump to block B. This could happen if
276 (eg) A finishes "jcond B; jmp B".
277
278 This means in turn that B's in_edges set can list A more than
279 once (twice in this example). However, each such entry must
280 have a different from_offs, since a patched jump can only
281 jump to one place at once (it's meaningless for it to have
282 multiple destinations.) IOW, the successor and predecessor
283 edges in the graph are not uniquely determined by a
284 TTEntry --> TTEntry pair, but rather by a
285 (TTEntry,offset) --> TTEntry triple.
286
287 If A has multiple edges to B then B will mention A multiple
288 times in its in_edges. To make things simpler, we then
289 require that A mentions B exactly the same number of times in
290 its out_edges. Furthermore, a matching out-in pair must have
291 the same offset (from_offs). This facilitates sanity
292 checking, and it facilitates establishing the invariant that
293 a out_edges set may not have duplicates when using the
294 equality defined by (TTEntry,offset). Hence the out_edges
295 and in_edges sets really do have both have set semantics.
296
297 eg if A has been patched to B at offsets 42 and 87 (in A)
298 then A.out_edges = { (B,42), (B,87) } (in any order)
299 and B.in_edges = { (A,42), (A,87) } (in any order)
300
301 Hence for each node pair P->Q in the graph, there's a 1:1
302 mapping between P.out_edges and Q.in_edges.
303 */
304 InEdgeArr in_edges;
305 OutEdgeArr out_edges;
sewardj6c3769f2002-11-29 01:02:45 +0000306 }
Elliott Hughesa0664b92017-04-18 17:46:52 -0700307 TTEntryC;
308
309/* And this is the hot part. */
310typedef
311 struct {
312 /* This structure describes precisely what ranges of guest code
313 the translation covers, so we can decide whether or not to
314 delete it when translations of a given address range are
315 invalidated. Originally this was a VexGuestExtents, but that
316 itself is 32 bytes on a 64-bit target, and we really want to
317 squeeze in an 8-bit |status| field into the 32 byte field, so
318 as to get 2 of them in a 64 byte LLC line. Hence the
319 VexGuestExtents fields are inlined, the _n_used field is
320 changed to a UChar (it only ever has the values 1, 2 or 3)
321 and the 8-bit status field is placed in byte 31 of the
322 structure. */
323 /* ORIGINALLY: VexGuestExtents vge; */
324 Addr vge_base[3];
325 UShort vge_len[3];
326 UChar vge_n_used; /* BEWARE: is UShort in VexGuestExtents */
327
328 /* Status of the slot. Note, we need to be able to do lazy
329 deletion, hence the Deleted state. */
330 enum { InUse, Deleted, Empty } status : 8;
331 }
332 TTEntryH;
333
334
335/* Impedance matchers, that convert between a VexGuestExtents and a
336 TTEntryH, ignoring TTEntryH::status, which doesn't exist in a
337 VexGuestExtents -- it is entirely unrelated. */
338
339/* Takes a VexGuestExtents and pushes it into a TTEntryH. The
340 TTEntryH.status field is left unchanged. */
341static
342inline void TTEntryH__from_VexGuestExtents ( /*MOD*/TTEntryH* tteH,
343 const VexGuestExtents* vge )
344{
345 tteH->vge_base[0] = vge->base[0];
346 tteH->vge_base[1] = vge->base[1];
347 tteH->vge_base[2] = vge->base[2];
348 tteH->vge_len[0] = vge->len[0];
349 tteH->vge_len[1] = vge->len[1];
350 tteH->vge_len[2] = vge->len[2];
351 tteH->vge_n_used = (UChar)vge->n_used; /* BEWARE: no range check. */
352}
353
354/* Takes a TTEntryH and pushes the vge_ components into a VexGuestExtents. */
355static
356inline void TTEntryH__to_VexGuestExtents ( /*MOD*/VexGuestExtents* vge,
357 const TTEntryH* tteH )
358{
359 vge->base[0] = tteH->vge_base[0];
360 vge->base[1] = tteH->vge_base[1];
361 vge->base[2] = tteH->vge_base[2];
362 vge->len[0] = tteH->vge_len[0] ;
363 vge->len[1] = tteH->vge_len[1] ;
364 vge->len[2] = tteH->vge_len[2] ;
365 vge->n_used = (UShort)tteH->vge_n_used ;
366}
sewardj6c3769f2002-11-29 01:02:45 +0000367
sewardj4ccf7072004-11-28 16:58:05 +0000368
sewardj291849f2012-04-20 23:58:55 +0000369/* A structure used for mapping host code addresses back to the
370 relevant TTEntry. Used when doing chaining, for finding the
371 TTEntry to which some arbitrary patch address belongs. */
372typedef
373 struct {
374 UChar* start;
375 UInt len;
philippe523b5b82015-03-23 21:49:32 +0000376 TTEno tteNo;
sewardj291849f2012-04-20 23:58:55 +0000377 }
378 HostExtent;
379
sewardjfa8ec112005-01-19 11:55:34 +0000380/* Finally, a sector itself. Each sector contains an array of
381 TCEntries, which hold code, and an array of TTEntries, containing
382 all required administrative info. Profiling is supported using the
philippebece82e2015-03-19 22:17:08 +0000383 TTEntry usage.prof.count and usage.prof.weight fields, if required.
sewardj4ccf7072004-11-28 16:58:05 +0000384
sewardjfa8ec112005-01-19 11:55:34 +0000385 If the sector is not in use, all three pointers are NULL and
386 tt_n_inuse is zero.
387*/
388typedef
389 struct {
390 /* The TCEntry area. Size of this depends on the average
391 translation size. We try and size it so it becomes full
392 precisely when this sector's translation table (tt) reaches
393 its load limit (SECTOR_TT_LIMIT_PERCENT). */
394 ULong* tc;
sewardj4ccf7072004-11-28 16:58:05 +0000395
philippe523b5b82015-03-23 21:49:32 +0000396 /* An hash table, mapping guest address to an index in the tt array.
philippebece82e2015-03-19 22:17:08 +0000397 htt is a fixed size, always containing
398 exactly N_HTTES_PER_SECTOR entries. */
philippe523b5b82015-03-23 21:49:32 +0000399 TTEno* htt;
philippebece82e2015-03-19 22:17:08 +0000400
Elliott Hughesa0664b92017-04-18 17:46:52 -0700401 /* The TTEntry{C,H} arrays. These are a fixed size, always
402 containing exactly N_TTES_PER_SECTOR entries. */
403 TTEntryC* ttC;
404 TTEntryH* ttH;
sewardj4ccf7072004-11-28 16:58:05 +0000405
sewardjfa8ec112005-01-19 11:55:34 +0000406 /* This points to the current allocation point in tc. */
407 ULong* tc_next;
sewardj6c3769f2002-11-29 01:02:45 +0000408
sewardjfa8ec112005-01-19 11:55:34 +0000409 /* The count of tt entries with state InUse. */
410 Int tt_n_inuse;
sewardj6c1bbbb2005-10-18 02:30:42 +0000411
philippebece82e2015-03-19 22:17:08 +0000412 /* A list of Empty/Deleted entries, chained by tte->next_empty_tte */
philippe523b5b82015-03-23 21:49:32 +0000413 TTEno empty_tt_list;
philippebece82e2015-03-19 22:17:08 +0000414
sewardj6c1bbbb2005-10-18 02:30:42 +0000415 /* Expandable arrays of tt indices for each of the ECLASS_N
416 address range equivalence classes. These hold indices into
417 the containing sector's tt array, which in turn should point
418 back here. */
419 Int ec2tte_size[ECLASS_N];
420 Int ec2tte_used[ECLASS_N];
philippe523b5b82015-03-23 21:49:32 +0000421 TTEno* ec2tte[ECLASS_N];
sewardj291849f2012-04-20 23:58:55 +0000422
423 /* The host extents. The [start, +len) ranges are constructed
424 in strictly non-overlapping order, so we can binary search
425 them at any time. */
426 XArray* host_extents; /* XArray* of HostExtent */
sewardjfa8ec112005-01-19 11:55:34 +0000427 }
428 Sector;
sewardjde4a1d02002-03-22 01:27:54 +0000429
sewardjde4a1d02002-03-22 01:27:54 +0000430
sewardj6c3769f2002-11-29 01:02:45 +0000431/*------------------ DECLS ------------------*/
432
sewardjfa8ec112005-01-19 11:55:34 +0000433/* The root data structure is an array of sectors. The index of the
434 youngest sector is recorded, and new translations are put into that
435 sector. When it fills up, we move along to the next sector and
436 start to fill that up, wrapping around at the end of the array.
437 That way, once all N_TC_SECTORS have been bought into use for the
438 first time, and are full, we then re-use the oldest sector,
439 endlessly.
sewardj6c3769f2002-11-29 01:02:45 +0000440
sewardjfa8ec112005-01-19 11:55:34 +0000441 When running, youngest sector should be between >= 0 and <
philippe523b5b82015-03-23 21:49:32 +0000442 N_TC_SECTORS. The initial value indicates the TT/TC system is
sewardjfa8ec112005-01-19 11:55:34 +0000443 not yet initialised.
444*/
philippe8e1bee42013-10-18 00:08:20 +0000445static Sector sectors[MAX_N_SECTORS];
philippe523b5b82015-03-23 21:49:32 +0000446static Int youngest_sector = INV_SNO;
sewardj6c3769f2002-11-29 01:02:45 +0000447
sewardjfa8ec112005-01-19 11:55:34 +0000448/* The number of ULongs in each TCEntry area. This is computed once
449 at startup and does not change. */
sewardja11ec172013-10-18 11:18:45 +0000450static Int tc_sector_szQ = 0;
nethercote92e7b7f2004-08-07 17:52:25 +0000451
452
sewardj5d0d1f32010-03-14 15:09:27 +0000453/* A list of sector numbers, in the order which they should be
454 searched to find translations. This is an optimisation to be used
455 when searching for translations and should not affect
philippe523b5b82015-03-23 21:49:32 +0000456 correctness. INV_SNO denotes "no entry". */
457static SECno sector_search_order[MAX_N_SECTORS];
sewardj5d0d1f32010-03-14 15:09:27 +0000458
459
sewardj5f76de02007-02-11 05:08:06 +0000460/* Fast helper for the TC. A direct-mapped cache which holds a set of
461 recently used (guest address, host address) pairs. This array is
462 referred to directly from m_dispatch/dispatch-<platform>.S.
sewardj8aef1192002-07-24 09:36:36 +0000463
sewardj5f76de02007-02-11 05:08:06 +0000464 Entries in tt_fast may refer to any valid TC entry, regardless of
sewardjfa8ec112005-01-19 11:55:34 +0000465 which sector it's in. Consequently we must be very careful to
466 invalidate this cache when TC entries are changed or disappear.
467
sewardj5f76de02007-02-11 05:08:06 +0000468 A special .guest address - TRANSTAB_BOGUS_GUEST_ADDR -- must be
469 pointed at to cause that cache entry to miss. This relies on the
470 assumption that no guest code actually has that address, hence a
471 value 0x1 seems good. m_translate gives the client a synthetic
472 segfault if it tries to execute at this address.
sewardjfa8ec112005-01-19 11:55:34 +0000473*/
sewardj5f76de02007-02-11 05:08:06 +0000474/*
475typedef
476 struct {
477 Addr guest;
478 Addr host;
479 }
480 FastCacheEntry;
481*/
482/*global*/ __attribute__((aligned(16)))
483 FastCacheEntry VG_(tt_fast)[VG_TT_FAST_SIZE];
sewardjfa8ec112005-01-19 11:55:34 +0000484
sewardj663a1bd2005-04-24 11:22:44 +0000485/* Make sure we're not used before initialisation. */
486static Bool init_done = False;
487
488
sewardjfa8ec112005-01-19 11:55:34 +0000489/*------------------ STATS DECLS ------------------*/
490
491/* Number of fast-cache updates and flushes done. */
sewardj291849f2012-04-20 23:58:55 +0000492static ULong n_fast_flushes = 0;
493static ULong n_fast_updates = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000494
495/* Number of full lookups done. */
sewardj291849f2012-04-20 23:58:55 +0000496static ULong n_full_lookups = 0;
497static ULong n_lookup_probes = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000498
sewardj26412bd2005-07-07 10:05:05 +0000499/* Number/osize/tsize of translations entered; also the number of
500 those for which self-checking was requested. */
sewardj291849f2012-04-20 23:58:55 +0000501static ULong n_in_count = 0;
502static ULong n_in_osize = 0;
503static ULong n_in_tsize = 0;
504static ULong n_in_sc_count = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000505
506/* Number/osize of translations discarded due to lack of space. */
sewardj291849f2012-04-20 23:58:55 +0000507static ULong n_dump_count = 0;
508static ULong n_dump_osize = 0;
philippe5e47e3f2015-03-12 22:36:22 +0000509static ULong n_sectors_recycled = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000510
511/* Number/osize of translations discarded due to requests to do so. */
sewardj291849f2012-04-20 23:58:55 +0000512static ULong n_disc_count = 0;
513static ULong n_disc_osize = 0;
514
515
516/*-------------------------------------------------------------*/
517/*--- Misc ---*/
518/*-------------------------------------------------------------*/
519
florian54fe2022012-10-27 23:07:42 +0000520static void* ttaux_malloc ( const HChar* tag, SizeT n )
sewardj291849f2012-04-20 23:58:55 +0000521{
522 return VG_(arena_malloc)(VG_AR_TTAUX, tag, n);
523}
524
525static void ttaux_free ( void* p )
526{
527 VG_(arena_free)(VG_AR_TTAUX, p);
528}
529
530
531/*-------------------------------------------------------------*/
532/*--- Chaining support ---*/
533/*-------------------------------------------------------------*/
534
Elliott Hughesa0664b92017-04-18 17:46:52 -0700535static inline TTEntryC* index_tteC ( SECno sNo, TTEno tteNo )
sewardj291849f2012-04-20 23:58:55 +0000536{
philippe8e1bee42013-10-18 00:08:20 +0000537 vg_assert(sNo < n_sectors);
sewardj291849f2012-04-20 23:58:55 +0000538 vg_assert(tteNo < N_TTES_PER_SECTOR);
539 Sector* s = &sectors[sNo];
Elliott Hughesa0664b92017-04-18 17:46:52 -0700540 vg_assert(s->ttC && s->ttH);
541 TTEntryC* tteC = &s->ttC[tteNo];
542 TTEntryH* tteH = &s->ttH[tteNo];
543 vg_assert(tteH->status == InUse);
544 return tteC;
545}
546
547static inline TTEntryH* index_tteH ( SECno sNo, TTEno tteNo )
548{
549 vg_assert(sNo < n_sectors);
550 vg_assert(tteNo < N_TTES_PER_SECTOR);
551 Sector* s = &sectors[sNo];
552 vg_assert(s->ttH);
553 TTEntryH* tteH = &s->ttH[tteNo];
554 vg_assert(tteH->status == InUse);
555 return tteH;
sewardj291849f2012-04-20 23:58:55 +0000556}
557
558static void InEdge__init ( InEdge* ie )
559{
philippe523b5b82015-03-23 21:49:32 +0000560 ie->from_sNo = INV_SNO; /* invalid */
sewardj291849f2012-04-20 23:58:55 +0000561 ie->from_tteNo = 0;
562 ie->from_offs = 0;
563 ie->to_fastEP = False;
564}
565
566static void OutEdge__init ( OutEdge* oe )
567{
philippe523b5b82015-03-23 21:49:32 +0000568 oe->to_sNo = INV_SNO; /* invalid */
sewardj291849f2012-04-20 23:58:55 +0000569 oe->to_tteNo = 0;
570 oe->from_offs = 0;
571}
572
Elliott Hughesa0664b92017-04-18 17:46:52 -0700573static void TTEntryC__init ( TTEntryC* tteC )
sewardj291849f2012-04-20 23:58:55 +0000574{
Elliott Hughesa0664b92017-04-18 17:46:52 -0700575 VG_(bzero_inline)(tteC, sizeof(*tteC));
576}
577
578static void TTEntryH__init ( TTEntryH* tteH )
579{
580 VG_(bzero_inline)(tteH, sizeof(*tteH));
sewardj291849f2012-04-20 23:58:55 +0000581}
582
florian518850b2014-10-22 22:25:30 +0000583static UWord InEdgeArr__size ( const InEdgeArr* iea )
sewardj291849f2012-04-20 23:58:55 +0000584{
philipped28615c2015-03-31 20:38:52 +0000585 if (iea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000586 vg_assert(iea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000587 return VG_(sizeXA)(iea->edges.var);
sewardj291849f2012-04-20 23:58:55 +0000588 } else {
589 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
590 return iea->n_fixed;
591 }
592}
593
594static void InEdgeArr__makeEmpty ( InEdgeArr* iea )
595{
philipped28615c2015-03-31 20:38:52 +0000596 if (iea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000597 vg_assert(iea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000598 VG_(deleteXA)(iea->edges.var);
599 iea->edges.var = NULL;
600 iea->has_var = False;
sewardj291849f2012-04-20 23:58:55 +0000601 } else {
602 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
603 iea->n_fixed = 0;
604 }
605}
606
607static
608InEdge* InEdgeArr__index ( InEdgeArr* iea, UWord i )
609{
philipped28615c2015-03-31 20:38:52 +0000610 if (iea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000611 vg_assert(iea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000612 return (InEdge*)VG_(indexXA)(iea->edges.var, i);
sewardj291849f2012-04-20 23:58:55 +0000613 } else {
614 vg_assert(i < iea->n_fixed);
philipped28615c2015-03-31 20:38:52 +0000615 return &iea->edges.fixed[i];
sewardj291849f2012-04-20 23:58:55 +0000616 }
617}
618
619static
620void InEdgeArr__deleteIndex ( InEdgeArr* iea, UWord i )
621{
philipped28615c2015-03-31 20:38:52 +0000622 if (iea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000623 vg_assert(iea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000624 VG_(removeIndexXA)(iea->edges.var, i);
sewardj291849f2012-04-20 23:58:55 +0000625 } else {
626 vg_assert(i < iea->n_fixed);
627 for (; i+1 < iea->n_fixed; i++) {
philipped28615c2015-03-31 20:38:52 +0000628 iea->edges.fixed[i] = iea->edges.fixed[i+1];
sewardj291849f2012-04-20 23:58:55 +0000629 }
630 iea->n_fixed--;
631 }
632}
633
634static
635void InEdgeArr__add ( InEdgeArr* iea, InEdge* ie )
636{
philipped28615c2015-03-31 20:38:52 +0000637 if (iea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000638 vg_assert(iea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000639 VG_(addToXA)(iea->edges.var, ie);
sewardj291849f2012-04-20 23:58:55 +0000640 } else {
641 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
642 if (iea->n_fixed == N_FIXED_IN_EDGE_ARR) {
643 /* The fixed array is full, so we have to initialise an
644 XArray and copy the fixed array into it. */
philipped28615c2015-03-31 20:38:52 +0000645 XArray *var = VG_(newXA)(ttaux_malloc, "transtab.IEA__add",
646 ttaux_free,
647 sizeof(InEdge));
philipped4dc5fc2015-05-01 16:46:38 +0000648 VG_(hintSizeXA) (var, iea->n_fixed + 1);
sewardj291849f2012-04-20 23:58:55 +0000649 UWord i;
650 for (i = 0; i < iea->n_fixed; i++) {
philipped28615c2015-03-31 20:38:52 +0000651 VG_(addToXA)(var, &iea->edges.fixed[i]);
sewardj291849f2012-04-20 23:58:55 +0000652 }
philipped28615c2015-03-31 20:38:52 +0000653 VG_(addToXA)(var, ie);
sewardj291849f2012-04-20 23:58:55 +0000654 iea->n_fixed = 0;
philipped28615c2015-03-31 20:38:52 +0000655 iea->has_var = True;
656 iea->edges.var = var;
sewardj291849f2012-04-20 23:58:55 +0000657 } else {
658 /* Just add to the fixed array. */
philipped28615c2015-03-31 20:38:52 +0000659 iea->edges.fixed[iea->n_fixed++] = *ie;
sewardj291849f2012-04-20 23:58:55 +0000660 }
661 }
662}
663
florian518850b2014-10-22 22:25:30 +0000664static UWord OutEdgeArr__size ( const OutEdgeArr* oea )
sewardj291849f2012-04-20 23:58:55 +0000665{
philipped28615c2015-03-31 20:38:52 +0000666 if (oea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000667 vg_assert(oea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000668 return VG_(sizeXA)(oea->edges.var);
sewardj291849f2012-04-20 23:58:55 +0000669 } else {
670 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
671 return oea->n_fixed;
672 }
673}
674
675static void OutEdgeArr__makeEmpty ( OutEdgeArr* oea )
676{
philipped28615c2015-03-31 20:38:52 +0000677 if (oea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000678 vg_assert(oea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000679 VG_(deleteXA)(oea->edges.var);
680 oea->edges.var = NULL;
681 oea->has_var = False;
sewardj291849f2012-04-20 23:58:55 +0000682 } else {
683 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
684 oea->n_fixed = 0;
685 }
686}
687
688static
689OutEdge* OutEdgeArr__index ( OutEdgeArr* oea, UWord i )
690{
philipped28615c2015-03-31 20:38:52 +0000691 if (oea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000692 vg_assert(oea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000693 return (OutEdge*)VG_(indexXA)(oea->edges.var, i);
sewardj291849f2012-04-20 23:58:55 +0000694 } else {
695 vg_assert(i < oea->n_fixed);
philipped28615c2015-03-31 20:38:52 +0000696 return &oea->edges.fixed[i];
sewardj291849f2012-04-20 23:58:55 +0000697 }
698}
699
700static
701void OutEdgeArr__deleteIndex ( OutEdgeArr* oea, UWord i )
702{
philipped28615c2015-03-31 20:38:52 +0000703 if (oea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000704 vg_assert(oea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000705 VG_(removeIndexXA)(oea->edges.var, i);
sewardj291849f2012-04-20 23:58:55 +0000706 } else {
707 vg_assert(i < oea->n_fixed);
708 for (; i+1 < oea->n_fixed; i++) {
philipped28615c2015-03-31 20:38:52 +0000709 oea->edges.fixed[i] = oea->edges.fixed[i+1];
sewardj291849f2012-04-20 23:58:55 +0000710 }
711 oea->n_fixed--;
712 }
713}
714
715static
716void OutEdgeArr__add ( OutEdgeArr* oea, OutEdge* oe )
717{
philipped28615c2015-03-31 20:38:52 +0000718 if (oea->has_var) {
sewardj291849f2012-04-20 23:58:55 +0000719 vg_assert(oea->n_fixed == 0);
philipped28615c2015-03-31 20:38:52 +0000720 VG_(addToXA)(oea->edges.var, oe);
sewardj291849f2012-04-20 23:58:55 +0000721 } else {
722 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
723 if (oea->n_fixed == N_FIXED_OUT_EDGE_ARR) {
724 /* The fixed array is full, so we have to initialise an
725 XArray and copy the fixed array into it. */
philipped28615c2015-03-31 20:38:52 +0000726 XArray *var = VG_(newXA)(ttaux_malloc, "transtab.OEA__add",
727 ttaux_free,
728 sizeof(OutEdge));
philipped4dc5fc2015-05-01 16:46:38 +0000729 VG_(hintSizeXA) (var, oea->n_fixed+1);
sewardj291849f2012-04-20 23:58:55 +0000730 UWord i;
731 for (i = 0; i < oea->n_fixed; i++) {
philipped28615c2015-03-31 20:38:52 +0000732 VG_(addToXA)(var, &oea->edges.fixed[i]);
sewardj291849f2012-04-20 23:58:55 +0000733 }
philipped28615c2015-03-31 20:38:52 +0000734 VG_(addToXA)(var, oe);
sewardj291849f2012-04-20 23:58:55 +0000735 oea->n_fixed = 0;
philipped28615c2015-03-31 20:38:52 +0000736 oea->has_var = True;
737 oea->edges.var = var;
sewardj291849f2012-04-20 23:58:55 +0000738 } else {
739 /* Just add to the fixed array. */
philipped28615c2015-03-31 20:38:52 +0000740 oea->edges.fixed[oea->n_fixed++] = *oe;
sewardj291849f2012-04-20 23:58:55 +0000741 }
742 }
743}
744
745static
florian6bd9dc12012-11-23 16:17:43 +0000746Int HostExtent__cmpOrd ( const void* v1, const void* v2 )
sewardj291849f2012-04-20 23:58:55 +0000747{
florian6bd9dc12012-11-23 16:17:43 +0000748 const HostExtent* hx1 = v1;
749 const HostExtent* hx2 = v2;
sewardj291849f2012-04-20 23:58:55 +0000750 if (hx1->start + hx1->len <= hx2->start) return -1;
751 if (hx2->start + hx2->len <= hx1->start) return 1;
752 return 0; /* partial overlap */
753}
754
philippe3a532202013-02-24 23:16:58 +0000755/* True if hx is a dead host extent, i.e. corresponds to host code
756 of an entry that was invalidated. */
757static
758Bool HostExtent__is_dead (const HostExtent* hx, const Sector* sec)
759{
philippe523b5b82015-03-23 21:49:32 +0000760 const TTEno tteNo = hx->tteNo;
philippe3a532202013-02-24 23:16:58 +0000761#define LDEBUG(m) if (DEBUG_TRANSTAB) \
762 VG_(printf) (m \
763 " start 0x%p len %u sector %d ttslot %u" \
florianddd61ff2015-01-04 17:20:45 +0000764 " tt.entry 0x%lu tt.tcptr 0x%p\n", \
philippe3a532202013-02-24 23:16:58 +0000765 hx->start, hx->len, (int)(sec - sectors), \
766 hx->tteNo, \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700767 sec->ttC[tteNo].entry, sec->ttC[tteNo].tcptr)
philippe3a532202013-02-24 23:16:58 +0000768
769 /* Entry might have been invalidated and not re-used yet.*/
Elliott Hughesa0664b92017-04-18 17:46:52 -0700770 if (sec->ttH[tteNo].status == Deleted) {
philippe3a532202013-02-24 23:16:58 +0000771 LDEBUG("found deleted entry");
772 return True;
773 }
774 /* Maybe we found this entry via a host_extents which was
775 inserted for an entry which was changed to Deleted then
776 re-used after. If this entry was re-used, then its tcptr
777 is >= to host_extents start (i.e. the previous tcptr) + len.
778 This is the case as there is no re-use of host code: a new
779 entry or re-used entry always gets "higher value" host code. */
Elliott Hughesa0664b92017-04-18 17:46:52 -0700780 if ((UChar*) sec->ttC[tteNo].tcptr >= hx->start + hx->len) {
philippe3a532202013-02-24 23:16:58 +0000781 LDEBUG("found re-used entry");
782 return True;
783 }
784
785 return False;
786#undef LDEBUG
787}
788
sewardj291849f2012-04-20 23:58:55 +0000789static __attribute__((noinline))
philippe523b5b82015-03-23 21:49:32 +0000790Bool find_TTEntry_from_hcode( /*OUT*/SECno* from_sNo,
791 /*OUT*/TTEno* from_tteNo,
sewardj291849f2012-04-20 23:58:55 +0000792 void* hcode )
793{
philippe523b5b82015-03-23 21:49:32 +0000794 SECno i;
sewardj291849f2012-04-20 23:58:55 +0000795
796 /* Search order logic copied from VG_(search_transtab). */
philippe8e1bee42013-10-18 00:08:20 +0000797 for (i = 0; i < n_sectors; i++) {
philippe523b5b82015-03-23 21:49:32 +0000798 SECno sno = sector_search_order[i];
799 if (UNLIKELY(sno == INV_SNO))
sewardj291849f2012-04-20 23:58:55 +0000800 return False; /* run out of sectors to search */
801
florian518850b2014-10-22 22:25:30 +0000802 const Sector* sec = &sectors[sno];
803 const XArray* /* of HostExtent */ host_extents = sec->host_extents;
sewardj291849f2012-04-20 23:58:55 +0000804 vg_assert(host_extents);
805
806 HostExtent key;
807 VG_(memset)(&key, 0, sizeof(key));
808 key.start = hcode;
809 key.len = 1;
810 Word firstW = -1, lastW = -1;
811 Bool found = VG_(lookupXA_UNSAFE)(
812 host_extents, &key, &firstW, &lastW,
florian6bd9dc12012-11-23 16:17:43 +0000813 HostExtent__cmpOrd );
sewardj291849f2012-04-20 23:58:55 +0000814 vg_assert(firstW == lastW); // always true, even if not found
815 if (found) {
816 HostExtent* hx = VG_(indexXA)(host_extents, firstW);
philippe523b5b82015-03-23 21:49:32 +0000817 TTEno tteNo = hx->tteNo;
sewardj291849f2012-04-20 23:58:55 +0000818 /* Do some additional sanity checks. */
philippebece82e2015-03-19 22:17:08 +0000819 vg_assert(tteNo < N_TTES_PER_SECTOR);
philippe3a532202013-02-24 23:16:58 +0000820
821 /* if this hx entry corresponds to dead host code, we must
822 tell this code has not been found, as it cannot be patched. */
823 if (HostExtent__is_dead (hx, sec))
sewardj291849f2012-04-20 23:58:55 +0000824 return False;
philippe3a532202013-02-24 23:16:58 +0000825
Elliott Hughesa0664b92017-04-18 17:46:52 -0700826 vg_assert(sec->ttH[tteNo].status == InUse);
sewardj291849f2012-04-20 23:58:55 +0000827 /* Can only half check that the found TTEntry contains hcode,
828 due to not having a length value for the hcode in the
829 TTEntry. */
Elliott Hughesa0664b92017-04-18 17:46:52 -0700830 vg_assert((UChar*)sec->ttC[tteNo].tcptr <= (UChar*)hcode);
sewardj291849f2012-04-20 23:58:55 +0000831 /* Looks plausible */
832 *from_sNo = sno;
philippe523b5b82015-03-23 21:49:32 +0000833 *from_tteNo = tteNo;
sewardj291849f2012-04-20 23:58:55 +0000834 return True;
835 }
836 }
837 return False;
838}
839
840
841/* Figure out whether or not hcode is jitted code present in the main
842 code cache (but not in the no-redir cache). Used for sanity
843 checking. */
florian518850b2014-10-22 22:25:30 +0000844static Bool is_in_the_main_TC ( const void* hcode )
sewardj291849f2012-04-20 23:58:55 +0000845{
philippe523b5b82015-03-23 21:49:32 +0000846 SECno i, sno;
philippe8e1bee42013-10-18 00:08:20 +0000847 for (i = 0; i < n_sectors; i++) {
sewardj291849f2012-04-20 23:58:55 +0000848 sno = sector_search_order[i];
philippe523b5b82015-03-23 21:49:32 +0000849 if (sno == INV_SNO)
sewardj291849f2012-04-20 23:58:55 +0000850 break; /* run out of sectors to search */
florian518850b2014-10-22 22:25:30 +0000851 if ((const UChar*)hcode >= (const UChar*)sectors[sno].tc
852 && (const UChar*)hcode <= (const UChar*)sectors[sno].tc_next
sewardj291849f2012-04-20 23:58:55 +0000853 + sizeof(ULong) - 1)
854 return True;
855 }
856 return False;
857}
858
859
860/* Fulfill a chaining request, and record admin info so we
861 can undo it later, if required.
862*/
863void VG_(tt_tc_do_chaining) ( void* from__patch_addr,
philippe523b5b82015-03-23 21:49:32 +0000864 SECno to_sNo,
865 TTEno to_tteNo,
sewardj291849f2012-04-20 23:58:55 +0000866 Bool to_fastEP )
867{
868 /* Get the CPU info established at startup. */
sewardj59731422014-07-24 12:45:24 +0000869 VexArch arch_host = VexArch_INVALID;
870 VexArchInfo archinfo_host;
871 VG_(bzero_inline)(&archinfo_host, sizeof(archinfo_host));
872 VG_(machine_get_VexArchInfo)( &arch_host, &archinfo_host );
873 VexEndness endness_host = archinfo_host.endness;
sewardj291849f2012-04-20 23:58:55 +0000874
875 // host_code is where we're patching to. So it needs to
876 // take into account, whether we're jumping to the slow
877 // or fast entry point. By definition, the fast entry point
878 // is exactly one event check's worth of code along from
879 // the slow (tcptr) entry point.
Elliott Hughesa0664b92017-04-18 17:46:52 -0700880 TTEntryC* to_tteC = index_tteC(to_sNo, to_tteNo);
881 void* host_code = ((UChar*)to_tteC->tcptr)
882 + (to_fastEP ? LibVEX_evCheckSzB(arch_host) : 0);
sewardj291849f2012-04-20 23:58:55 +0000883
884 // stay sane -- the patch point (dst) is in this sector's code cache
885 vg_assert( (UChar*)host_code >= (UChar*)sectors[to_sNo].tc );
886 vg_assert( (UChar*)host_code <= (UChar*)sectors[to_sNo].tc_next
887 + sizeof(ULong) - 1 );
888
889 /* Find the TTEntry for the from__ code. This isn't simple since
890 we only know the patch address, which is going to be somewhere
891 inside the from_ block. */
philippe523b5b82015-03-23 21:49:32 +0000892 SECno from_sNo = INV_SNO;
893 TTEno from_tteNo = INV_TTE;
sewardj291849f2012-04-20 23:58:55 +0000894 Bool from_found
895 = find_TTEntry_from_hcode( &from_sNo, &from_tteNo,
896 from__patch_addr );
897 if (!from_found) {
898 // The from code might have been discarded due to sector re-use
899 // or marked Deleted due to translation invalidation.
900 // In such a case, don't do the chaining.
901 VG_(debugLog)(1,"transtab",
902 "host code %p not found (discarded? sector recycled?)"
903 " => no chaining done\n",
904 from__patch_addr);
905 return;
906 }
907
Elliott Hughesa0664b92017-04-18 17:46:52 -0700908 TTEntryC* from_tteC = index_tteC(from_sNo, from_tteNo);
sewardj291849f2012-04-20 23:58:55 +0000909
910 /* Get VEX to do the patching itself. We have to hand it off
911 since it is host-dependent. */
912 VexInvalRange vir
913 = LibVEX_Chain(
sewardj59731422014-07-24 12:45:24 +0000914 arch_host, endness_host,
sewardj291849f2012-04-20 23:58:55 +0000915 from__patch_addr,
916 VG_(fnptr_to_fnentry)(
917 to_fastEP ? &VG_(disp_cp_chain_me_to_fastEP)
918 : &VG_(disp_cp_chain_me_to_slowEP)),
919 (void*)host_code
920 );
921 VG_(invalidate_icache)( (void*)vir.start, vir.len );
922
923 /* Now do the tricky bit -- update the ch_succs and ch_preds info
924 for the two translations involved, so we can undo the chaining
925 later, which we will have to do if the to_ block gets removed
926 for whatever reason. */
927
928 /* This is the new from_ -> to_ link to add. */
929 InEdge ie;
930 InEdge__init(&ie);
931 ie.from_sNo = from_sNo;
932 ie.from_tteNo = from_tteNo;
933 ie.to_fastEP = to_fastEP;
934 HWord from_offs = (HWord)( (UChar*)from__patch_addr
Elliott Hughesa0664b92017-04-18 17:46:52 -0700935 - (UChar*)from_tteC->tcptr );
sewardj291849f2012-04-20 23:58:55 +0000936 vg_assert(from_offs < 100000/* let's say */);
937 ie.from_offs = (UInt)from_offs;
938
939 /* This is the new to_ -> from_ backlink to add. */
940 OutEdge oe;
941 OutEdge__init(&oe);
942 oe.to_sNo = to_sNo;
943 oe.to_tteNo = to_tteNo;
944 oe.from_offs = (UInt)from_offs;
945
946 /* Add .. */
Elliott Hughesa0664b92017-04-18 17:46:52 -0700947 InEdgeArr__add(&to_tteC->in_edges, &ie);
948 OutEdgeArr__add(&from_tteC->out_edges, &oe);
sewardj291849f2012-04-20 23:58:55 +0000949}
950
951
952/* Unchain one patch, as described by the specified InEdge. For
953 sanity check purposes only (to check that the patched location is
954 as expected) it also requires the fast and slow entry point
955 addresses of the destination block (that is, the block that owns
956 this InEdge). */
957__attribute__((noinline))
sewardj59731422014-07-24 12:45:24 +0000958static void unchain_one ( VexArch arch_host, VexEndness endness_host,
sewardj291849f2012-04-20 23:58:55 +0000959 InEdge* ie,
960 void* to_fastEPaddr, void* to_slowEPaddr )
961{
962 vg_assert(ie);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700963 TTEntryC* tteC
964 = index_tteC(ie->from_sNo, ie->from_tteNo);
sewardj291849f2012-04-20 23:58:55 +0000965 UChar* place_to_patch
Elliott Hughesa0664b92017-04-18 17:46:52 -0700966 = ((UChar*)tteC->tcptr) + ie->from_offs;
sewardj291849f2012-04-20 23:58:55 +0000967 UChar* disp_cp_chain_me
968 = VG_(fnptr_to_fnentry)(
969 ie->to_fastEP ? &VG_(disp_cp_chain_me_to_fastEP)
970 : &VG_(disp_cp_chain_me_to_slowEP)
971 );
972 UChar* place_to_jump_to_EXPECTED
973 = ie->to_fastEP ? to_fastEPaddr : to_slowEPaddr;
974
975 // stay sane: both src and dst for this unchaining are
976 // in the main code cache
977 vg_assert( is_in_the_main_TC(place_to_patch) ); // src
978 vg_assert( is_in_the_main_TC(place_to_jump_to_EXPECTED) ); // dst
979 // dst check is ok because LibVEX_UnChain checks that
980 // place_to_jump_to_EXPECTED really is the current dst, and
981 // asserts if it isn't.
982 VexInvalRange vir
sewardj59731422014-07-24 12:45:24 +0000983 = LibVEX_UnChain( arch_host, endness_host, place_to_patch,
sewardj291849f2012-04-20 23:58:55 +0000984 place_to_jump_to_EXPECTED, disp_cp_chain_me );
985 VG_(invalidate_icache)( (void*)vir.start, vir.len );
986}
987
988
989/* The specified block is about to be deleted. Update the preds and
990 succs of its associated blocks accordingly. This includes undoing
991 any chained jumps to this block. */
992static
sewardj59731422014-07-24 12:45:24 +0000993void unchain_in_preparation_for_deletion ( VexArch arch_host,
994 VexEndness endness_host,
philippe523b5b82015-03-23 21:49:32 +0000995 SECno here_sNo, TTEno here_tteNo )
sewardj291849f2012-04-20 23:58:55 +0000996{
philippe3a532202013-02-24 23:16:58 +0000997 if (DEBUG_TRANSTAB)
998 VG_(printf)("QQQ unchain_in_prep %u.%u...\n", here_sNo, here_tteNo);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700999 UWord i, j, n, m;
1000 Int evCheckSzB = LibVEX_evCheckSzB(arch_host);
1001 TTEntryC* here_tteC = index_tteC(here_sNo, here_tteNo);
1002 TTEntryH* here_tteH = index_tteH(here_sNo, here_tteNo);
philippe3a532202013-02-24 23:16:58 +00001003 if (DEBUG_TRANSTAB)
florianddd61ff2015-01-04 17:20:45 +00001004 VG_(printf)("... QQQ tt.entry 0x%lu tt.tcptr 0x%p\n",
Elliott Hughesa0664b92017-04-18 17:46:52 -07001005 here_tteC->entry, here_tteC->tcptr);
1006 vg_assert(here_tteH->status == InUse);
sewardj291849f2012-04-20 23:58:55 +00001007
1008 /* Visit all InEdges owned by here_tte. */
Elliott Hughesa0664b92017-04-18 17:46:52 -07001009 n = InEdgeArr__size(&here_tteC->in_edges);
sewardj291849f2012-04-20 23:58:55 +00001010 for (i = 0; i < n; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001011 InEdge* ie = InEdgeArr__index(&here_tteC->in_edges, i);
sewardj291849f2012-04-20 23:58:55 +00001012 // Undo the chaining.
Elliott Hughesa0664b92017-04-18 17:46:52 -07001013 UChar* here_slow_EP = (UChar*)here_tteC->tcptr;
sewardj291849f2012-04-20 23:58:55 +00001014 UChar* here_fast_EP = here_slow_EP + evCheckSzB;
sewardj59731422014-07-24 12:45:24 +00001015 unchain_one(arch_host, endness_host, ie, here_fast_EP, here_slow_EP);
sewardj291849f2012-04-20 23:58:55 +00001016 // Find the corresponding entry in the "from" node's out_edges,
1017 // and remove it.
Elliott Hughesa0664b92017-04-18 17:46:52 -07001018 TTEntryC* from_tteC = index_tteC(ie->from_sNo, ie->from_tteNo);
1019 m = OutEdgeArr__size(&from_tteC->out_edges);
sewardj291849f2012-04-20 23:58:55 +00001020 vg_assert(m > 0); // it must have at least one entry
1021 for (j = 0; j < m; j++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001022 OutEdge* oe = OutEdgeArr__index(&from_tteC->out_edges, j);
sewardj291849f2012-04-20 23:58:55 +00001023 if (oe->to_sNo == here_sNo && oe->to_tteNo == here_tteNo
1024 && oe->from_offs == ie->from_offs)
1025 break;
1026 }
1027 vg_assert(j < m); // "oe must be findable"
Elliott Hughesa0664b92017-04-18 17:46:52 -07001028 OutEdgeArr__deleteIndex(&from_tteC->out_edges, j);
sewardj291849f2012-04-20 23:58:55 +00001029 }
1030
1031 /* Visit all OutEdges owned by here_tte. */
Elliott Hughesa0664b92017-04-18 17:46:52 -07001032 n = OutEdgeArr__size(&here_tteC->out_edges);
sewardj291849f2012-04-20 23:58:55 +00001033 for (i = 0; i < n; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001034 OutEdge* oe = OutEdgeArr__index(&here_tteC->out_edges, i);
sewardj291849f2012-04-20 23:58:55 +00001035 // Find the corresponding entry in the "to" node's in_edges,
1036 // and remove it.
Elliott Hughesa0664b92017-04-18 17:46:52 -07001037 TTEntryC* to_tteC = index_tteC(oe->to_sNo, oe->to_tteNo);
1038 m = InEdgeArr__size(&to_tteC->in_edges);
sewardj291849f2012-04-20 23:58:55 +00001039 vg_assert(m > 0); // it must have at least one entry
1040 for (j = 0; j < m; j++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001041 InEdge* ie = InEdgeArr__index(&to_tteC->in_edges, j);
sewardj291849f2012-04-20 23:58:55 +00001042 if (ie->from_sNo == here_sNo && ie->from_tteNo == here_tteNo
1043 && ie->from_offs == oe->from_offs)
1044 break;
1045 }
1046 vg_assert(j < m); // "ie must be findable"
Elliott Hughesa0664b92017-04-18 17:46:52 -07001047 InEdgeArr__deleteIndex(&to_tteC->in_edges, j);
sewardj291849f2012-04-20 23:58:55 +00001048 }
1049
Elliott Hughesa0664b92017-04-18 17:46:52 -07001050 InEdgeArr__makeEmpty(&here_tteC->in_edges);
1051 OutEdgeArr__makeEmpty(&here_tteC->out_edges);
sewardj291849f2012-04-20 23:58:55 +00001052}
sewardjfa8ec112005-01-19 11:55:34 +00001053
1054
sewardj6c1bbbb2005-10-18 02:30:42 +00001055/*-------------------------------------------------------------*/
1056/*--- Address-range equivalence class stuff ---*/
1057/*-------------------------------------------------------------*/
1058
1059/* Return equivalence class number for a range. */
1060
philipped28615c2015-03-31 20:38:52 +00001061static EClassNo range_to_eclass ( Addr start, UInt len )
sewardj6c1bbbb2005-10-18 02:30:42 +00001062{
1063 UInt mask = (1 << ECLASS_WIDTH) - 1;
1064 UInt lo = (UInt)start;
1065 UInt hi = lo + len - 1;
1066 UInt loBits = (lo >> ECLASS_SHIFT) & mask;
1067 UInt hiBits = (hi >> ECLASS_SHIFT) & mask;
1068 if (loBits == hiBits) {
1069 vg_assert(loBits < ECLASS_N-1);
1070 return loBits;
1071 } else {
1072 return ECLASS_MISC;
1073 }
1074}
1075
1076
1077/* Calculates the equivalence class numbers for any VexGuestExtent.
1078 These are written in *eclasses, which must be big enough to hold 3
1079 Ints. The number written, between 1 and 3, is returned. The
1080 eclasses are presented in order, and any duplicates are removed.
1081*/
1082
1083static
philipped28615c2015-03-31 20:38:52 +00001084Int vexGuestExtents_to_eclasses ( /*OUT*/EClassNo* eclasses,
Elliott Hughesa0664b92017-04-18 17:46:52 -07001085 const TTEntryH* tteH )
sewardj6c1bbbb2005-10-18 02:30:42 +00001086{
florian518850b2014-10-22 22:25:30 +00001087
sewardj6c1bbbb2005-10-18 02:30:42 +00001088# define SWAP(_lv1,_lv2) \
1089 do { Int t = _lv1; _lv1 = _lv2; _lv2 = t; } while (0)
1090
Elliott Hughesa0664b92017-04-18 17:46:52 -07001091 UInt i, j, n_ec;
philipped28615c2015-03-31 20:38:52 +00001092 EClassNo r;
sewardj6c1bbbb2005-10-18 02:30:42 +00001093
Elliott Hughesa0664b92017-04-18 17:46:52 -07001094 vg_assert(tteH->vge_n_used >= 1 && tteH->vge_n_used <= 3);
sewardj6c1bbbb2005-10-18 02:30:42 +00001095
1096 n_ec = 0;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001097 for (i = 0; i < tteH->vge_n_used; i++) {
1098 r = range_to_eclass( tteH->vge_base[i], tteH->vge_len[i] );
sewardj6c1bbbb2005-10-18 02:30:42 +00001099 if (r == ECLASS_MISC)
1100 goto bad;
1101 /* only add if we haven't already seen it */
1102 for (j = 0; j < n_ec; j++)
1103 if (eclasses[j] == r)
1104 break;
1105 if (j == n_ec)
1106 eclasses[n_ec++] = r;
1107 }
1108
1109 if (n_ec == 1)
1110 return 1;
1111
1112 if (n_ec == 2) {
1113 /* sort */
1114 if (eclasses[0] > eclasses[1])
1115 SWAP(eclasses[0], eclasses[1]);
1116 return 2;
1117 }
1118
1119 if (n_ec == 3) {
1120 /* sort */
1121 if (eclasses[0] > eclasses[2])
1122 SWAP(eclasses[0], eclasses[2]);
1123 if (eclasses[0] > eclasses[1])
1124 SWAP(eclasses[0], eclasses[1]);
1125 if (eclasses[1] > eclasses[2])
1126 SWAP(eclasses[1], eclasses[2]);
1127 return 3;
1128 }
1129
1130 /* NOTREACHED */
1131 vg_assert(0);
1132
1133 bad:
1134 eclasses[0] = ECLASS_MISC;
1135 return 1;
1136
1137# undef SWAP
1138}
1139
1140
1141/* Add tteno to the set of entries listed for equivalence class ec in
1142 this sector. Returns used location in eclass array. */
1143
1144static
philipped28615c2015-03-31 20:38:52 +00001145UInt addEClassNo ( /*MOD*/Sector* sec, EClassNo ec, TTEno tteno )
sewardj6c1bbbb2005-10-18 02:30:42 +00001146{
1147 Int old_sz, new_sz, i, r;
philippe523b5b82015-03-23 21:49:32 +00001148 TTEno *old_ar, *new_ar;
sewardj6c1bbbb2005-10-18 02:30:42 +00001149
1150 vg_assert(ec >= 0 && ec < ECLASS_N);
1151 vg_assert(tteno < N_TTES_PER_SECTOR);
1152
philippe3a532202013-02-24 23:16:58 +00001153 if (DEBUG_TRANSTAB) VG_(printf)("ec %d gets %d\n", ec, (Int)tteno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001154
1155 if (sec->ec2tte_used[ec] >= sec->ec2tte_size[ec]) {
1156
1157 vg_assert(sec->ec2tte_used[ec] == sec->ec2tte_size[ec]);
1158
1159 old_sz = sec->ec2tte_size[ec];
1160 old_ar = sec->ec2tte[ec];
1161 new_sz = old_sz==0 ? 8 : old_sz<64 ? 2*old_sz : (3*old_sz)/2;
sewardj291849f2012-04-20 23:58:55 +00001162 new_ar = ttaux_malloc("transtab.aECN.1",
philippe523b5b82015-03-23 21:49:32 +00001163 new_sz * sizeof(TTEno));
sewardj6c1bbbb2005-10-18 02:30:42 +00001164 for (i = 0; i < old_sz; i++)
1165 new_ar[i] = old_ar[i];
1166 if (old_ar)
sewardj291849f2012-04-20 23:58:55 +00001167 ttaux_free(old_ar);
sewardj6c1bbbb2005-10-18 02:30:42 +00001168 sec->ec2tte_size[ec] = new_sz;
1169 sec->ec2tte[ec] = new_ar;
1170
philippe3a532202013-02-24 23:16:58 +00001171 if (DEBUG_TRANSTAB) VG_(printf)("expand ec %d to %d\n", ec, new_sz);
sewardj6c1bbbb2005-10-18 02:30:42 +00001172 }
1173
1174 /* Common case */
1175 r = sec->ec2tte_used[ec]++;
1176 vg_assert(r >= 0 && r < sec->ec2tte_size[ec]);
1177 sec->ec2tte[ec][r] = tteno;
1178 return (UInt)r;
1179}
1180
1181
1182/* 'vge' is being added to 'sec' at TT entry 'tteno'. Add appropriate
1183 eclass entries to 'sec'. */
1184
1185static
philippe523b5b82015-03-23 21:49:32 +00001186void upd_eclasses_after_add ( /*MOD*/Sector* sec, TTEno tteno )
sewardj6c1bbbb2005-10-18 02:30:42 +00001187{
philipped28615c2015-03-31 20:38:52 +00001188 Int i, r;
1189 EClassNo eclasses[3];
sewardj6c1bbbb2005-10-18 02:30:42 +00001190 vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
1191
Elliott Hughesa0664b92017-04-18 17:46:52 -07001192 TTEntryH* tteH = &sec->ttH[tteno];
1193 r = vexGuestExtents_to_eclasses( eclasses, tteH );
sewardj6c1bbbb2005-10-18 02:30:42 +00001194 vg_assert(r >= 1 && r <= 3);
sewardj6c1bbbb2005-10-18 02:30:42 +00001195
Elliott Hughesa0664b92017-04-18 17:46:52 -07001196 TTEntryC* tteC = &sec->ttC[tteno];
1197 tteC->n_tte2ec = r;
sewardj6c1bbbb2005-10-18 02:30:42 +00001198 for (i = 0; i < r; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001199 tteC->tte2ec_ec[i] = eclasses[i];
1200 tteC->tte2ec_ix[i] = addEClassNo( sec, eclasses[i], tteno );
sewardj6c1bbbb2005-10-18 02:30:42 +00001201 }
1202}
1203
1204
1205/* Check the eclass info in 'sec' to ensure it is consistent. Returns
1206 True if OK, False if something's not right. Expensive. */
1207
florian518850b2014-10-22 22:25:30 +00001208static Bool sanity_check_eclasses_in_sector ( const Sector* sec )
sewardj6c1bbbb2005-10-18 02:30:42 +00001209{
1210# define BAD(_str) do { whassup = (_str); goto bad; } while (0)
1211
florian6bd9dc12012-11-23 16:17:43 +00001212 const HChar* whassup = NULL;
philipped28615c2015-03-31 20:38:52 +00001213 Int j, k, n, ec_idx;
1214 EClassNo i;
1215 EClassNo ec_num;
philippe523b5b82015-03-23 21:49:32 +00001216 TTEno tteno;
sewardj6c1bbbb2005-10-18 02:30:42 +00001217 ULong* tce;
1218
1219 /* Basic checks on this sector */
philippebece82e2015-03-19 22:17:08 +00001220 if (sec->tt_n_inuse < 0 || sec->tt_n_inuse > N_TTES_PER_SECTOR)
sewardj6c1bbbb2005-10-18 02:30:42 +00001221 BAD("invalid sec->tt_n_inuse");
1222 tce = sec->tc_next;
1223 if (tce < &sec->tc[0] || tce > &sec->tc[tc_sector_szQ])
1224 BAD("sec->tc_next points outside tc");
1225
1226 /* For each eclass ... */
1227 for (i = 0; i < ECLASS_N; i++) {
1228 if (sec->ec2tte_size[i] == 0 && sec->ec2tte[i] != NULL)
1229 BAD("ec2tte_size/ec2tte mismatch(1)");
1230 if (sec->ec2tte_size[i] != 0 && sec->ec2tte[i] == NULL)
1231 BAD("ec2tte_size/ec2tte mismatch(2)");
1232 if (sec->ec2tte_used[i] < 0
1233 || sec->ec2tte_used[i] > sec->ec2tte_size[i])
1234 BAD("implausible ec2tte_used");
1235 if (sec->ec2tte_used[i] == 0)
1236 continue;
1237
1238 /* For each tt reference in each eclass .. ensure the reference
1239 is to a valid tt entry, and that the entry's address ranges
1240 really include this eclass. */
1241
1242 for (j = 0; j < sec->ec2tte_used[i]; j++) {
1243 tteno = sec->ec2tte[i][j];
1244 if (tteno == EC2TTE_DELETED)
1245 continue;
1246 if (tteno >= N_TTES_PER_SECTOR)
1247 BAD("implausible tteno");
Elliott Hughesa0664b92017-04-18 17:46:52 -07001248 TTEntryC* tteC = &sec->ttC[tteno];
1249 TTEntryH* tteH = &sec->ttH[tteno];
1250 if (tteH->status != InUse)
sewardj6c1bbbb2005-10-18 02:30:42 +00001251 BAD("tteno points to non-inuse tte");
Elliott Hughesa0664b92017-04-18 17:46:52 -07001252 if (tteC->n_tte2ec < 1 || tteC->n_tte2ec > 3)
1253 BAD("tteC->n_tte2ec out of range");
sewardj6c1bbbb2005-10-18 02:30:42 +00001254 /* Exactly least one of tte->eclasses[0 .. tte->n_eclasses-1]
1255 must equal i. Inspect tte's eclass info. */
1256 n = 0;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001257 for (k = 0; k < tteC->n_tte2ec; k++) {
1258 if (k < tteC->n_tte2ec-1
1259 && tteC->tte2ec_ec[k] >= tteC->tte2ec_ec[k+1])
1260 BAD("tteC->tte2ec_ec[..] out of order");
1261 ec_num = tteC->tte2ec_ec[k];
sewardj6c1bbbb2005-10-18 02:30:42 +00001262 if (ec_num < 0 || ec_num >= ECLASS_N)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001263 BAD("tteC->tte2ec_ec[..] out of range");
sewardj6c1bbbb2005-10-18 02:30:42 +00001264 if (ec_num != i)
1265 continue;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001266 ec_idx = tteC->tte2ec_ix[k];
sewardj6c1bbbb2005-10-18 02:30:42 +00001267 if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[i])
Elliott Hughesa0664b92017-04-18 17:46:52 -07001268 BAD("tteC->tte2ec_ix[..] out of range");
sewardj6c1bbbb2005-10-18 02:30:42 +00001269 if (ec_idx == j)
1270 n++;
1271 }
1272 if (n != 1)
1273 BAD("tteno does not point back at eclass");
1274 }
1275 }
1276
1277 /* That establishes that for each forward pointer from TTEntrys
1278 there is a corresponding backward pointer from the eclass[]
1279 arrays. However, it doesn't rule out the possibility of other,
1280 bogus pointers in the eclass[] arrays. So do those similarly:
1281 scan through them and check the TTEntryies they point at point
1282 back. */
1283
philippe523b5b82015-03-23 21:49:32 +00001284 for (tteno = 0; tteno < N_TTES_PER_SECTOR; tteno++) {
sewardj6c1bbbb2005-10-18 02:30:42 +00001285
Elliott Hughesa0664b92017-04-18 17:46:52 -07001286 TTEntryC* tteC = &sec->ttC[tteno];
1287 TTEntryH* tteH = &sec->ttH[tteno];
1288 if (tteH->status == Empty || tteH->status == Deleted) {
1289 if (tteC->n_tte2ec != 0)
1290 BAD("tteC->n_tte2ec nonzero for unused tte");
sewardj6c1bbbb2005-10-18 02:30:42 +00001291 continue;
1292 }
1293
Elliott Hughesa0664b92017-04-18 17:46:52 -07001294 vg_assert(tteH->status == InUse);
sewardj6c1bbbb2005-10-18 02:30:42 +00001295
Elliott Hughesa0664b92017-04-18 17:46:52 -07001296 if (tteC->n_tte2ec < 1 || tteC->n_tte2ec > 3)
1297 BAD("tteC->n_tte2ec out of range(2)");
sewardj6c1bbbb2005-10-18 02:30:42 +00001298
Elliott Hughesa0664b92017-04-18 17:46:52 -07001299 for (j = 0; j < tteC->n_tte2ec; j++) {
1300 ec_num = tteC->tte2ec_ec[j];
sewardj6c1bbbb2005-10-18 02:30:42 +00001301 if (ec_num < 0 || ec_num >= ECLASS_N)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001302 BAD("tteC->tte2ec_ec[..] out of range");
1303 ec_idx = tteC->tte2ec_ix[j];
sewardj6c1bbbb2005-10-18 02:30:42 +00001304 if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[ec_num])
Elliott Hughesa0664b92017-04-18 17:46:52 -07001305 BAD("tteC->tte2ec_ix[..] out of range(2)");
philippe523b5b82015-03-23 21:49:32 +00001306 if (sec->ec2tte[ec_num][ec_idx] != tteno)
sewardj6c1bbbb2005-10-18 02:30:42 +00001307 BAD("ec2tte does not point back to tte");
1308 }
1309 }
1310
1311 return True;
1312
1313 bad:
1314 if (whassup)
1315 VG_(debugLog)(0, "transtab", "eclass sanity fail: %s\n", whassup);
1316
1317# if 0
1318 VG_(printf)("eclass = %d\n", i);
1319 VG_(printf)("tteno = %d\n", (Int)tteno);
1320 switch (tte->status) {
1321 case InUse: VG_(printf)("InUse\n"); break;
1322 case Deleted: VG_(printf)("Deleted\n"); break;
1323 case Empty: VG_(printf)("Empty\n"); break;
1324 }
1325 if (tte->status != Empty) {
1326 for (k = 0; k < tte->vge.n_used; k++)
florianddd61ff2015-01-04 17:20:45 +00001327 VG_(printf)("0x%lx %u\n", tte->vge.base[k], (UInt)tte->vge.len[k]);
sewardj6c1bbbb2005-10-18 02:30:42 +00001328 }
1329# endif
1330
1331 return False;
1332
1333# undef BAD
1334}
1335
1336
1337/* Sanity check absolutely everything. True == check passed. */
1338
sewardj5f76de02007-02-11 05:08:06 +00001339/* forwards */
sewardj0ec07f32006-01-12 12:32:32 +00001340static Bool sanity_check_redir_tt_tc ( void );
1341
sewardj5d0d1f32010-03-14 15:09:27 +00001342static Bool sanity_check_sector_search_order ( void )
1343{
philippe523b5b82015-03-23 21:49:32 +00001344 SECno i, j, nListed;
sewardj5d0d1f32010-03-14 15:09:27 +00001345 /* assert the array is the right size */
philippe8e1bee42013-10-18 00:08:20 +00001346 vg_assert(MAX_N_SECTORS == (sizeof(sector_search_order)
1347 / sizeof(sector_search_order[0])));
philippe523b5b82015-03-23 21:49:32 +00001348 /* Check it's of the form valid_sector_numbers ++ [INV_SNO, INV_SNO, ..] */
philippe8e1bee42013-10-18 00:08:20 +00001349 for (i = 0; i < n_sectors; i++) {
philippe523b5b82015-03-23 21:49:32 +00001350 if (sector_search_order[i] == INV_SNO
1351 || sector_search_order[i] >= n_sectors)
sewardj5d0d1f32010-03-14 15:09:27 +00001352 break;
1353 }
1354 nListed = i;
philippe8e1bee42013-10-18 00:08:20 +00001355 for (/* */; i < n_sectors; i++) {
philippe523b5b82015-03-23 21:49:32 +00001356 if (sector_search_order[i] != INV_SNO)
sewardj5d0d1f32010-03-14 15:09:27 +00001357 break;
1358 }
philippe8e1bee42013-10-18 00:08:20 +00001359 if (i != n_sectors)
sewardj5d0d1f32010-03-14 15:09:27 +00001360 return False;
1361 /* Check each sector number only appears once */
philippe8e1bee42013-10-18 00:08:20 +00001362 for (i = 0; i < n_sectors; i++) {
philippe523b5b82015-03-23 21:49:32 +00001363 if (sector_search_order[i] == INV_SNO)
sewardj5d0d1f32010-03-14 15:09:27 +00001364 continue;
philippe8e1bee42013-10-18 00:08:20 +00001365 for (j = i+1; j < n_sectors; j++) {
sewardj5d0d1f32010-03-14 15:09:27 +00001366 if (sector_search_order[j] == sector_search_order[i])
1367 return False;
1368 }
1369 }
1370 /* Check that the number of listed sectors equals the number
1371 in use, by counting nListed back down. */
philippe8e1bee42013-10-18 00:08:20 +00001372 for (i = 0; i < n_sectors; i++) {
sewardj5d0d1f32010-03-14 15:09:27 +00001373 if (sectors[i].tc != NULL)
1374 nListed--;
1375 }
1376 if (nListed != 0)
1377 return False;
1378 return True;
1379}
1380
sewardj6c1bbbb2005-10-18 02:30:42 +00001381static Bool sanity_check_all_sectors ( void )
1382{
philippe523b5b82015-03-23 21:49:32 +00001383 SECno sno;
sewardj6c1bbbb2005-10-18 02:30:42 +00001384 Bool sane;
1385 Sector* sec;
philippe8e1bee42013-10-18 00:08:20 +00001386 for (sno = 0; sno < n_sectors; sno++) {
philippe3a532202013-02-24 23:16:58 +00001387 Int i;
1388 Int nr_not_dead_hx = 0;
1389 Int szhxa;
sewardj6c1bbbb2005-10-18 02:30:42 +00001390 sec = &sectors[sno];
1391 if (sec->tc == NULL)
1392 continue;
1393 sane = sanity_check_eclasses_in_sector( sec );
1394 if (!sane)
1395 return False;
philippe3a532202013-02-24 23:16:58 +00001396 szhxa = VG_(sizeXA)(sec->host_extents);
1397 for (i = 0; i < szhxa; i++) {
1398 const HostExtent* hx = VG_(indexXA)(sec->host_extents, i);
1399 if (!HostExtent__is_dead (hx, sec))
1400 nr_not_dead_hx++;
1401 }
1402 if (nr_not_dead_hx != sec->tt_n_inuse) {
1403 VG_(debugLog)(0, "transtab",
philippe523b5b82015-03-23 21:49:32 +00001404 "nr_not_dead_hx %d sanity fail "
1405 "(expected == in use %d)\n",
philippe3a532202013-02-24 23:16:58 +00001406 nr_not_dead_hx, sec->tt_n_inuse);
1407 return False;
1408 }
sewardj6c1bbbb2005-10-18 02:30:42 +00001409 }
philippe3a532202013-02-24 23:16:58 +00001410
sewardj5f76de02007-02-11 05:08:06 +00001411 if ( !sanity_check_redir_tt_tc() )
1412 return False;
sewardj5d0d1f32010-03-14 15:09:27 +00001413 if ( !sanity_check_sector_search_order() )
1414 return False;
sewardj6c1bbbb2005-10-18 02:30:42 +00001415 return True;
1416}
1417
sewardjfa8ec112005-01-19 11:55:34 +00001418
sewardj5d0d1f32010-03-14 15:09:27 +00001419
sewardjfa8ec112005-01-19 11:55:34 +00001420/*-------------------------------------------------------------*/
sewardj6c1bbbb2005-10-18 02:30:42 +00001421/*--- Add/find translations ---*/
sewardjfa8ec112005-01-19 11:55:34 +00001422/*-------------------------------------------------------------*/
1423
florian518850b2014-10-22 22:25:30 +00001424static UInt vge_osize ( const VexGuestExtents* vge )
sewardjc0d8f682002-11-30 00:49:43 +00001425{
sewardjfa8ec112005-01-19 11:55:34 +00001426 UInt i, n = 0;
1427 for (i = 0; i < vge->n_used; i++)
1428 n += (UInt)vge->len[i];
1429 return n;
sewardjc0d8f682002-11-30 00:49:43 +00001430}
1431
Elliott Hughesa0664b92017-04-18 17:46:52 -07001432static UInt TTEntryH__osize ( const TTEntryH* tteH )
1433{
1434 UInt i, n = 0;
1435 for (i = 0; i < tteH->vge_n_used; i++)
1436 n += (UInt)tteH->vge_len[i];
1437 return n;
1438}
1439
philippe523b5b82015-03-23 21:49:32 +00001440static Bool isValidSector ( SECno sector )
sewardj6c3769f2002-11-29 01:02:45 +00001441{
philippe523b5b82015-03-23 21:49:32 +00001442 if (sector == INV_SNO || sector >= n_sectors)
sewardjfa8ec112005-01-19 11:55:34 +00001443 return False;
1444 return True;
1445}
1446
philippe523b5b82015-03-23 21:49:32 +00001447static inline HTTno HASH_TT ( Addr key )
sewardjfa8ec112005-01-19 11:55:34 +00001448{
florianddd61ff2015-01-04 17:20:45 +00001449 UInt kHi = sizeof(Addr) == 4 ? 0 : (key >> 32);
sewardjfa8ec112005-01-19 11:55:34 +00001450 UInt kLo = (UInt)key;
sewardj6c1bbbb2005-10-18 02:30:42 +00001451 UInt k32 = kHi ^ kLo;
1452 UInt ror = 7;
1453 if (ror > 0)
1454 k32 = (k32 >> ror) | (k32 << (32-ror));
philippe523b5b82015-03-23 21:49:32 +00001455 return (HTTno)(k32 % N_HTTES_PER_SECTOR);
sewardjfa8ec112005-01-19 11:55:34 +00001456}
1457
florianddd61ff2015-01-04 17:20:45 +00001458static void setFastCacheEntry ( Addr key, ULong* tcptr )
sewardjfa8ec112005-01-19 11:55:34 +00001459{
sewardj3387dda2005-12-26 17:58:58 +00001460 UInt cno = (UInt)VG_TT_FAST_HASH(key);
florianddd61ff2015-01-04 17:20:45 +00001461 VG_(tt_fast)[cno].guest = key;
sewardj5f76de02007-02-11 05:08:06 +00001462 VG_(tt_fast)[cno].host = (Addr)tcptr;
sewardjfa8ec112005-01-19 11:55:34 +00001463 n_fast_updates++;
sewardj5f76de02007-02-11 05:08:06 +00001464 /* This shouldn't fail. It should be assured by m_translate
1465 which should reject any attempt to make translation of code
1466 starting at TRANSTAB_BOGUS_GUEST_ADDR. */
1467 vg_assert(VG_(tt_fast)[cno].guest != TRANSTAB_BOGUS_GUEST_ADDR);
sewardjfa8ec112005-01-19 11:55:34 +00001468}
1469
sewardj291849f2012-04-20 23:58:55 +00001470/* Invalidate the fast cache VG_(tt_fast). */
sewardjfa8ec112005-01-19 11:55:34 +00001471static void invalidateFastCache ( void )
1472{
1473 UInt j;
sewardj65e19392005-10-19 01:32:41 +00001474 /* This loop is popular enough to make it worth unrolling a
1475 bit, at least on ppc32. */
1476 vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
1477 for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
sewardj5f76de02007-02-11 05:08:06 +00001478 VG_(tt_fast)[j+0].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1479 VG_(tt_fast)[j+1].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1480 VG_(tt_fast)[j+2].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1481 VG_(tt_fast)[j+3].guest = TRANSTAB_BOGUS_GUEST_ADDR;
sewardjfa8ec112005-01-19 11:55:34 +00001482 }
sewardj5f76de02007-02-11 05:08:06 +00001483
sewardj65e19392005-10-19 01:32:41 +00001484 vg_assert(j == VG_TT_FAST_SIZE);
sewardjfa8ec112005-01-19 11:55:34 +00001485 n_fast_flushes++;
1486}
1487
philippebece82e2015-03-19 22:17:08 +00001488
philippe523b5b82015-03-23 21:49:32 +00001489static TTEno get_empty_tt_slot(SECno sNo)
philippebece82e2015-03-19 22:17:08 +00001490{
philippe523b5b82015-03-23 21:49:32 +00001491 TTEno i;
philippebece82e2015-03-19 22:17:08 +00001492
1493 i = sectors[sNo].empty_tt_list;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001494 sectors[sNo].empty_tt_list = sectors[sNo].ttC[i].usage.next_empty_tte;
philippebece82e2015-03-19 22:17:08 +00001495
1496 vg_assert (i >= 0 && i < N_TTES_PER_SECTOR);
1497
1498 return i;
1499}
1500
Elliott Hughesa0664b92017-04-18 17:46:52 -07001501static void add_to_empty_tt_list (SECno sNo, TTEno tteno)
philippebece82e2015-03-19 22:17:08 +00001502{
Elliott Hughesa0664b92017-04-18 17:46:52 -07001503 sectors[sNo].ttC[tteno].usage.next_empty_tte = sectors[sNo].empty_tt_list;
philippebece82e2015-03-19 22:17:08 +00001504 sectors[sNo].empty_tt_list = tteno;
1505}
1506
philippe523b5b82015-03-23 21:49:32 +00001507static void initialiseSector ( SECno sno )
sewardjfa8ec112005-01-19 11:55:34 +00001508{
philippe523b5b82015-03-23 21:49:32 +00001509 UInt i;
sewardj291849f2012-04-20 23:58:55 +00001510 SysRes sres;
sewardj6c1bbbb2005-10-18 02:30:42 +00001511 Sector* sec;
sewardjfa8ec112005-01-19 11:55:34 +00001512 vg_assert(isValidSector(sno));
1513
sewardj5d0d1f32010-03-14 15:09:27 +00001514 { Bool sane = sanity_check_sector_search_order();
1515 vg_assert(sane);
1516 }
sewardj6c1bbbb2005-10-18 02:30:42 +00001517 sec = &sectors[sno];
1518
1519 if (sec->tc == NULL) {
1520
sewardjfa8ec112005-01-19 11:55:34 +00001521 /* Sector has never been used before. Need to allocate tt and
1522 tc. */
Elliott Hughesa0664b92017-04-18 17:46:52 -07001523 vg_assert(sec->ttC == NULL);
1524 vg_assert(sec->ttH == NULL);
sewardj6c1bbbb2005-10-18 02:30:42 +00001525 vg_assert(sec->tc_next == NULL);
1526 vg_assert(sec->tt_n_inuse == 0);
philipped28615c2015-03-31 20:38:52 +00001527 for (EClassNo e = 0; e < ECLASS_N; e++) {
1528 vg_assert(sec->ec2tte_size[e] == 0);
1529 vg_assert(sec->ec2tte_used[e] == 0);
1530 vg_assert(sec->ec2tte[e] == NULL);
sewardj6c1bbbb2005-10-18 02:30:42 +00001531 }
sewardj291849f2012-04-20 23:58:55 +00001532 vg_assert(sec->host_extents == NULL);
sewardj45f4e7c2005-09-27 19:20:21 +00001533
philippe5e47e3f2015-03-12 22:36:22 +00001534 if (VG_(clo_stats) || VG_(debugLog_getLevel)() >= 1)
sewardj059838b2012-12-17 12:44:03 +00001535 VG_(dmsg)("transtab: " "allocate sector %d\n", sno);
sewardj45f4e7c2005-09-27 19:20:21 +00001536
1537 sres = VG_(am_mmap_anon_float_valgrind)( 8 * tc_sector_szQ );
njncda2f0f2009-05-18 02:12:08 +00001538 if (sr_isError(sres)) {
sewardj45f4e7c2005-09-27 19:20:21 +00001539 VG_(out_of_memory_NORETURN)("initialiseSector(TC)",
1540 8 * tc_sector_szQ );
1541 /*NOTREACHED*/
1542 }
florian44bd4462014-12-29 17:04:46 +00001543 sec->tc = (ULong*)(Addr)sr_Res(sres);
sewardj45f4e7c2005-09-27 19:20:21 +00001544
1545 sres = VG_(am_mmap_anon_float_valgrind)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001546 ( N_TTES_PER_SECTOR * sizeof(TTEntryC) );
njncda2f0f2009-05-18 02:12:08 +00001547 if (sr_isError(sres)) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001548 VG_(out_of_memory_NORETURN)("initialiseSector(TTC)",
1549 N_TTES_PER_SECTOR * sizeof(TTEntryC) );
sewardj45f4e7c2005-09-27 19:20:21 +00001550 /*NOTREACHED*/
1551 }
Elliott Hughesa0664b92017-04-18 17:46:52 -07001552 sec->ttC = (TTEntryC*)(Addr)sr_Res(sres);
1553
1554 sres = VG_(am_mmap_anon_float_valgrind)
1555 ( N_TTES_PER_SECTOR * sizeof(TTEntryH) );
1556 if (sr_isError(sres)) {
1557 VG_(out_of_memory_NORETURN)("initialiseSector(TTH)",
1558 N_TTES_PER_SECTOR * sizeof(TTEntryH) );
1559 /*NOTREACHED*/
1560 }
1561 sec->ttH = (TTEntryH*)(Addr)sr_Res(sres);
1562
philippebece82e2015-03-19 22:17:08 +00001563 sec->empty_tt_list = HTT_EMPTY;
philippe523b5b82015-03-23 21:49:32 +00001564 for (TTEno ei = 0; ei < N_TTES_PER_SECTOR; ei++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001565 sec->ttH[ei].status = Empty;
1566 sec->ttC[ei].n_tte2ec = 0;
1567 add_to_empty_tt_list(sno, ei);
sewardj6c1bbbb2005-10-18 02:30:42 +00001568 }
philippe523b5b82015-03-23 21:49:32 +00001569
1570 sres = VG_(am_mmap_anon_float_valgrind)
1571 ( N_HTTES_PER_SECTOR * sizeof(TTEno) );
1572 if (sr_isError(sres)) {
1573 VG_(out_of_memory_NORETURN)("initialiseSector(HTT)",
1574 N_HTTES_PER_SECTOR * sizeof(TTEno) );
1575 /*NOTREACHED*/
1576 }
1577 sec->htt = (TTEno*)(Addr)sr_Res(sres);
1578 for (HTTno hi = 0; hi < N_HTTES_PER_SECTOR; hi++)
1579 sec->htt[hi] = HTT_EMPTY;
sewardj45f4e7c2005-09-27 19:20:21 +00001580
sewardj291849f2012-04-20 23:58:55 +00001581 /* Set up the host_extents array. */
1582 sec->host_extents
1583 = VG_(newXA)(ttaux_malloc, "transtab.initialiseSector(host_extents)",
1584 ttaux_free,
1585 sizeof(HostExtent));
1586
sewardj5d0d1f32010-03-14 15:09:27 +00001587 /* Add an entry in the sector_search_order */
philippe8e1bee42013-10-18 00:08:20 +00001588 for (i = 0; i < n_sectors; i++) {
philippe523b5b82015-03-23 21:49:32 +00001589 if (sector_search_order[i] == INV_SNO)
sewardj5d0d1f32010-03-14 15:09:27 +00001590 break;
1591 }
philippe8e1bee42013-10-18 00:08:20 +00001592 vg_assert(i >= 0 && i < n_sectors);
sewardj5d0d1f32010-03-14 15:09:27 +00001593 sector_search_order[i] = sno;
1594
sewardjfa8ec112005-01-19 11:55:34 +00001595 if (VG_(clo_verbosity) > 2)
sewardj738856f2009-07-15 14:48:32 +00001596 VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d\n", sno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001597
sewardjfa8ec112005-01-19 11:55:34 +00001598 } else {
sewardj6c1bbbb2005-10-18 02:30:42 +00001599
1600 /* Sector has been used before. Dump the old contents. */
philippe5e47e3f2015-03-12 22:36:22 +00001601 if (VG_(clo_stats) || VG_(debugLog_getLevel)() >= 1)
sewardj1bb648d2015-03-05 11:28:57 +00001602 VG_(dmsg)("transtab: " "recycle sector %d\n", sno);
philippe5e47e3f2015-03-12 22:36:22 +00001603 n_sectors_recycled++;
sewardj059838b2012-12-17 12:44:03 +00001604
Elliott Hughesa0664b92017-04-18 17:46:52 -07001605 vg_assert(sec->ttC != NULL);
1606 vg_assert(sec->ttH != NULL);
sewardj6c1bbbb2005-10-18 02:30:42 +00001607 vg_assert(sec->tc_next != NULL);
1608 n_dump_count += sec->tt_n_inuse;
1609
sewardj59731422014-07-24 12:45:24 +00001610 VexArch arch_host = VexArch_INVALID;
1611 VexArchInfo archinfo_host;
1612 VG_(bzero_inline)(&archinfo_host, sizeof(archinfo_host));
1613 VG_(machine_get_VexArchInfo)( &arch_host, &archinfo_host );
1614 VexEndness endness_host = archinfo_host.endness;
sewardj291849f2012-04-20 23:58:55 +00001615
sewardj6c1bbbb2005-10-18 02:30:42 +00001616 /* Visit each just-about-to-be-abandoned translation. */
philippe3a532202013-02-24 23:16:58 +00001617 if (DEBUG_TRANSTAB) VG_(printf)("QQQ unlink-entire-sector: %d START\n",
1618 sno);
philippebece82e2015-03-19 22:17:08 +00001619 sec->empty_tt_list = HTT_EMPTY;
philippe523b5b82015-03-23 21:49:32 +00001620 for (TTEno ei = 0; ei < N_TTES_PER_SECTOR; ei++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001621 if (sec->ttH[ei].status == InUse) {
1622 vg_assert(sec->ttC[ei].n_tte2ec >= 1);
1623 vg_assert(sec->ttC[ei].n_tte2ec <= 3);
1624 n_dump_osize += TTEntryH__osize(&sec->ttH[ei]);
sewardj37867722005-10-12 10:51:01 +00001625 /* Tell the tool too. */
sewardj0b9d74a2006-12-24 02:24:11 +00001626 if (VG_(needs).superblock_discards) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001627 VexGuestExtents vge_tmp;
1628 TTEntryH__to_VexGuestExtents( &vge_tmp, &sec->ttH[ei] );
sewardj0b9d74a2006-12-24 02:24:11 +00001629 VG_TDICT_CALL( tool_discard_superblock_info,
Elliott Hughesa0664b92017-04-18 17:46:52 -07001630 sec->ttC[ei].entry, vge_tmp );
sewardj37867722005-10-12 10:51:01 +00001631 }
sewardj59731422014-07-24 12:45:24 +00001632 unchain_in_preparation_for_deletion(arch_host,
philippe523b5b82015-03-23 21:49:32 +00001633 endness_host, sno, ei);
sewardj6c1bbbb2005-10-18 02:30:42 +00001634 } else {
Elliott Hughesa0664b92017-04-18 17:46:52 -07001635 vg_assert(sec->ttC[ei].n_tte2ec == 0);
sewardj6c1bbbb2005-10-18 02:30:42 +00001636 }
Elliott Hughesa0664b92017-04-18 17:46:52 -07001637 sec->ttH[ei].status = Empty;
1638 sec->ttC[ei].n_tte2ec = 0;
1639 add_to_empty_tt_list(sno, ei);
sewardj6c1bbbb2005-10-18 02:30:42 +00001640 }
philippe523b5b82015-03-23 21:49:32 +00001641 for (HTTno hi = 0; hi < N_HTTES_PER_SECTOR; hi++)
1642 sec->htt[hi] = HTT_EMPTY;
philippebece82e2015-03-19 22:17:08 +00001643
philippe3a532202013-02-24 23:16:58 +00001644 if (DEBUG_TRANSTAB) VG_(printf)("QQQ unlink-entire-sector: %d END\n",
1645 sno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001646
1647 /* Free up the eclass structures. */
philippeaa29de22015-04-01 18:15:42 +00001648 for (EClassNo e = 0; e < ECLASS_N; e++) {
philipped28615c2015-03-31 20:38:52 +00001649 if (sec->ec2tte_size[e] == 0) {
1650 vg_assert(sec->ec2tte_used[e] == 0);
1651 vg_assert(sec->ec2tte[e] == NULL);
sewardj6c1bbbb2005-10-18 02:30:42 +00001652 } else {
philipped28615c2015-03-31 20:38:52 +00001653 vg_assert(sec->ec2tte[e] != NULL);
1654 ttaux_free(sec->ec2tte[e]);
1655 sec->ec2tte[e] = NULL;
1656 sec->ec2tte_size[e] = 0;
1657 sec->ec2tte_used[e] = 0;
sewardjfa8ec112005-01-19 11:55:34 +00001658 }
1659 }
sewardj6c1bbbb2005-10-18 02:30:42 +00001660
sewardj291849f2012-04-20 23:58:55 +00001661 /* Empty out the host extents array. */
1662 vg_assert(sec->host_extents != NULL);
1663 VG_(dropTailXA)(sec->host_extents, VG_(sizeXA)(sec->host_extents));
1664 vg_assert(VG_(sizeXA)(sec->host_extents) == 0);
1665
sewardj5d0d1f32010-03-14 15:09:27 +00001666 /* Sanity check: ensure it is already in
1667 sector_search_order[]. */
philippe523b5b82015-03-23 21:49:32 +00001668 SECno ix;
1669 for (ix = 0; ix < n_sectors; ix++) {
1670 if (sector_search_order[ix] == sno)
sewardj5d0d1f32010-03-14 15:09:27 +00001671 break;
1672 }
philippe523b5b82015-03-23 21:49:32 +00001673 vg_assert(ix >= 0 && ix < n_sectors);
sewardj5d0d1f32010-03-14 15:09:27 +00001674
sewardjfa8ec112005-01-19 11:55:34 +00001675 if (VG_(clo_verbosity) > 2)
sewardj738856f2009-07-15 14:48:32 +00001676 VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d\n", sno);
sewardjfa8ec112005-01-19 11:55:34 +00001677 }
1678
sewardj6c1bbbb2005-10-18 02:30:42 +00001679 sec->tc_next = sec->tc;
1680 sec->tt_n_inuse = 0;
sewardjfa8ec112005-01-19 11:55:34 +00001681
1682 invalidateFastCache();
sewardj5d0d1f32010-03-14 15:09:27 +00001683
1684 { Bool sane = sanity_check_sector_search_order();
1685 vg_assert(sane);
1686 }
sewardj6c3769f2002-11-29 01:02:45 +00001687}
1688
sewardjfa8ec112005-01-19 11:55:34 +00001689/* Add a translation of vge to TT/TC. The translation is temporarily
1690 in code[0 .. code_len-1].
1691
1692 pre: youngest_sector points to a valid (although possibly full)
1693 sector.
1694*/
florian518850b2014-10-22 22:25:30 +00001695void VG_(add_to_transtab)( const VexGuestExtents* vge,
florianddd61ff2015-01-04 17:20:45 +00001696 Addr entry,
florian44bd4462014-12-29 17:04:46 +00001697 Addr code,
sewardj26412bd2005-07-07 10:05:05 +00001698 UInt code_len,
sewardj291849f2012-04-20 23:58:55 +00001699 Bool is_self_checking,
1700 Int offs_profInc,
sewardj59731422014-07-24 12:45:24 +00001701 UInt n_guest_instrs )
sewardj6c3769f2002-11-29 01:02:45 +00001702{
philippe523b5b82015-03-23 21:49:32 +00001703 Int tcAvailQ, reqdQ, y;
sewardj5f76de02007-02-11 05:08:06 +00001704 ULong *tcptr, *tcptr2;
sewardjfa8ec112005-01-19 11:55:34 +00001705 UChar* srcP;
1706 UChar* dstP;
1707
sewardj663a1bd2005-04-24 11:22:44 +00001708 vg_assert(init_done);
sewardjfa8ec112005-01-19 11:55:34 +00001709 vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
sewardje8089302006-10-17 02:15:17 +00001710
1711 /* 60000: should agree with N_TMPBUF in m_translate.c. */
1712 vg_assert(code_len > 0 && code_len < 60000);
sewardjfa8ec112005-01-19 11:55:34 +00001713
sewardjb7301c62012-04-24 11:50:49 +00001714 /* Generally stay sane */
1715 vg_assert(n_guest_instrs < 200); /* it can be zero, tho */
1716
philippe3a532202013-02-24 23:16:58 +00001717 if (DEBUG_TRANSTAB)
florianddd61ff2015-01-04 17:20:45 +00001718 VG_(printf)("add_to_transtab(entry = 0x%lx, len = %u) ...\n",
sewardjfa8ec112005-01-19 11:55:34 +00001719 entry, code_len);
1720
1721 n_in_count++;
1722 n_in_tsize += code_len;
1723 n_in_osize += vge_osize(vge);
sewardj26412bd2005-07-07 10:05:05 +00001724 if (is_self_checking)
1725 n_in_sc_count++;
sewardjfa8ec112005-01-19 11:55:34 +00001726
1727 y = youngest_sector;
1728 vg_assert(isValidSector(y));
1729
1730 if (sectors[y].tc == NULL)
1731 initialiseSector(y);
1732
1733 /* Try putting the translation in this sector. */
sewardj5f76de02007-02-11 05:08:06 +00001734 reqdQ = (code_len + 7) >> 3;
sewardjfa8ec112005-01-19 11:55:34 +00001735
1736 /* Will it fit in tc? */
1737 tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
1738 - ((ULong*)(sectors[y].tc_next));
1739 vg_assert(tcAvailQ >= 0);
1740 vg_assert(tcAvailQ <= tc_sector_szQ);
1741
1742 if (tcAvailQ < reqdQ
philippebece82e2015-03-19 22:17:08 +00001743 || sectors[y].tt_n_inuse >= N_TTES_PER_SECTOR) {
sewardjfa8ec112005-01-19 11:55:34 +00001744 /* No. So move on to the next sector. Either it's never been
1745 used before, in which case it will get its tt/tc allocated
1746 now, or it has been used before, in which case it is set to be
1747 empty, hence throwing out the oldest sector. */
sewardja16ea0a2005-09-30 10:34:06 +00001748 vg_assert(tc_sector_szQ > 0);
sewardj059838b2012-12-17 12:44:03 +00001749 Int tt_loading_pct = (100 * sectors[y].tt_n_inuse)
philippebece82e2015-03-19 22:17:08 +00001750 / N_HTTES_PER_SECTOR;
sewardj059838b2012-12-17 12:44:03 +00001751 Int tc_loading_pct = (100 * (tc_sector_szQ - tcAvailQ))
1752 / tc_sector_szQ;
philippe5e47e3f2015-03-12 22:36:22 +00001753 if (VG_(clo_stats) || VG_(debugLog_getLevel)() >= 1) {
sewardj059838b2012-12-17 12:44:03 +00001754 VG_(dmsg)("transtab: "
sewardj1bb648d2015-03-05 11:28:57 +00001755 "declare sector %d full "
philippe5e47e3f2015-03-12 22:36:22 +00001756 "(TT loading %2d%%, TC loading %2d%%, avg tce size %d)\n",
1757 y, tt_loading_pct, tc_loading_pct,
1758 8 * (tc_sector_szQ - tcAvailQ)/sectors[y].tt_n_inuse);
sewardj059838b2012-12-17 12:44:03 +00001759 }
sewardjfa8ec112005-01-19 11:55:34 +00001760 youngest_sector++;
philippe8e1bee42013-10-18 00:08:20 +00001761 if (youngest_sector >= n_sectors)
sewardjfa8ec112005-01-19 11:55:34 +00001762 youngest_sector = 0;
1763 y = youngest_sector;
1764 initialiseSector(y);
1765 }
1766
1767 /* Be sure ... */
1768 tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
1769 - ((ULong*)(sectors[y].tc_next));
1770 vg_assert(tcAvailQ >= 0);
1771 vg_assert(tcAvailQ <= tc_sector_szQ);
1772 vg_assert(tcAvailQ >= reqdQ);
philippebece82e2015-03-19 22:17:08 +00001773 vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR);
sewardjfa8ec112005-01-19 11:55:34 +00001774 vg_assert(sectors[y].tt_n_inuse >= 0);
1775
1776 /* Copy into tc. */
sewardj5f76de02007-02-11 05:08:06 +00001777 tcptr = sectors[y].tc_next;
1778 vg_assert(tcptr >= &sectors[y].tc[0]);
1779 vg_assert(tcptr <= &sectors[y].tc[tc_sector_szQ]);
sewardjfa8ec112005-01-19 11:55:34 +00001780
sewardj5f76de02007-02-11 05:08:06 +00001781 dstP = (UChar*)tcptr;
sewardjfa8ec112005-01-19 11:55:34 +00001782 srcP = (UChar*)code;
sewardj291849f2012-04-20 23:58:55 +00001783 VG_(memcpy)(dstP, srcP, code_len);
sewardjfa8ec112005-01-19 11:55:34 +00001784 sectors[y].tc_next += reqdQ;
1785 sectors[y].tt_n_inuse++;
1786
1787 /* more paranoia */
sewardj5f76de02007-02-11 05:08:06 +00001788 tcptr2 = sectors[y].tc_next;
1789 vg_assert(tcptr2 >= &sectors[y].tc[0]);
1790 vg_assert(tcptr2 <= &sectors[y].tc[tc_sector_szQ]);
sewardjfa8ec112005-01-19 11:55:34 +00001791
1792 /* Find an empty tt slot, and use it. There must be such a slot
1793 since tt is never allowed to get completely full. */
philippe523b5b82015-03-23 21:49:32 +00001794 TTEno tteix = get_empty_tt_slot(y);
Elliott Hughesa0664b92017-04-18 17:46:52 -07001795 TTEntryC__init(&sectors[y].ttC[tteix]);
1796 TTEntryH__init(&sectors[y].ttH[tteix]);
1797 sectors[y].ttC[tteix].tcptr = tcptr;
1798 sectors[y].ttC[tteix].usage.prof.count = 0;
1799 sectors[y].ttC[tteix].usage.prof.weight =
philippebece82e2015-03-19 22:17:08 +00001800 n_guest_instrs == 0 ? 1 : n_guest_instrs;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001801 sectors[y].ttC[tteix].entry = entry;
1802 TTEntryH__from_VexGuestExtents( &sectors[y].ttH[tteix], vge );
1803 sectors[y].ttH[tteix].status = InUse;
sewardjfa8ec112005-01-19 11:55:34 +00001804
philippebece82e2015-03-19 22:17:08 +00001805 // Point an htt entry to the tt slot
philippe523b5b82015-03-23 21:49:32 +00001806 HTTno htti = HASH_TT(entry);
philippebece82e2015-03-19 22:17:08 +00001807 vg_assert(htti >= 0 && htti < N_HTTES_PER_SECTOR);
1808 while (True) {
1809 if (sectors[y].htt[htti] == HTT_EMPTY
1810 || sectors[y].htt[htti] == HTT_DELETED)
1811 break;
1812 htti++;
1813 if (htti >= N_HTTES_PER_SECTOR)
1814 htti = 0;
1815 }
philippe523b5b82015-03-23 21:49:32 +00001816 sectors[y].htt[htti] = tteix;
philippebece82e2015-03-19 22:17:08 +00001817
sewardj291849f2012-04-20 23:58:55 +00001818 /* Patch in the profile counter location, if necessary. */
1819 if (offs_profInc != -1) {
1820 vg_assert(offs_profInc >= 0 && offs_profInc < code_len);
sewardj59731422014-07-24 12:45:24 +00001821 VexArch arch_host = VexArch_INVALID;
1822 VexArchInfo archinfo_host;
1823 VG_(bzero_inline)(&archinfo_host, sizeof(archinfo_host));
1824 VG_(machine_get_VexArchInfo)( &arch_host, &archinfo_host );
1825 VexEndness endness_host = archinfo_host.endness;
sewardj291849f2012-04-20 23:58:55 +00001826 VexInvalRange vir
sewardj59731422014-07-24 12:45:24 +00001827 = LibVEX_PatchProfInc( arch_host, endness_host,
sewardj291849f2012-04-20 23:58:55 +00001828 dstP + offs_profInc,
Elliott Hughesa0664b92017-04-18 17:46:52 -07001829 &sectors[y].ttC[tteix].usage.prof.count );
sewardj291849f2012-04-20 23:58:55 +00001830 VG_(invalidate_icache)( (void*)vir.start, vir.len );
1831 }
1832
1833 VG_(invalidate_icache)( dstP, code_len );
1834
1835 /* Add this entry to the host_extents map, checking that we're
1836 adding in order. */
1837 { HostExtent hx;
1838 hx.start = (UChar*)tcptr;
1839 hx.len = code_len;
philippe523b5b82015-03-23 21:49:32 +00001840 hx.tteNo = tteix;
sewardj291849f2012-04-20 23:58:55 +00001841 vg_assert(hx.len > 0); /* bsearch fails w/ zero length entries */
1842 XArray* hx_array = sectors[y].host_extents;
1843 vg_assert(hx_array);
1844 Word n = VG_(sizeXA)(hx_array);
1845 if (n > 0) {
1846 HostExtent* hx_prev = (HostExtent*)VG_(indexXA)(hx_array, n-1);
1847 vg_assert(hx_prev->start + hx_prev->len <= hx.start);
1848 }
1849 VG_(addToXA)(hx_array, &hx);
philippe3a532202013-02-24 23:16:58 +00001850 if (DEBUG_TRANSTAB)
1851 VG_(printf)("... hx.start 0x%p hx.len %u sector %d ttslot %d\n",
philippe523b5b82015-03-23 21:49:32 +00001852 hx.start, hx.len, y, tteix);
sewardj291849f2012-04-20 23:58:55 +00001853 }
1854
sewardj6c1bbbb2005-10-18 02:30:42 +00001855 /* Update the fast-cache. */
sewardj291849f2012-04-20 23:58:55 +00001856 setFastCacheEntry( entry, tcptr );
sewardj6c1bbbb2005-10-18 02:30:42 +00001857
1858 /* Note the eclass numbers for this translation. */
philippe523b5b82015-03-23 21:49:32 +00001859 upd_eclasses_after_add( &sectors[y], tteix );
sewardj6c3769f2002-11-29 01:02:45 +00001860}
1861
1862
sewardjfa8ec112005-01-19 11:55:34 +00001863/* Search for the translation of the given guest address. If
1864 requested, a successful search can also cause the fast-caches to be
philippe523b5b82015-03-23 21:49:32 +00001865 updated.
sewardj6c3769f2002-11-29 01:02:45 +00001866*/
florian44bd4462014-12-29 17:04:46 +00001867Bool VG_(search_transtab) ( /*OUT*/Addr* res_hcode,
philippe523b5b82015-03-23 21:49:32 +00001868 /*OUT*/SECno* res_sNo,
1869 /*OUT*/TTEno* res_tteNo,
florianddd61ff2015-01-04 17:20:45 +00001870 Addr guest_addr,
sewardjfa8ec112005-01-19 11:55:34 +00001871 Bool upd_cache )
sewardj6c3769f2002-11-29 01:02:45 +00001872{
philippe523b5b82015-03-23 21:49:32 +00001873 SECno i, sno;
1874 HTTno j, k, kstart;
1875 TTEno tti;
sewardj663a1bd2005-04-24 11:22:44 +00001876
1877 vg_assert(init_done);
sewardjfa8ec112005-01-19 11:55:34 +00001878 /* Find the initial probe point just once. It will be the same in
1879 all sectors and avoids multiple expensive % operations. */
1880 n_full_lookups++;
sewardjfa8ec112005-01-19 11:55:34 +00001881 kstart = HASH_TT(guest_addr);
philippebece82e2015-03-19 22:17:08 +00001882 vg_assert(kstart >= 0 && kstart < N_HTTES_PER_SECTOR);
sewardj6c3769f2002-11-29 01:02:45 +00001883
sewardj5d0d1f32010-03-14 15:09:27 +00001884 /* Search in all the sectors,using sector_search_order[] as a
1885 heuristic guide as to what order to visit the sectors. */
philippe8e1bee42013-10-18 00:08:20 +00001886 for (i = 0; i < n_sectors; i++) {
sewardj6c3769f2002-11-29 01:02:45 +00001887
sewardj5d0d1f32010-03-14 15:09:27 +00001888 sno = sector_search_order[i];
philippe523b5b82015-03-23 21:49:32 +00001889 if (UNLIKELY(sno == INV_SNO))
sewardj5d0d1f32010-03-14 15:09:27 +00001890 return False; /* run out of sectors to search */
sewardj6c3769f2002-11-29 01:02:45 +00001891
sewardjfa8ec112005-01-19 11:55:34 +00001892 k = kstart;
philippebece82e2015-03-19 22:17:08 +00001893 for (j = 0; j < N_HTTES_PER_SECTOR; j++) {
sewardjfa8ec112005-01-19 11:55:34 +00001894 n_lookup_probes++;
philippebece82e2015-03-19 22:17:08 +00001895 tti = sectors[sno].htt[k];
1896 if (tti < N_TTES_PER_SECTOR
Elliott Hughesa0664b92017-04-18 17:46:52 -07001897 && sectors[sno].ttC[tti].entry == guest_addr) {
sewardjfa8ec112005-01-19 11:55:34 +00001898 /* found it */
1899 if (upd_cache)
1900 setFastCacheEntry(
Elliott Hughesa0664b92017-04-18 17:46:52 -07001901 guest_addr, sectors[sno].ttC[tti].tcptr );
sewardj291849f2012-04-20 23:58:55 +00001902 if (res_hcode)
Elliott Hughesa0664b92017-04-18 17:46:52 -07001903 *res_hcode = (Addr)sectors[sno].ttC[tti].tcptr;
sewardj291849f2012-04-20 23:58:55 +00001904 if (res_sNo)
1905 *res_sNo = sno;
1906 if (res_tteNo)
philippebece82e2015-03-19 22:17:08 +00001907 *res_tteNo = tti;
sewardj5d0d1f32010-03-14 15:09:27 +00001908 /* pull this one one step closer to the front. For large
1909 apps this more or less halves the number of required
1910 probes. */
1911 if (i > 0) {
1912 Int tmp = sector_search_order[i-1];
1913 sector_search_order[i-1] = sector_search_order[i];
1914 sector_search_order[i] = tmp;
1915 }
sewardjfa8ec112005-01-19 11:55:34 +00001916 return True;
1917 }
philippebece82e2015-03-19 22:17:08 +00001918 // tti is HTT_EMPTY or HTT_DELETED or not the entry of guest_addr
1919 if (sectors[sno].htt[k] == HTT_EMPTY)
sewardjfa8ec112005-01-19 11:55:34 +00001920 break; /* not found in this sector */
1921 k++;
philippebece82e2015-03-19 22:17:08 +00001922 if (k == N_HTTES_PER_SECTOR)
sewardjfa8ec112005-01-19 11:55:34 +00001923 k = 0;
sewardj6c3769f2002-11-29 01:02:45 +00001924 }
sewardjfa8ec112005-01-19 11:55:34 +00001925
1926 /* If we fall off the end, all entries are InUse and not
1927 matching, or Deleted. In any case we did not find it in this
1928 sector. */
sewardj6c3769f2002-11-29 01:02:45 +00001929 }
sewardjfa8ec112005-01-19 11:55:34 +00001930
1931 /* Not found in any sector. */
1932 return False;
sewardj6c3769f2002-11-29 01:02:45 +00001933}
1934
1935
sewardj6c1bbbb2005-10-18 02:30:42 +00001936/*-------------------------------------------------------------*/
1937/*--- Delete translations. ---*/
1938/*-------------------------------------------------------------*/
1939
sewardj0ec07f32006-01-12 12:32:32 +00001940/* forward */
florianddd61ff2015-01-04 17:20:45 +00001941static void unredir_discard_translations( Addr, ULong );
sewardj0ec07f32006-01-12 12:32:32 +00001942
sewardj6c1bbbb2005-10-18 02:30:42 +00001943/* Stuff for deleting translations which intersect with a given
1944 address range. Unfortunately, to make this run at a reasonable
1945 speed, it is complex. */
sewardjfa8ec112005-01-19 11:55:34 +00001946
1947static inline
florianddd61ff2015-01-04 17:20:45 +00001948Bool overlap1 ( Addr s1, ULong r1, Addr s2, ULong r2 )
sewardjfa8ec112005-01-19 11:55:34 +00001949{
florianddd61ff2015-01-04 17:20:45 +00001950 Addr e1 = s1 + r1 - 1;
1951 Addr e2 = s2 + r2 - 1;
sewardjfa8ec112005-01-19 11:55:34 +00001952 if (e1 < s2 || e2 < s1)
1953 return False;
1954 return True;
1955}
1956
1957static inline
Elliott Hughesa0664b92017-04-18 17:46:52 -07001958Bool overlaps ( Addr start, ULong range, const TTEntryH* tteH )
sewardjfa8ec112005-01-19 11:55:34 +00001959{
Elliott Hughesa0664b92017-04-18 17:46:52 -07001960 if (overlap1(start, range, tteH->vge_base[0], tteH->vge_len[0]))
sewardjfa8ec112005-01-19 11:55:34 +00001961 return True;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001962 if (tteH->vge_n_used < 2)
sewardjfa8ec112005-01-19 11:55:34 +00001963 return False;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001964 if (overlap1(start, range, tteH->vge_base[1], tteH->vge_len[1]))
sewardjfa8ec112005-01-19 11:55:34 +00001965 return True;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001966 if (tteH->vge_n_used < 3)
sewardjfa8ec112005-01-19 11:55:34 +00001967 return False;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001968 if (overlap1(start, range, tteH->vge_base[2], tteH->vge_len[2]))
sewardjfa8ec112005-01-19 11:55:34 +00001969 return True;
1970 return False;
1971}
1972
1973
sewardj6c1bbbb2005-10-18 02:30:42 +00001974/* Delete a tt entry, and update all the eclass data accordingly. */
1975
philippe523b5b82015-03-23 21:49:32 +00001976static void delete_tte ( /*MOD*/Sector* sec, SECno secNo, TTEno tteno,
sewardj59731422014-07-24 12:45:24 +00001977 VexArch arch_host, VexEndness endness_host )
sewardj6c1bbbb2005-10-18 02:30:42 +00001978{
philipped28615c2015-03-31 20:38:52 +00001979 Int i, ec_idx;
1980 EClassNo ec_num;
sewardj6c1bbbb2005-10-18 02:30:42 +00001981
sewardj291849f2012-04-20 23:58:55 +00001982 /* sec and secNo are mutually redundant; cross-check. */
1983 vg_assert(sec == &sectors[secNo]);
1984
sewardj6c1bbbb2005-10-18 02:30:42 +00001985 vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
Elliott Hughesa0664b92017-04-18 17:46:52 -07001986 TTEntryC* tteC = &sec->ttC[tteno];
1987 TTEntryH* tteH = &sec->ttH[tteno];
1988 vg_assert(tteH->status == InUse);
1989 vg_assert(tteC->n_tte2ec >= 1 && tteC->n_tte2ec <= 3);
sewardj6c1bbbb2005-10-18 02:30:42 +00001990
sewardj291849f2012-04-20 23:58:55 +00001991 /* Unchain .. */
sewardj59731422014-07-24 12:45:24 +00001992 unchain_in_preparation_for_deletion(arch_host, endness_host, secNo, tteno);
sewardj291849f2012-04-20 23:58:55 +00001993
sewardj6c1bbbb2005-10-18 02:30:42 +00001994 /* Deal with the ec-to-tte links first. */
Elliott Hughesa0664b92017-04-18 17:46:52 -07001995 for (i = 0; i < tteC->n_tte2ec; i++) {
1996 ec_num = tteC->tte2ec_ec[i];
1997 ec_idx = tteC->tte2ec_ix[i];
sewardj6c1bbbb2005-10-18 02:30:42 +00001998 vg_assert(ec_num >= 0 && ec_num < ECLASS_N);
1999 vg_assert(ec_idx >= 0);
2000 vg_assert(ec_idx < sec->ec2tte_used[ec_num]);
2001 /* Assert that the two links point at each other. */
philippe523b5b82015-03-23 21:49:32 +00002002 vg_assert(sec->ec2tte[ec_num][ec_idx] == tteno);
sewardj6c1bbbb2005-10-18 02:30:42 +00002003 /* "delete" the pointer back to here. */
2004 sec->ec2tte[ec_num][ec_idx] = EC2TTE_DELETED;
2005 }
2006
2007 /* Now fix up this TTEntry. */
philippebece82e2015-03-19 22:17:08 +00002008 /* Mark the entry as deleted in htt.
2009 Note: we could avoid the below hash table search by
2010 adding a reference from tte to its hash position in tt. */
philippe523b5b82015-03-23 21:49:32 +00002011 HTTno j;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002012 HTTno k = HASH_TT(tteC->entry);
philippe523b5b82015-03-23 21:49:32 +00002013 vg_assert(k >= 0 && k < N_HTTES_PER_SECTOR);
philippebece82e2015-03-19 22:17:08 +00002014 for (j = 0; j < N_HTTES_PER_SECTOR; j++) {
2015 if (sec->htt[k] == tteno)
2016 break;
2017 k++;
2018 if (k == N_HTTES_PER_SECTOR)
2019 k = 0;
2020 }
2021 vg_assert(j < N_HTTES_PER_SECTOR);
Elliott Hughesa0664b92017-04-18 17:46:52 -07002022 sec->htt[k] = HTT_DELETED;
2023 tteH->status = Deleted;
2024 tteC->n_tte2ec = 0;
2025 add_to_empty_tt_list(secNo, tteno);
sewardj6c1bbbb2005-10-18 02:30:42 +00002026
2027 /* Stats .. */
2028 sec->tt_n_inuse--;
2029 n_disc_count++;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002030 n_disc_osize += TTEntryH__osize(tteH);
sewardj6c1bbbb2005-10-18 02:30:42 +00002031
2032 /* Tell the tool too. */
sewardj0b9d74a2006-12-24 02:24:11 +00002033 if (VG_(needs).superblock_discards) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002034 VexGuestExtents vge_tmp;
2035 TTEntryH__to_VexGuestExtents( &vge_tmp, tteH );
2036 VG_TDICT_CALL( tool_discard_superblock_info, tteC->entry, vge_tmp );
sewardj6c1bbbb2005-10-18 02:30:42 +00002037 }
2038}
2039
2040
2041/* Delete translations from sec which intersect specified range, but
2042 only consider translations in the specified eclass. */
2043
2044static
philippe523b5b82015-03-23 21:49:32 +00002045Bool delete_translations_in_sector_eclass ( /*MOD*/Sector* sec, SECno secNo,
florianddd61ff2015-01-04 17:20:45 +00002046 Addr guest_start, ULong range,
philipped28615c2015-03-31 20:38:52 +00002047 EClassNo ec,
sewardj59731422014-07-24 12:45:24 +00002048 VexArch arch_host,
2049 VexEndness endness_host )
sewardj6c1bbbb2005-10-18 02:30:42 +00002050{
2051 Int i;
philippe523b5b82015-03-23 21:49:32 +00002052 TTEno tteno;
sewardj6c1bbbb2005-10-18 02:30:42 +00002053 Bool anyDeld = False;
sewardj6c1bbbb2005-10-18 02:30:42 +00002054
2055 vg_assert(ec >= 0 && ec < ECLASS_N);
2056
2057 for (i = 0; i < sec->ec2tte_used[ec]; i++) {
2058
2059 tteno = sec->ec2tte[ec][i];
2060 if (tteno == EC2TTE_DELETED) {
2061 /* already deleted */
2062 continue;
2063 }
2064
2065 vg_assert(tteno < N_TTES_PER_SECTOR);
2066
Elliott Hughesa0664b92017-04-18 17:46:52 -07002067 TTEntryH* tteH = &sec->ttH[tteno];
2068 vg_assert(tteH->status == InUse);
sewardj6c1bbbb2005-10-18 02:30:42 +00002069
Elliott Hughesa0664b92017-04-18 17:46:52 -07002070 if (overlaps( guest_start, range, tteH )) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002071 anyDeld = True;
philippe523b5b82015-03-23 21:49:32 +00002072 delete_tte( sec, secNo, tteno, arch_host, endness_host );
sewardj6c1bbbb2005-10-18 02:30:42 +00002073 }
2074
2075 }
2076
2077 return anyDeld;
2078}
2079
2080
2081/* Delete translations from sec which intersect specified range, the
2082 slow way, by inspecting all translations in sec. */
2083
2084static
philippe523b5b82015-03-23 21:49:32 +00002085Bool delete_translations_in_sector ( /*MOD*/Sector* sec, SECno secNo,
florianddd61ff2015-01-04 17:20:45 +00002086 Addr guest_start, ULong range,
sewardj59731422014-07-24 12:45:24 +00002087 VexArch arch_host,
2088 VexEndness endness_host )
sewardj6c1bbbb2005-10-18 02:30:42 +00002089{
philippe523b5b82015-03-23 21:49:32 +00002090 TTEno i;
2091 Bool anyDeld = False;
sewardj6c1bbbb2005-10-18 02:30:42 +00002092
2093 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002094 /* The entire and only purpose of splitting TTEntry into cold
2095 and hot parts (TTEntryC and TTEntryH) is to make this search
2096 loop run as fast as possible, by avoiding having to pull all
2097 of the cold data up the memory hierarchy. */
2098 if (UNLIKELY(sec->ttH[i].status == InUse
2099 && overlaps( guest_start, range, &sec->ttH[i] ))) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002100 anyDeld = True;
sewardj59731422014-07-24 12:45:24 +00002101 delete_tte( sec, secNo, i, arch_host, endness_host );
sewardj6c1bbbb2005-10-18 02:30:42 +00002102 }
2103 }
2104
2105 return anyDeld;
2106}
2107
2108
florianddd61ff2015-01-04 17:20:45 +00002109void VG_(discard_translations) ( Addr guest_start, ULong range,
florian1636d332012-11-15 04:27:04 +00002110 const HChar* who )
sewardjfa8ec112005-01-19 11:55:34 +00002111{
sewardj6c1bbbb2005-10-18 02:30:42 +00002112 Sector* sec;
philippe523b5b82015-03-23 21:49:32 +00002113 SECno sno;
philipped28615c2015-03-31 20:38:52 +00002114 EClassNo ec;
sewardj6c1bbbb2005-10-18 02:30:42 +00002115 Bool anyDeleted = False;
sewardjfa8ec112005-01-19 11:55:34 +00002116
sewardj663a1bd2005-04-24 11:22:44 +00002117 vg_assert(init_done);
2118
sewardja16ea0a2005-09-30 10:34:06 +00002119 VG_(debugLog)(2, "transtab",
florianddd61ff2015-01-04 17:20:45 +00002120 "discard_translations(0x%lx, %llu) req by %s\n",
sewardj45f4e7c2005-09-27 19:20:21 +00002121 guest_start, range, who );
2122
sewardj6c1bbbb2005-10-18 02:30:42 +00002123 /* Pre-deletion sanity check */
Elliott Hughesa0664b92017-04-18 17:46:52 -07002124 if (VG_(clo_sanity_level) >= 4) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002125 Bool sane = sanity_check_all_sectors();
2126 vg_assert(sane);
2127 }
2128
2129 if (range == 0)
2130 return;
2131
sewardj59731422014-07-24 12:45:24 +00002132 VexArch arch_host = VexArch_INVALID;
2133 VexArchInfo archinfo_host;
2134 VG_(bzero_inline)(&archinfo_host, sizeof(archinfo_host));
2135 VG_(machine_get_VexArchInfo)( &arch_host, &archinfo_host );
2136 VexEndness endness_host = archinfo_host.endness;
sewardj291849f2012-04-20 23:58:55 +00002137
sewardj6c1bbbb2005-10-18 02:30:42 +00002138 /* There are two different ways to do this.
2139
2140 If the range fits within a single address-range equivalence
2141 class, as will be the case for a cache line sized invalidation,
2142 then we only have to inspect the set of translations listed in
2143 that equivalence class, and also in the "sin-bin" equivalence
2144 class ECLASS_MISC.
2145
2146 Otherwise, the invalidation is of a larger range and probably
2147 results from munmap. In this case it's (probably!) faster just
2148 to inspect all translations, dump those we don't want, and
2149 regenerate the equivalence class information (since modifying it
2150 in-situ is even more expensive).
2151 */
2152
2153 /* First off, figure out if the range falls within a single class,
2154 and if so which one. */
2155
2156 ec = ECLASS_MISC;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002157 if (range <= (1ULL << ECLASS_SHIFT))
sewardj6c1bbbb2005-10-18 02:30:42 +00002158 ec = range_to_eclass( guest_start, (UInt)range );
2159
2160 /* if ec is ECLASS_MISC then we aren't looking at just a single
2161 class, so use the slow scheme. Else use the fast scheme,
2162 examining 'ec' and ECLASS_MISC. */
2163
2164 if (ec != ECLASS_MISC) {
2165
2166 VG_(debugLog)(2, "transtab",
2167 " FAST, ec = %d\n", ec);
2168
2169 /* Fast scheme */
2170 vg_assert(ec >= 0 && ec < ECLASS_MISC);
2171
philippe8e1bee42013-10-18 00:08:20 +00002172 for (sno = 0; sno < n_sectors; sno++) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002173 sec = &sectors[sno];
2174 if (sec->tc == NULL)
2175 continue;
2176 anyDeleted |= delete_translations_in_sector_eclass(
sewardj291849f2012-04-20 23:58:55 +00002177 sec, sno, guest_start, range, ec,
sewardj59731422014-07-24 12:45:24 +00002178 arch_host, endness_host
sewardj291849f2012-04-20 23:58:55 +00002179 );
sewardj6c1bbbb2005-10-18 02:30:42 +00002180 anyDeleted |= delete_translations_in_sector_eclass(
sewardj291849f2012-04-20 23:58:55 +00002181 sec, sno, guest_start, range, ECLASS_MISC,
sewardj59731422014-07-24 12:45:24 +00002182 arch_host, endness_host
sewardj291849f2012-04-20 23:58:55 +00002183 );
sewardj6c1bbbb2005-10-18 02:30:42 +00002184 }
2185
2186 } else {
2187
2188 /* slow scheme */
2189
2190 VG_(debugLog)(2, "transtab",
2191 " SLOW, ec = %d\n", ec);
2192
philippe8e1bee42013-10-18 00:08:20 +00002193 for (sno = 0; sno < n_sectors; sno++) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002194 sec = &sectors[sno];
2195 if (sec->tc == NULL)
2196 continue;
2197 anyDeleted |= delete_translations_in_sector(
sewardj59731422014-07-24 12:45:24 +00002198 sec, sno, guest_start, range,
2199 arch_host, endness_host
2200 );
sewardj6c1bbbb2005-10-18 02:30:42 +00002201 }
2202
sewardjfa8ec112005-01-19 11:55:34 +00002203 }
2204
2205 if (anyDeleted)
2206 invalidateFastCache();
sewardj6c1bbbb2005-10-18 02:30:42 +00002207
sewardj0ec07f32006-01-12 12:32:32 +00002208 /* don't forget the no-redir cache */
2209 unredir_discard_translations( guest_start, range );
2210
sewardj6c1bbbb2005-10-18 02:30:42 +00002211 /* Post-deletion sanity check */
Elliott Hughesa0664b92017-04-18 17:46:52 -07002212 if (VG_(clo_sanity_level) >= 4) {
2213 TTEno i;
2214 Bool sane = sanity_check_all_sectors();
sewardj6c1bbbb2005-10-18 02:30:42 +00002215 vg_assert(sane);
2216 /* But now, also check the requested address range isn't
2217 present anywhere. */
philippe8e1bee42013-10-18 00:08:20 +00002218 for (sno = 0; sno < n_sectors; sno++) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002219 sec = &sectors[sno];
2220 if (sec->tc == NULL)
2221 continue;
2222 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002223 TTEntryH* tteH = &sec->ttH[i];
2224 if (tteH->status != InUse)
sewardj6c1bbbb2005-10-18 02:30:42 +00002225 continue;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002226 vg_assert(!overlaps( guest_start, range, tteH ));
sewardj6c1bbbb2005-10-18 02:30:42 +00002227 }
2228 }
2229 }
sewardjfa8ec112005-01-19 11:55:34 +00002230}
2231
florian5f1aeb62015-01-13 17:33:59 +00002232/* Whether or not tools may discard translations. */
2233Bool VG_(ok_to_discard_translations) = False;
2234
2235/* This function is exported to tools which can use it to discard
2236 translations, provided it is safe to do so. */
2237void VG_(discard_translations_safely) ( Addr start, SizeT len,
2238 const HChar* who )
2239{
2240 vg_assert(VG_(ok_to_discard_translations));
2241 VG_(discard_translations)(start, len, who);
2242}
sewardjfa8ec112005-01-19 11:55:34 +00002243
2244/*------------------------------------------------------------*/
sewardj0ec07f32006-01-12 12:32:32 +00002245/*--- AUXILIARY: the unredirected TT/TC ---*/
2246/*------------------------------------------------------------*/
2247
2248/* A very simple translation cache which holds a small number of
2249 unredirected translations. This is completely independent of the
2250 main tt/tc structures. When unredir_tc or unredir_tt becomes full,
2251 both structures are simply dumped and we start over.
2252
2253 Since these translations are unredirected, the search key is (by
2254 definition) the first address entry in the .vge field. */
2255
2256/* Sized to hold 500 translations of average size 1000 bytes. */
2257
2258#define UNREDIR_SZB 1000
2259
2260#define N_UNREDIR_TT 500
2261#define N_UNREDIR_TCQ (N_UNREDIR_TT * UNREDIR_SZB / sizeof(ULong))
2262
2263typedef
2264 struct {
2265 VexGuestExtents vge;
2266 Addr hcode;
2267 Bool inUse;
2268 }
2269 UTCEntry;
2270
2271/* We just allocate forwards in _tc, never deleting. */
tom78c0c092006-01-13 09:57:01 +00002272static ULong *unredir_tc;
2273static Int unredir_tc_used = N_UNREDIR_TCQ;
sewardj0ec07f32006-01-12 12:32:32 +00002274
2275/* Slots in _tt can come into use and out again (.inUse).
2276 Nevertheless _tt_highwater is maintained so that invalidations
2277 don't have to scan all the slots when only a few are in use.
2278 _tt_highwater holds the index of the highest ever allocated
2279 slot. */
2280static UTCEntry unredir_tt[N_UNREDIR_TT];
2281static Int unredir_tt_highwater;
2282
2283
2284static void init_unredir_tt_tc ( void )
2285{
2286 Int i;
tom78c0c092006-01-13 09:57:01 +00002287 if (unredir_tc == NULL) {
njncda2f0f2009-05-18 02:12:08 +00002288 SysRes sres = VG_(am_mmap_anon_float_valgrind)
2289 ( N_UNREDIR_TT * UNREDIR_SZB );
2290 if (sr_isError(sres)) {
2291 VG_(out_of_memory_NORETURN)("init_unredir_tt_tc",
2292 N_UNREDIR_TT * UNREDIR_SZB);
tom78c0c092006-01-13 09:57:01 +00002293 /*NOTREACHED*/
2294 }
florian44bd4462014-12-29 17:04:46 +00002295 unredir_tc = (ULong *)(Addr)sr_Res(sres);
tom78c0c092006-01-13 09:57:01 +00002296 }
sewardj0ec07f32006-01-12 12:32:32 +00002297 unredir_tc_used = 0;
2298 for (i = 0; i < N_UNREDIR_TT; i++)
2299 unredir_tt[i].inUse = False;
2300 unredir_tt_highwater = -1;
2301}
2302
2303/* Do a sanity check; return False on failure. */
2304static Bool sanity_check_redir_tt_tc ( void )
2305{
2306 Int i;
2307 if (unredir_tt_highwater < -1) return False;
2308 if (unredir_tt_highwater >= N_UNREDIR_TT) return False;
2309
2310 for (i = unredir_tt_highwater+1; i < N_UNREDIR_TT; i++)
2311 if (unredir_tt[i].inUse)
2312 return False;
2313
2314 if (unredir_tc_used < 0) return False;
2315 if (unredir_tc_used > N_UNREDIR_TCQ) return False;
2316
2317 return True;
2318}
2319
2320
2321/* Add an UNREDIRECTED translation of vge to TT/TC. The translation
2322 is temporarily in code[0 .. code_len-1].
2323*/
florian518850b2014-10-22 22:25:30 +00002324void VG_(add_to_unredir_transtab)( const VexGuestExtents* vge,
florianddd61ff2015-01-04 17:20:45 +00002325 Addr entry,
florian44bd4462014-12-29 17:04:46 +00002326 Addr code,
njn1dcee092009-02-24 03:07:37 +00002327 UInt code_len )
sewardj0ec07f32006-01-12 12:32:32 +00002328{
2329 Int i, j, code_szQ;
2330 HChar *srcP, *dstP;
2331
2332 vg_assert(sanity_check_redir_tt_tc());
2333
2334 /* This is the whole point: it's not redirected! */
2335 vg_assert(entry == vge->base[0]);
2336
2337 /* How many unredir_tt slots are needed */
2338 code_szQ = (code_len + 7) / 8;
2339
2340 /* Look for an empty unredir_tc slot */
2341 for (i = 0; i < N_UNREDIR_TT; i++)
2342 if (!unredir_tt[i].inUse)
2343 break;
2344
2345 if (i >= N_UNREDIR_TT || code_szQ > (N_UNREDIR_TCQ - unredir_tc_used)) {
2346 /* It's full; dump everything we currently have */
2347 init_unredir_tt_tc();
2348 i = 0;
2349 }
2350
2351 vg_assert(unredir_tc_used >= 0);
2352 vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
2353 vg_assert(code_szQ > 0);
2354 vg_assert(code_szQ + unredir_tc_used <= N_UNREDIR_TCQ);
2355 vg_assert(i >= 0 && i < N_UNREDIR_TT);
2356 vg_assert(unredir_tt[i].inUse == False);
2357
2358 if (i > unredir_tt_highwater)
2359 unredir_tt_highwater = i;
2360
2361 dstP = (HChar*)&unredir_tc[unredir_tc_used];
2362 srcP = (HChar*)code;
2363 for (j = 0; j < code_len; j++)
2364 dstP[j] = srcP[j];
2365
sewardj291849f2012-04-20 23:58:55 +00002366 VG_(invalidate_icache)( dstP, code_len );
sewardjc0a02f82006-04-07 12:47:05 +00002367
sewardj0ec07f32006-01-12 12:32:32 +00002368 unredir_tt[i].inUse = True;
2369 unredir_tt[i].vge = *vge;
2370 unredir_tt[i].hcode = (Addr)dstP;
2371
2372 unredir_tc_used += code_szQ;
2373 vg_assert(unredir_tc_used >= 0);
2374 vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
2375
2376 vg_assert(&dstP[code_len] <= (HChar*)&unredir_tc[unredir_tc_used]);
2377}
2378
florian44bd4462014-12-29 17:04:46 +00002379Bool VG_(search_unredir_transtab) ( /*OUT*/Addr* result,
florianddd61ff2015-01-04 17:20:45 +00002380 Addr guest_addr )
sewardj0ec07f32006-01-12 12:32:32 +00002381{
2382 Int i;
2383 for (i = 0; i < N_UNREDIR_TT; i++) {
2384 if (!unredir_tt[i].inUse)
2385 continue;
2386 if (unredir_tt[i].vge.base[0] == guest_addr) {
florianddd61ff2015-01-04 17:20:45 +00002387 *result = unredir_tt[i].hcode;
sewardj0ec07f32006-01-12 12:32:32 +00002388 return True;
2389 }
2390 }
2391 return False;
2392}
2393
florianddd61ff2015-01-04 17:20:45 +00002394static void unredir_discard_translations( Addr guest_start, ULong range )
sewardj0ec07f32006-01-12 12:32:32 +00002395{
2396 Int i;
2397
2398 vg_assert(sanity_check_redir_tt_tc());
2399
2400 for (i = 0; i <= unredir_tt_highwater; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002401 if (unredir_tt[i].inUse) {
2402 /* Fake up a TTEntryH just so we can pass it to overlaps()
2403 without having to make a new version of overlaps() just for
2404 this rare case. */
2405 TTEntryH tmp_tteH;
2406 TTEntryH__from_VexGuestExtents( &tmp_tteH, &unredir_tt[i].vge );
2407 tmp_tteH.status = Empty; /* Completely irrelevant; pure paranoia. */
2408 if (overlaps( guest_start, range, &tmp_tteH )) {
2409 unredir_tt[i].inUse = False;
2410 }
2411 }
sewardj0ec07f32006-01-12 12:32:32 +00002412 }
2413}
2414
2415
2416/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002417/*--- Initialisation. ---*/
2418/*------------------------------------------------------------*/
2419
sewardjc0d8f682002-11-30 00:49:43 +00002420void VG_(init_tt_tc) ( void )
2421{
sewardja11ec172013-10-18 11:18:45 +00002422 Int i, avg_codeszQ;
sewardjc0d8f682002-11-30 00:49:43 +00002423
sewardj663a1bd2005-04-24 11:22:44 +00002424 vg_assert(!init_done);
2425 init_done = True;
2426
sewardj4ccf7072004-11-28 16:58:05 +00002427 /* Otherwise lots of things go wrong... */
sewardjfa8ec112005-01-19 11:55:34 +00002428 vg_assert(sizeof(ULong) == 8);
philippe523b5b82015-03-23 21:49:32 +00002429 vg_assert(sizeof(TTEno) == sizeof(HTTno));
2430 vg_assert(sizeof(TTEno) == 2);
2431 vg_assert(N_TTES_PER_SECTOR <= N_HTTES_PER_SECTOR);
2432 vg_assert(N_HTTES_PER_SECTOR < INV_TTE);
2433 vg_assert(N_HTTES_PER_SECTOR < EC2TTE_DELETED);
2434 vg_assert(N_HTTES_PER_SECTOR < HTT_EMPTY);
sewardj5f76de02007-02-11 05:08:06 +00002435 /* check fast cache entries really are 2 words long */
2436 vg_assert(sizeof(Addr) == sizeof(void*));
2437 vg_assert(sizeof(FastCacheEntry) == 2 * sizeof(Addr));
2438 /* check fast cache entries are packed back-to-back with no spaces */
philippe523b5b82015-03-23 21:49:32 +00002439 vg_assert(sizeof( VG_(tt_fast) )
2440 == VG_TT_FAST_SIZE * sizeof(FastCacheEntry));
sewardj5f76de02007-02-11 05:08:06 +00002441 /* check fast cache is aligned as we requested. Not fatal if it
2442 isn't, but we might as well make sure. */
2443 vg_assert(VG_IS_16_ALIGNED( ((Addr) & VG_(tt_fast)[0]) ));
sewardjfa8ec112005-01-19 11:55:34 +00002444
Elliott Hughesa0664b92017-04-18 17:46:52 -07002445 /* The TTEntryH size is critical for keeping the LLC miss rate down
2446 when doing a lot of discarding. Hence check it here. We also
2447 have a lot of TTEntryCs so let's check that too. */
2448 if (sizeof(HWord) == 8) {
2449 vg_assert(sizeof(TTEntryH) <= 32);
2450 vg_assert(sizeof(TTEntryC) <= 112);
2451 }
2452 else if (sizeof(HWord) == 4) {
2453 vg_assert(sizeof(TTEntryH) <= 20);
2454# if defined(VGP_ppc32_linux) || defined(VGP_mips32_linux) \
2455 || defined(VGP_arm_linux)
2456 /* On PPC32, MIPS32, ARM32 platforms, alignof(ULong) == 8, so the
2457 structure is larger than on other 32 bit targets. */
2458 vg_assert(sizeof(TTEntryC) <= 96);
2459# else
2460 vg_assert(sizeof(TTEntryC) <= 88);
2461# endif
2462 }
2463 else {
2464 vg_assert(0);
2465 }
2466
2467 /* All the hassle about converting between TTEntryH and
2468 VexGuestExtents was so as to ensure the following. */
2469 vg_assert(sizeof(TTEntryH) == sizeof(VexGuestExtents));
2470
sewardjfa8ec112005-01-19 11:55:34 +00002471 if (VG_(clo_verbosity) > 2)
2472 VG_(message)(Vg_DebugMsg,
2473 "TT/TC: VG_(init_tt_tc) "
sewardj738856f2009-07-15 14:48:32 +00002474 "(startup of code management)\n");
sewardjfa8ec112005-01-19 11:55:34 +00002475
2476 /* Figure out how big each tc area should be. */
philippe924c8522015-03-15 12:24:19 +00002477 if (VG_(clo_avg_transtab_entry_size) == 0)
2478 avg_codeszQ = (VG_(details).avg_translation_sizeB + 7) / 8;
2479 else
2480 avg_codeszQ = (VG_(clo_avg_transtab_entry_size) + 7) / 8;
philippebece82e2015-03-19 22:17:08 +00002481 tc_sector_szQ = N_TTES_PER_SECTOR * (1 + avg_codeszQ);
sewardjfa8ec112005-01-19 11:55:34 +00002482
sewardjc0d8f682002-11-30 00:49:43 +00002483 /* Ensure the calculated value is not way crazy. */
philippebece82e2015-03-19 22:17:08 +00002484 vg_assert(tc_sector_szQ >= 2 * N_TTES_PER_SECTOR);
2485 vg_assert(tc_sector_szQ <= 100 * N_TTES_PER_SECTOR);
sewardjc0d8f682002-11-30 00:49:43 +00002486
philippe8e1bee42013-10-18 00:08:20 +00002487 n_sectors = VG_(clo_num_transtab_sectors);
2488 vg_assert(n_sectors >= MIN_N_SECTORS);
2489 vg_assert(n_sectors <= MAX_N_SECTORS);
2490
sewardja11ec172013-10-18 11:18:45 +00002491 /* Initialise the sectors, even the ones we aren't going to use.
2492 Set all fields to zero. */
sewardjfa8ec112005-01-19 11:55:34 +00002493 youngest_sector = 0;
sewardja11ec172013-10-18 11:18:45 +00002494 for (i = 0; i < MAX_N_SECTORS; i++)
2495 VG_(memset)(&sectors[i], 0, sizeof(sectors[i]));
sewardjc0d8f682002-11-30 00:49:43 +00002496
sewardja11ec172013-10-18 11:18:45 +00002497 /* Initialise the sector_search_order hint table, including the
2498 entries we aren't going to use. */
2499 for (i = 0; i < MAX_N_SECTORS; i++)
philippe523b5b82015-03-23 21:49:32 +00002500 sector_search_order[i] = INV_SNO;
sewardj5d0d1f32010-03-14 15:09:27 +00002501
sewardj291849f2012-04-20 23:58:55 +00002502 /* Initialise the fast cache. */
sewardjfa8ec112005-01-19 11:55:34 +00002503 invalidateFastCache();
sewardjc0d8f682002-11-30 00:49:43 +00002504
sewardj0ec07f32006-01-12 12:32:32 +00002505 /* and the unredir tt/tc */
2506 init_unredir_tt_tc();
2507
philippe8e1bee42013-10-18 00:08:20 +00002508 if (VG_(clo_verbosity) > 2 || VG_(clo_stats)
2509 || VG_(debugLog_getLevel) () >= 2) {
sewardjc0d8f682002-11-30 00:49:43 +00002510 VG_(message)(Vg_DebugMsg,
floriana5e06c32015-08-05 21:16:09 +00002511 "TT/TC: cache: %s--avg-transtab-entry-size=%u, "
2512 "%stool provided default %u\n",
philippe924c8522015-03-15 12:24:19 +00002513 VG_(clo_avg_transtab_entry_size) == 0 ? "ignoring " : "using ",
2514 VG_(clo_avg_transtab_entry_size),
2515 VG_(clo_avg_transtab_entry_size) == 0 ? "using " : "ignoring ",
2516 VG_(details).avg_translation_sizeB);
2517 VG_(message)(Vg_DebugMsg,
Elliott Hughesa0664b92017-04-18 17:46:52 -07002518 "TT/TC: cache: %d sectors of %'d bytes each = %'d total TC\n",
philippe8e1bee42013-10-18 00:08:20 +00002519 n_sectors, 8 * tc_sector_szQ,
2520 n_sectors * 8 * tc_sector_szQ );
sewardjc0d8f682002-11-30 00:49:43 +00002521 VG_(message)(Vg_DebugMsg,
Elliott Hughesa0664b92017-04-18 17:46:52 -07002522 "TT/TC: table: %'d tables[%d] of C %'d + H %'d bytes each "
2523 "= %'d total TT\n",
philippebece82e2015-03-19 22:17:08 +00002524 n_sectors, N_TTES_PER_SECTOR,
Elliott Hughesa0664b92017-04-18 17:46:52 -07002525 (int)(N_TTES_PER_SECTOR * sizeof(TTEntryC)),
2526 (int)(N_TTES_PER_SECTOR * sizeof(TTEntryH)),
2527 (int)(n_sectors * N_TTES_PER_SECTOR
2528 * (sizeof(TTEntryC) + sizeof(TTEntryH))));
philippe8e1bee42013-10-18 00:08:20 +00002529 VG_(message)(Vg_DebugMsg,
Elliott Hughesa0664b92017-04-18 17:46:52 -07002530 "TT/TC: table: %d tt entries each = %'d total tt entries\n",
philippebece82e2015-03-19 22:17:08 +00002531 N_TTES_PER_SECTOR, n_sectors * N_TTES_PER_SECTOR);
2532 VG_(message)(Vg_DebugMsg,
Elliott Hughesa0664b92017-04-18 17:46:52 -07002533 "TT/TC: table: %d htt[%d] of %'d bytes each = %'d total HTT"
philippebece82e2015-03-19 22:17:08 +00002534 " (htt[%d] %d%% max occup)\n",
2535 n_sectors, N_HTTES_PER_SECTOR,
philippe523b5b82015-03-23 21:49:32 +00002536 (int)(N_HTTES_PER_SECTOR * sizeof(TTEno)),
2537 (int)(n_sectors * N_HTTES_PER_SECTOR * sizeof(TTEno)),
philippebece82e2015-03-19 22:17:08 +00002538 N_HTTES_PER_SECTOR, SECTOR_TT_LIMIT_PERCENT);
sewardjfa8ec112005-01-19 11:55:34 +00002539 }
Elliott Hughesa0664b92017-04-18 17:46:52 -07002540
2541 if (0) {
2542 VG_(printf)("XXXX sizeof(VexGuestExtents) = %d\n",
2543 (Int)sizeof(VexGuestExtents));
2544 VG_(printf)("XXXX sizeof(InEdge) = %d\n", (Int)sizeof(InEdge));
2545 VG_(printf)("XXXX sizeof(OutEdge) = %d\n", (Int)sizeof(OutEdge));
2546 VG_(printf)("XXXX sizeof(InEdgeArr) = %d\n", (Int)sizeof(InEdgeArr));
2547 VG_(printf)("XXXX sizeof(OutEdgeArr) = %d\n", (Int)sizeof(OutEdgeArr));
2548 VG_(printf)("XXXX sizeof(TTEntryC) = %d\n", (Int)sizeof(TTEntryC));
2549 VG_(printf)("XXXX sizeof(TTEntryH) = %d\n", (Int)sizeof(TTEntryH));
2550 }
sewardjfa8ec112005-01-19 11:55:34 +00002551}
2552
2553
2554/*------------------------------------------------------------*/
2555/*--- Printing out statistics. ---*/
2556/*------------------------------------------------------------*/
2557
philippe24f33d72015-03-26 22:12:40 +00002558static Double safe_idiv( ULong a, ULong b )
sewardjfa8ec112005-01-19 11:55:34 +00002559{
philippe24f33d72015-03-26 22:12:40 +00002560 return (b == 0 ? 0 : (Double)a / (Double)b);
sewardjfa8ec112005-01-19 11:55:34 +00002561}
2562
2563UInt VG_(get_bbs_translated) ( void )
2564{
2565 return n_in_count;
2566}
2567
2568void VG_(print_tt_tc_stats) ( void )
2569{
2570 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002571 " tt/tc: %'llu tt lookups requiring %'llu probes\n",
sewardjfa8ec112005-01-19 11:55:34 +00002572 n_full_lookups, n_lookup_probes );
2573 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002574 " tt/tc: %'llu fast-cache updates, %'llu flushes\n",
sewardjfa8ec112005-01-19 11:55:34 +00002575 n_fast_updates, n_fast_flushes );
2576
2577 VG_(message)(Vg_DebugMsg,
floriana5e06c32015-08-05 21:16:09 +00002578 " transtab: new %'llu "
philippe24f33d72015-03-26 22:12:40 +00002579 "(%'llu -> %'llu; ratio %3.1f) [%'llu scs] "
floriana5e06c32015-08-05 21:16:09 +00002580 "avg tce size %llu\n",
sewardjfa8ec112005-01-19 11:55:34 +00002581 n_in_count, n_in_osize, n_in_tsize,
philippe24f33d72015-03-26 22:12:40 +00002582 safe_idiv(n_in_tsize, n_in_osize),
philippe5e47e3f2015-03-12 22:36:22 +00002583 n_in_sc_count,
floriana5e06c32015-08-05 21:16:09 +00002584 n_in_tsize / (n_in_count ? n_in_count : 1));
sewardjfa8ec112005-01-19 11:55:34 +00002585 VG_(message)(Vg_DebugMsg,
philippe5e47e3f2015-03-12 22:36:22 +00002586 " transtab: dumped %'llu (%'llu -> ?" "?) "
2587 "(sectors recycled %'llu)\n",
2588 n_dump_count, n_dump_osize, n_sectors_recycled );
sewardjfa8ec112005-01-19 11:55:34 +00002589 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002590 " transtab: discarded %'llu (%'llu -> ?" "?)\n",
sewardjfa8ec112005-01-19 11:55:34 +00002591 n_disc_count, n_disc_osize );
sewardj6c1bbbb2005-10-18 02:30:42 +00002592
philippe3a532202013-02-24 23:16:58 +00002593 if (DEBUG_TRANSTAB) {
sewardj6c1bbbb2005-10-18 02:30:42 +00002594 VG_(printf)("\n");
philipped28615c2015-03-31 20:38:52 +00002595 for (EClassNo e = 0; e < ECLASS_N; e++) {
2596 VG_(printf)(" %4d", sectors[0].ec2tte_used[e]);
2597 if (e % 16 == 15)
sewardj6c1bbbb2005-10-18 02:30:42 +00002598 VG_(printf)("\n");
2599 }
2600 VG_(printf)("\n\n");
2601 }
sewardjfa8ec112005-01-19 11:55:34 +00002602}
2603
2604/*------------------------------------------------------------*/
2605/*--- Printing out of profiling results. ---*/
2606/*------------------------------------------------------------*/
2607
Elliott Hughesa0664b92017-04-18 17:46:52 -07002608static ULong score ( const TTEntryC* tteC )
sewardjfa8ec112005-01-19 11:55:34 +00002609{
Elliott Hughesa0664b92017-04-18 17:46:52 -07002610 return ((ULong)tteC->usage.prof.weight) * ((ULong)tteC->usage.prof.count);
sewardjfa8ec112005-01-19 11:55:34 +00002611}
2612
sewardj17c5e2e2012-12-28 09:12:14 +00002613ULong VG_(get_SB_profile) ( SBProfEntry tops[], UInt n_tops )
sewardjfa8ec112005-01-19 11:55:34 +00002614{
philippe523b5b82015-03-23 21:49:32 +00002615 SECno sno;
2616 Int r, s;
njn2025cf92005-06-26 20:44:48 +00002617 ULong score_total;
philippe523b5b82015-03-23 21:49:32 +00002618 TTEno i;
sewardjfa8ec112005-01-19 11:55:34 +00002619
2620 /* First, compute the total weighted count, and find the top N
njn2025cf92005-06-26 20:44:48 +00002621 ttes. tops contains pointers to the most-used n_tops blocks, in
sewardjfa8ec112005-01-19 11:55:34 +00002622 descending order (viz, tops[0] is the highest scorer). */
philippe523b5b82015-03-23 21:49:32 +00002623 for (s = 0; s < n_tops; s++) {
2624 tops[s].addr = 0;
2625 tops[s].score = 0;
njn2025cf92005-06-26 20:44:48 +00002626 }
sewardjfa8ec112005-01-19 11:55:34 +00002627
2628 score_total = 0;
2629
philippe8e1bee42013-10-18 00:08:20 +00002630 for (sno = 0; sno < n_sectors; sno++) {
sewardjfa8ec112005-01-19 11:55:34 +00002631 if (sectors[sno].tc == NULL)
2632 continue;
2633 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002634 if (sectors[sno].ttH[i].status != InUse)
sewardjfa8ec112005-01-19 11:55:34 +00002635 continue;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002636 score_total += score(&sectors[sno].ttC[i]);
2637 /* Find the rank for sectors[sno].tt{C,H}[i]. */
njn2025cf92005-06-26 20:44:48 +00002638 r = n_tops-1;
sewardjfa8ec112005-01-19 11:55:34 +00002639 while (True) {
2640 if (r == -1)
2641 break;
njn2025cf92005-06-26 20:44:48 +00002642 if (tops[r].addr == 0) {
sewardjfa8ec112005-01-19 11:55:34 +00002643 r--;
2644 continue;
2645 }
Elliott Hughesa0664b92017-04-18 17:46:52 -07002646 if ( score(&sectors[sno].ttC[i]) > tops[r].score ) {
sewardjfa8ec112005-01-19 11:55:34 +00002647 r--;
2648 continue;
2649 }
2650 break;
2651 }
2652 r++;
njn2025cf92005-06-26 20:44:48 +00002653 vg_assert(r >= 0 && r <= n_tops);
sewardjfa8ec112005-01-19 11:55:34 +00002654 /* This bb should be placed at r, and bbs above it shifted
2655 upwards one slot. */
njn2025cf92005-06-26 20:44:48 +00002656 if (r < n_tops) {
2657 for (s = n_tops-1; s > r; s--)
sewardjfa8ec112005-01-19 11:55:34 +00002658 tops[s] = tops[s-1];
Elliott Hughesa0664b92017-04-18 17:46:52 -07002659 tops[r].addr = sectors[sno].ttC[i].entry;
2660 tops[r].score = score( &sectors[sno].ttC[i] );
sewardjfa8ec112005-01-19 11:55:34 +00002661 }
2662 }
sewardjc0d8f682002-11-30 00:49:43 +00002663 }
2664
sewardj17c5e2e2012-12-28 09:12:14 +00002665 /* Now zero out all the counter fields, so that we can make
2666 multiple calls here and just get the values since the last call,
2667 each time, rather than values accumulated for the whole run. */
philippe8e1bee42013-10-18 00:08:20 +00002668 for (sno = 0; sno < n_sectors; sno++) {
sewardj17c5e2e2012-12-28 09:12:14 +00002669 if (sectors[sno].tc == NULL)
2670 continue;
2671 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07002672 if (sectors[sno].ttH[i].status != InUse)
sewardj17c5e2e2012-12-28 09:12:14 +00002673 continue;
Elliott Hughesa0664b92017-04-18 17:46:52 -07002674 sectors[sno].ttC[i].usage.prof.count = 0;
sewardj17c5e2e2012-12-28 09:12:14 +00002675 }
2676 }
2677
njn2025cf92005-06-26 20:44:48 +00002678 return score_total;
sewardjc0d8f682002-11-30 00:49:43 +00002679}
2680
sewardjde4a1d02002-03-22 01:27:54 +00002681/*--------------------------------------------------------------------*/
njn8bddf582005-05-13 23:40:55 +00002682/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00002683/*--------------------------------------------------------------------*/