blob: 1d3cc206dc670fa82b2e1043706f2563a58b3213 [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
sewardjec062e82011-10-23 07:32:08 +000011 Copyright (C) 2000-2011 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
sewardj18d75132002-05-16 11:06:21 +000049/* #define DEBUG_TRANSTAB */
50
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
sewardj6c3769f2002-11-29 01:02:45 +000056/*------------------ CONSTANTS ------------------*/
sewardjde4a1d02002-03-22 01:27:54 +000057
sewardjfa8ec112005-01-19 11:55:34 +000058/* Number of sectors the TC is divided into. If you need a larger
59 overall translation cache, increase this value. */
60#define N_SECTORS 8
sewardjde4a1d02002-03-22 01:27:54 +000061
sewardjfa8ec112005-01-19 11:55:34 +000062/* Number of TC entries in each sector. This needs to be a prime
sewardj6c1bbbb2005-10-18 02:30:42 +000063 number to work properly, it must be <= 65535 (so that a TT index
64 fits in a UShort, leaving room for 0xFFFF(EC2TTE_DELETED) to denote
65 'deleted') and it is strongly recommended not to change this.
66 65521 is the largest prime <= 65535. */
sewardje25053c2012-04-23 09:53:20 +000067#define N_TTES_PER_SECTOR /*10007*/ /*30011*/ /*40009*/ 65521
sewardjde4a1d02002-03-22 01:27:54 +000068
sewardjfa8ec112005-01-19 11:55:34 +000069/* Because each sector contains a hash table of TTEntries, we need to
70 specify the maximum allowable loading, after which the sector is
71 deemed full. */
sewardj5d0d1f32010-03-14 15:09:27 +000072#define SECTOR_TT_LIMIT_PERCENT 65
sewardjde4a1d02002-03-22 01:27:54 +000073
sewardjfa8ec112005-01-19 11:55:34 +000074/* The sector is deemed full when this many entries are in it. */
75#define N_TTES_PER_SECTOR_USABLE \
76 ((N_TTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
sewardjde4a1d02002-03-22 01:27:54 +000077
sewardj6c1bbbb2005-10-18 02:30:42 +000078/* Equivalence classes for fast address range deletion. There are 1 +
79 2^ECLASS_WIDTH bins. The highest one, ECLASS_MISC, describes an
80 address range which does not fall cleanly within any specific bin.
81 Note that ECLASS_SHIFT + ECLASS_WIDTH must be < 32. */
82#define ECLASS_SHIFT 11
83#define ECLASS_WIDTH 8
84#define ECLASS_MISC (1 << ECLASS_WIDTH)
85#define ECLASS_N (1 + ECLASS_MISC)
86
87#define EC2TTE_DELETED 0xFFFF /* 16-bit special value */
88
sewardjde4a1d02002-03-22 01:27:54 +000089
sewardj6c3769f2002-11-29 01:02:45 +000090/*------------------ TYPES ------------------*/
91
sewardj291849f2012-04-20 23:58:55 +000092/* In edges ("to-me") in the graph created by chaining. */
93typedef
94 struct {
95 UInt from_sNo; /* sector number */
96 UInt from_tteNo; /* TTE number in given sector */
97 UInt from_offs; /* code offset from TCEntry::tcptr where the patch is */
98 Bool to_fastEP; /* Is the patch to a fast or slow entry point? */
99 }
100 InEdge;
101
102
103/* Out edges ("from-me") in the graph created by chaining. */
104typedef
105 struct {
106 UInt to_sNo; /* sector number */
107 UInt to_tteNo; /* TTE number in given sector */
108 UInt from_offs; /* code offset in owning translation where patch is */
109 }
110 OutEdge;
111
112
113#define N_FIXED_IN_EDGE_ARR 3
114typedef
115 struct {
116 UInt n_fixed; /* 0 .. N_FIXED_IN_EDGE_ARR */
117 InEdge fixed[N_FIXED_IN_EDGE_ARR];
118 XArray* var; /* XArray* of InEdgeArr */
119 }
120 InEdgeArr;
121
122#define N_FIXED_OUT_EDGE_ARR 2
123typedef
124 struct {
125 UInt n_fixed; /* 0 .. N_FIXED_OUT_EDGE_ARR */
126 OutEdge fixed[N_FIXED_OUT_EDGE_ARR];
127 XArray* var; /* XArray* of OutEdgeArr */
128 }
129 OutEdgeArr;
130
131
sewardjfa8ec112005-01-19 11:55:34 +0000132/* A translation-table entry. This indicates precisely which areas of
133 guest code are included in the translation, and contains all other
134 auxiliary info too. */
135typedef
136 struct {
137 /* Profiling only: the count and weight (arbitrary meaning) for
138 this translation. Weight is a property of the translation
139 itself and computed once when the translation is created.
140 Count is an entry count for the translation and is
141 incremented by 1 every time the translation is used, if we
142 are profiling. */
sewardj291849f2012-04-20 23:58:55 +0000143 ULong count;
sewardjfa8ec112005-01-19 11:55:34 +0000144 UShort weight;
145
146 /* Status of the slot. Note, we need to be able to do lazy
147 deletion, hence the Deleted state. */
148 enum { InUse, Deleted, Empty } status;
149
sewardj5f76de02007-02-11 05:08:06 +0000150 /* 64-bit aligned pointer to one or more 64-bit words containing
151 the corresponding host code (must be in the same sector!)
152 This is a pointer into the sector's tc (code) area. */
153 ULong* tcptr;
sewardjfa8ec112005-01-19 11:55:34 +0000154
155 /* This is the original guest address that purportedly is the
156 entry point of the translation. You might think that .entry
157 should be the same as .vge->base[0], and most of the time it
158 is. However, when doing redirections, that is not the case.
159 .vge must always correctly describe the guest code sections
160 from which this translation was made. However, .entry may or
161 may not be a lie, depending on whether or not we're doing
162 redirection. */
163 Addr64 entry;
164
165 /* This structure describes precisely what ranges of guest code
166 the translation covers, so we can decide whether or not to
167 delete it when translations of a given address range are
168 invalidated. */
169 VexGuestExtents vge;
sewardj6c1bbbb2005-10-18 02:30:42 +0000170
171 /* Address range summary info: these are pointers back to
172 eclass[] entries in the containing Sector. Those entries in
173 turn point back here -- the two structures are mutually
174 redundant but both necessary to make fast deletions work.
175 The eclass info is similar to, and derived from, this entry's
176 'vge' field, but it is not the same */
177 UShort n_tte2ec; // # tte2ec pointers (1 to 3)
178 UShort tte2ec_ec[3]; // for each, the eclass #
179 UInt tte2ec_ix[3]; // and the index within the eclass.
180 // for i in 0 .. n_tte2ec-1
181 // sec->ec2tte[ tte2ec_ec[i] ][ tte2ec_ix[i] ]
182 // should be the index
183 // of this TTEntry in the containing Sector's tt array.
sewardj291849f2012-04-20 23:58:55 +0000184
185 /* Admin information for chaining. 'in_edges' is a set of the
186 patch points which jump to this translation -- hence are
187 predecessors in the control flow graph. 'out_edges' points
188 to successors in the control flow graph -- translations to
189 which this one has a patched jump. In short these are just
190 backwards and forwards edges in the graph of patched-together
191 blocks. The 'in_edges' contain slightly more info, enough
192 that we can undo the chaining of each mentioned patch point.
193 The 'out_edges' list exists only so that we can visit the
194 'in_edges' entries of all blocks we're patched through to, in
195 order to remove ourselves from then when we're deleted. */
196
197 /* A translation can disappear for two reasons:
198 1. erased (as part of the oldest sector cleanup) when the
199 youngest sector is full.
200 2. discarded due to calls to VG_(discard_translations).
201 VG_(discard_translations) sets the status of the
202 translation to 'Deleted'.
203 A.o., the gdbserver discards one or more translations
204 when a breakpoint is inserted or removed at an Addr,
205 or when single stepping mode is enabled/disabled
206 or when a translation is instrumented for gdbserver
207 (all the target jumps of this translation are
208 invalidated).
209
210 So, it is possible that the translation A to be patched
211 (to obtain a patched jump from A to B) is invalidated
212 after B is translated and before A is patched.
213 In case a translation is erased or discarded, the patching
214 cannot be done. VG_(tt_tc_do_chaining) and find_TTEntry_from_hcode
215 are checking the 'from' translation still exists before
216 doing the patching.
217
218 Is it safe to erase or discard the current translation E being
219 executed ? Amazing, but yes, it is safe.
220 Here is the explanation:
221
222 The translation E being executed can only be erased if a new
223 translation N is being done. A new translation is done only
224 if the host addr is a not yet patched jump to another
225 translation. In such a case, the guest address of N is
226 assigned to the PC in the VEX state. Control is returned
227 to the scheduler. N will be translated. This can erase the
228 translation E (in case of sector full). VG_(tt_tc_do_chaining)
229 will not do the chaining to a non found translation E.
230 The execution will continue at the current guest PC
231 (i.e. the translation N).
232 => it is safe to erase the current translation being executed.
233
234 The current translation E being executed can also be discarded
235 (e.g. by gdbserver). VG_(discard_translations) will mark
236 this translation E as Deleted, but the translation itself
237 is not erased. In particular, its host code can only
238 be overwritten or erased in case a new translation is done.
239 A new translation will only be done if a not yet translated
240 jump is to be executed. The execution of the Deleted translation
241 E will continue till a non patched jump is encountered.
242 This situation is then similar to the 'erasing' case above :
243 the current translation E can be erased or overwritten, as the
244 execution will continue at the new translation N.
245
246 */
247
248 /* It is possible, although very unlikely, that a block A has
249 more than one patched jump to block B. This could happen if
250 (eg) A finishes "jcond B; jmp B".
251
252 This means in turn that B's in_edges set can list A more than
253 once (twice in this example). However, each such entry must
254 have a different from_offs, since a patched jump can only
255 jump to one place at once (it's meaningless for it to have
256 multiple destinations.) IOW, the successor and predecessor
257 edges in the graph are not uniquely determined by a
258 TTEntry --> TTEntry pair, but rather by a
259 (TTEntry,offset) --> TTEntry triple.
260
261 If A has multiple edges to B then B will mention A multiple
262 times in its in_edges. To make things simpler, we then
263 require that A mentions B exactly the same number of times in
264 its out_edges. Furthermore, a matching out-in pair must have
265 the same offset (from_offs). This facilitates sanity
266 checking, and it facilitates establishing the invariant that
267 a out_edges set may not have duplicates when using the
268 equality defined by (TTEntry,offset). Hence the out_edges
269 and in_edges sets really do have both have set semantics.
270
271 eg if A has been patched to B at offsets 42 and 87 (in A)
272 then A.out_edges = { (B,42), (B,87) } (in any order)
273 and B.in_edges = { (A,42), (A,87) } (in any order)
274
275 Hence for each node pair P->Q in the graph, there's a 1:1
276 mapping between P.out_edges and Q.in_edges.
277 */
278 InEdgeArr in_edges;
279 OutEdgeArr out_edges;
sewardj6c3769f2002-11-29 01:02:45 +0000280 }
281 TTEntry;
282
sewardj4ccf7072004-11-28 16:58:05 +0000283
sewardj291849f2012-04-20 23:58:55 +0000284/* A structure used for mapping host code addresses back to the
285 relevant TTEntry. Used when doing chaining, for finding the
286 TTEntry to which some arbitrary patch address belongs. */
287typedef
288 struct {
289 UChar* start;
290 UInt len;
291 UInt tteNo;
292 }
293 HostExtent;
294
sewardjfa8ec112005-01-19 11:55:34 +0000295/* Finally, a sector itself. Each sector contains an array of
296 TCEntries, which hold code, and an array of TTEntries, containing
297 all required administrative info. Profiling is supported using the
sewardj291849f2012-04-20 23:58:55 +0000298 TTEntry .count and .weight fields, if required.
sewardj4ccf7072004-11-28 16:58:05 +0000299
sewardjfa8ec112005-01-19 11:55:34 +0000300 If the sector is not in use, all three pointers are NULL and
301 tt_n_inuse is zero.
302*/
303typedef
304 struct {
305 /* The TCEntry area. Size of this depends on the average
306 translation size. We try and size it so it becomes full
307 precisely when this sector's translation table (tt) reaches
308 its load limit (SECTOR_TT_LIMIT_PERCENT). */
309 ULong* tc;
sewardj4ccf7072004-11-28 16:58:05 +0000310
sewardjfa8ec112005-01-19 11:55:34 +0000311 /* The TTEntry array. This is a fixed size, always containing
312 exactly N_TTES_PER_SECTOR entries. */
313 TTEntry* tt;
sewardj4ccf7072004-11-28 16:58:05 +0000314
sewardjfa8ec112005-01-19 11:55:34 +0000315 /* This points to the current allocation point in tc. */
316 ULong* tc_next;
sewardj6c3769f2002-11-29 01:02:45 +0000317
sewardjfa8ec112005-01-19 11:55:34 +0000318 /* The count of tt entries with state InUse. */
319 Int tt_n_inuse;
sewardj6c1bbbb2005-10-18 02:30:42 +0000320
321 /* Expandable arrays of tt indices for each of the ECLASS_N
322 address range equivalence classes. These hold indices into
323 the containing sector's tt array, which in turn should point
324 back here. */
325 Int ec2tte_size[ECLASS_N];
326 Int ec2tte_used[ECLASS_N];
327 UShort* ec2tte[ECLASS_N];
sewardj291849f2012-04-20 23:58:55 +0000328
329 /* The host extents. The [start, +len) ranges are constructed
330 in strictly non-overlapping order, so we can binary search
331 them at any time. */
332 XArray* host_extents; /* XArray* of HostExtent */
sewardjfa8ec112005-01-19 11:55:34 +0000333 }
334 Sector;
sewardjde4a1d02002-03-22 01:27:54 +0000335
sewardjde4a1d02002-03-22 01:27:54 +0000336
sewardj6c3769f2002-11-29 01:02:45 +0000337/*------------------ DECLS ------------------*/
338
sewardjfa8ec112005-01-19 11:55:34 +0000339/* The root data structure is an array of sectors. The index of the
340 youngest sector is recorded, and new translations are put into that
341 sector. When it fills up, we move along to the next sector and
342 start to fill that up, wrapping around at the end of the array.
343 That way, once all N_TC_SECTORS have been bought into use for the
344 first time, and are full, we then re-use the oldest sector,
345 endlessly.
sewardj6c3769f2002-11-29 01:02:45 +0000346
sewardjfa8ec112005-01-19 11:55:34 +0000347 When running, youngest sector should be between >= 0 and <
348 N_TC_SECTORS. The initial -1 value indicates the TT/TC system is
349 not yet initialised.
350*/
351static Sector sectors[N_SECTORS];
352static Int youngest_sector = -1;
sewardj6c3769f2002-11-29 01:02:45 +0000353
sewardjfa8ec112005-01-19 11:55:34 +0000354/* The number of ULongs in each TCEntry area. This is computed once
355 at startup and does not change. */
356static Int tc_sector_szQ;
nethercote92e7b7f2004-08-07 17:52:25 +0000357
358
sewardj5d0d1f32010-03-14 15:09:27 +0000359/* A list of sector numbers, in the order which they should be
360 searched to find translations. This is an optimisation to be used
361 when searching for translations and should not affect
362 correctness. -1 denotes "no entry". */
363static Int sector_search_order[N_SECTORS];
364
365
sewardj5f76de02007-02-11 05:08:06 +0000366/* Fast helper for the TC. A direct-mapped cache which holds a set of
367 recently used (guest address, host address) pairs. This array is
368 referred to directly from m_dispatch/dispatch-<platform>.S.
sewardj8aef1192002-07-24 09:36:36 +0000369
sewardj5f76de02007-02-11 05:08:06 +0000370 Entries in tt_fast may refer to any valid TC entry, regardless of
sewardjfa8ec112005-01-19 11:55:34 +0000371 which sector it's in. Consequently we must be very careful to
372 invalidate this cache when TC entries are changed or disappear.
373
sewardj5f76de02007-02-11 05:08:06 +0000374 A special .guest address - TRANSTAB_BOGUS_GUEST_ADDR -- must be
375 pointed at to cause that cache entry to miss. This relies on the
376 assumption that no guest code actually has that address, hence a
377 value 0x1 seems good. m_translate gives the client a synthetic
378 segfault if it tries to execute at this address.
sewardjfa8ec112005-01-19 11:55:34 +0000379*/
sewardj5f76de02007-02-11 05:08:06 +0000380/*
381typedef
382 struct {
383 Addr guest;
384 Addr host;
385 }
386 FastCacheEntry;
387*/
388/*global*/ __attribute__((aligned(16)))
389 FastCacheEntry VG_(tt_fast)[VG_TT_FAST_SIZE];
sewardjfa8ec112005-01-19 11:55:34 +0000390
sewardj663a1bd2005-04-24 11:22:44 +0000391/* Make sure we're not used before initialisation. */
392static Bool init_done = False;
393
394
sewardjfa8ec112005-01-19 11:55:34 +0000395/*------------------ STATS DECLS ------------------*/
396
397/* Number of fast-cache updates and flushes done. */
sewardj291849f2012-04-20 23:58:55 +0000398static ULong n_fast_flushes = 0;
399static ULong n_fast_updates = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000400
401/* Number of full lookups done. */
sewardj291849f2012-04-20 23:58:55 +0000402static ULong n_full_lookups = 0;
403static ULong n_lookup_probes = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000404
sewardj26412bd2005-07-07 10:05:05 +0000405/* Number/osize/tsize of translations entered; also the number of
406 those for which self-checking was requested. */
sewardj291849f2012-04-20 23:58:55 +0000407static ULong n_in_count = 0;
408static ULong n_in_osize = 0;
409static ULong n_in_tsize = 0;
410static ULong n_in_sc_count = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000411
412/* Number/osize of translations discarded due to lack of space. */
sewardj291849f2012-04-20 23:58:55 +0000413static ULong n_dump_count = 0;
414static ULong n_dump_osize = 0;
sewardjfa8ec112005-01-19 11:55:34 +0000415
416/* Number/osize of translations discarded due to requests to do so. */
sewardj291849f2012-04-20 23:58:55 +0000417static ULong n_disc_count = 0;
418static ULong n_disc_osize = 0;
419
420
421/*-------------------------------------------------------------*/
422/*--- Misc ---*/
423/*-------------------------------------------------------------*/
424
425static void* ttaux_malloc ( HChar* tag, SizeT n )
426{
427 return VG_(arena_malloc)(VG_AR_TTAUX, tag, n);
428}
429
430static void ttaux_free ( void* p )
431{
432 VG_(arena_free)(VG_AR_TTAUX, p);
433}
434
435
436/*-------------------------------------------------------------*/
437/*--- Chaining support ---*/
438/*-------------------------------------------------------------*/
439
440static inline TTEntry* index_tte ( UInt sNo, UInt tteNo )
441{
442 vg_assert(sNo < N_SECTORS);
443 vg_assert(tteNo < N_TTES_PER_SECTOR);
444 Sector* s = &sectors[sNo];
445 vg_assert(s->tt);
446 TTEntry* tte = &s->tt[tteNo];
447 vg_assert(tte->status == InUse);
448 return tte;
449}
450
451static void InEdge__init ( InEdge* ie )
452{
453 ie->from_sNo = -1; /* invalid */
454 ie->from_tteNo = 0;
455 ie->from_offs = 0;
456 ie->to_fastEP = False;
457}
458
459static void OutEdge__init ( OutEdge* oe )
460{
461 oe->to_sNo = -1; /* invalid */
462 oe->to_tteNo = 0;
463 oe->from_offs = 0;
464}
465
466static void TTEntry__init ( TTEntry* tte )
467{
468 VG_(memset)(tte, 0, sizeof(*tte));
469}
470
471static UWord InEdgeArr__size ( InEdgeArr* iea )
472{
473 if (iea->var) {
474 vg_assert(iea->n_fixed == 0);
475 return VG_(sizeXA)(iea->var);
476 } else {
477 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
478 return iea->n_fixed;
479 }
480}
481
482static void InEdgeArr__makeEmpty ( InEdgeArr* iea )
483{
484 if (iea->var) {
485 vg_assert(iea->n_fixed == 0);
486 VG_(deleteXA)(iea->var);
487 iea->var = NULL;
488 } else {
489 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
490 iea->n_fixed = 0;
491 }
492}
493
494static
495InEdge* InEdgeArr__index ( InEdgeArr* iea, UWord i )
496{
497 if (iea->var) {
498 vg_assert(iea->n_fixed == 0);
499 return (InEdge*)VG_(indexXA)(iea->var, i);
500 } else {
501 vg_assert(i < iea->n_fixed);
502 return &iea->fixed[i];
503 }
504}
505
506static
507void InEdgeArr__deleteIndex ( InEdgeArr* iea, UWord i )
508{
509 if (iea->var) {
510 vg_assert(iea->n_fixed == 0);
511 VG_(removeIndexXA)(iea->var, i);
512 } else {
513 vg_assert(i < iea->n_fixed);
514 for (; i+1 < iea->n_fixed; i++) {
515 iea->fixed[i] = iea->fixed[i+1];
516 }
517 iea->n_fixed--;
518 }
519}
520
521static
522void InEdgeArr__add ( InEdgeArr* iea, InEdge* ie )
523{
524 if (iea->var) {
525 vg_assert(iea->n_fixed == 0);
526 VG_(addToXA)(iea->var, ie);
527 } else {
528 vg_assert(iea->n_fixed <= N_FIXED_IN_EDGE_ARR);
529 if (iea->n_fixed == N_FIXED_IN_EDGE_ARR) {
530 /* The fixed array is full, so we have to initialise an
531 XArray and copy the fixed array into it. */
532 iea->var = VG_(newXA)(ttaux_malloc, "transtab.IEA__add",
533 ttaux_free,
534 sizeof(InEdge));
535 UWord i;
536 for (i = 0; i < iea->n_fixed; i++) {
537 VG_(addToXA)(iea->var, &iea->fixed[i]);
538 }
539 VG_(addToXA)(iea->var, ie);
540 iea->n_fixed = 0;
541 } else {
542 /* Just add to the fixed array. */
543 iea->fixed[iea->n_fixed++] = *ie;
544 }
545 }
546}
547
548static UWord OutEdgeArr__size ( OutEdgeArr* oea )
549{
550 if (oea->var) {
551 vg_assert(oea->n_fixed == 0);
552 return VG_(sizeXA)(oea->var);
553 } else {
554 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
555 return oea->n_fixed;
556 }
557}
558
559static void OutEdgeArr__makeEmpty ( OutEdgeArr* oea )
560{
561 if (oea->var) {
562 vg_assert(oea->n_fixed == 0);
563 VG_(deleteXA)(oea->var);
564 oea->var = NULL;
565 } else {
566 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
567 oea->n_fixed = 0;
568 }
569}
570
571static
572OutEdge* OutEdgeArr__index ( OutEdgeArr* oea, UWord i )
573{
574 if (oea->var) {
575 vg_assert(oea->n_fixed == 0);
576 return (OutEdge*)VG_(indexXA)(oea->var, i);
577 } else {
578 vg_assert(i < oea->n_fixed);
579 return &oea->fixed[i];
580 }
581}
582
583static
584void OutEdgeArr__deleteIndex ( OutEdgeArr* oea, UWord i )
585{
586 if (oea->var) {
587 vg_assert(oea->n_fixed == 0);
588 VG_(removeIndexXA)(oea->var, i);
589 } else {
590 vg_assert(i < oea->n_fixed);
591 for (; i+1 < oea->n_fixed; i++) {
592 oea->fixed[i] = oea->fixed[i+1];
593 }
594 oea->n_fixed--;
595 }
596}
597
598static
599void OutEdgeArr__add ( OutEdgeArr* oea, OutEdge* oe )
600{
601 if (oea->var) {
602 vg_assert(oea->n_fixed == 0);
603 VG_(addToXA)(oea->var, oe);
604 } else {
605 vg_assert(oea->n_fixed <= N_FIXED_OUT_EDGE_ARR);
606 if (oea->n_fixed == N_FIXED_OUT_EDGE_ARR) {
607 /* The fixed array is full, so we have to initialise an
608 XArray and copy the fixed array into it. */
609 oea->var = VG_(newXA)(ttaux_malloc, "transtab.OEA__add",
610 ttaux_free,
611 sizeof(OutEdge));
612 UWord i;
613 for (i = 0; i < oea->n_fixed; i++) {
614 VG_(addToXA)(oea->var, &oea->fixed[i]);
615 }
616 VG_(addToXA)(oea->var, oe);
617 oea->n_fixed = 0;
618 } else {
619 /* Just add to the fixed array. */
620 oea->fixed[oea->n_fixed++] = *oe;
621 }
622 }
623}
624
625static
626Int HostExtent__cmpOrd ( void* v1, void* v2 )
627{
628 HostExtent* hx1 = (HostExtent*)v1;
629 HostExtent* hx2 = (HostExtent*)v2;
630 if (hx1->start + hx1->len <= hx2->start) return -1;
631 if (hx2->start + hx2->len <= hx1->start) return 1;
632 return 0; /* partial overlap */
633}
634
635static __attribute__((noinline))
636Bool find_TTEntry_from_hcode( /*OUT*/UInt* from_sNo,
637 /*OUT*/UInt* from_tteNo,
638 void* hcode )
639{
640 Int i;
641
642 /* Search order logic copied from VG_(search_transtab). */
643 for (i = 0; i < N_SECTORS; i++) {
644 Int sno = sector_search_order[i];
645 if (UNLIKELY(sno == -1))
646 return False; /* run out of sectors to search */
647
648 Sector* sec = &sectors[sno];
649 XArray* /* of HostExtent */ host_extents = sec->host_extents;
650 vg_assert(host_extents);
651
652 HostExtent key;
653 VG_(memset)(&key, 0, sizeof(key));
654 key.start = hcode;
655 key.len = 1;
656 Word firstW = -1, lastW = -1;
657 Bool found = VG_(lookupXA_UNSAFE)(
658 host_extents, &key, &firstW, &lastW,
659 (Int(*)(void*,void*))HostExtent__cmpOrd
660 );
661 vg_assert(firstW == lastW); // always true, even if not found
662 if (found) {
663 HostExtent* hx = VG_(indexXA)(host_extents, firstW);
664 UInt tteNo = hx->tteNo;
665 /* Do some additional sanity checks. */
666 vg_assert(tteNo <= N_TTES_PER_SECTOR);
667 /* Entry might have been invalidated. Consider this
668 as not found. */
669 if (sec->tt[tteNo].status == Deleted)
670 return False;
671 vg_assert(sec->tt[tteNo].status == InUse);
672 /* Can only half check that the found TTEntry contains hcode,
673 due to not having a length value for the hcode in the
674 TTEntry. */
675 vg_assert((UChar*)sec->tt[tteNo].tcptr <= (UChar*)hcode);
676 /* Looks plausible */
677 *from_sNo = sno;
678 *from_tteNo = (UInt)tteNo;
679 return True;
680 }
681 }
682 return False;
683}
684
685
686/* Figure out whether or not hcode is jitted code present in the main
687 code cache (but not in the no-redir cache). Used for sanity
688 checking. */
689static Bool is_in_the_main_TC ( void* hcode )
690{
691 Int i, sno;
692 for (i = 0; i < N_SECTORS; i++) {
693 sno = sector_search_order[i];
694 if (sno == -1)
695 break; /* run out of sectors to search */
696 if ((UChar*)hcode >= (UChar*)sectors[sno].tc
697 && (UChar*)hcode <= (UChar*)sectors[sno].tc_next
698 + sizeof(ULong) - 1)
699 return True;
700 }
701 return False;
702}
703
704
705/* Fulfill a chaining request, and record admin info so we
706 can undo it later, if required.
707*/
708void VG_(tt_tc_do_chaining) ( void* from__patch_addr,
709 UInt to_sNo,
710 UInt to_tteNo,
711 Bool to_fastEP )
712{
713 /* Get the CPU info established at startup. */
714 VexArch vex_arch = VexArch_INVALID;
715 VG_(machine_get_VexArchInfo)( &vex_arch, NULL );
716
717 // host_code is where we're patching to. So it needs to
718 // take into account, whether we're jumping to the slow
719 // or fast entry point. By definition, the fast entry point
720 // is exactly one event check's worth of code along from
721 // the slow (tcptr) entry point.
722 TTEntry* to_tte = index_tte(to_sNo, to_tteNo);
723 void* host_code = ((UChar*)to_tte->tcptr)
724 + (to_fastEP ? LibVEX_evCheckSzB(vex_arch) : 0);
725
726 // stay sane -- the patch point (dst) is in this sector's code cache
727 vg_assert( (UChar*)host_code >= (UChar*)sectors[to_sNo].tc );
728 vg_assert( (UChar*)host_code <= (UChar*)sectors[to_sNo].tc_next
729 + sizeof(ULong) - 1 );
730
731 /* Find the TTEntry for the from__ code. This isn't simple since
732 we only know the patch address, which is going to be somewhere
733 inside the from_ block. */
734 UInt from_sNo = (UInt)-1;
735 UInt from_tteNo = (UInt)-1;
736 Bool from_found
737 = find_TTEntry_from_hcode( &from_sNo, &from_tteNo,
738 from__patch_addr );
739 if (!from_found) {
740 // The from code might have been discarded due to sector re-use
741 // or marked Deleted due to translation invalidation.
742 // In such a case, don't do the chaining.
743 VG_(debugLog)(1,"transtab",
744 "host code %p not found (discarded? sector recycled?)"
745 " => no chaining done\n",
746 from__patch_addr);
747 return;
748 }
749
750 TTEntry* from_tte = index_tte(from_sNo, from_tteNo);
751
752 /* Get VEX to do the patching itself. We have to hand it off
753 since it is host-dependent. */
754 VexInvalRange vir
755 = LibVEX_Chain(
756 vex_arch,
757 from__patch_addr,
758 VG_(fnptr_to_fnentry)(
759 to_fastEP ? &VG_(disp_cp_chain_me_to_fastEP)
760 : &VG_(disp_cp_chain_me_to_slowEP)),
761 (void*)host_code
762 );
763 VG_(invalidate_icache)( (void*)vir.start, vir.len );
764
765 /* Now do the tricky bit -- update the ch_succs and ch_preds info
766 for the two translations involved, so we can undo the chaining
767 later, which we will have to do if the to_ block gets removed
768 for whatever reason. */
769
770 /* This is the new from_ -> to_ link to add. */
771 InEdge ie;
772 InEdge__init(&ie);
773 ie.from_sNo = from_sNo;
774 ie.from_tteNo = from_tteNo;
775 ie.to_fastEP = to_fastEP;
776 HWord from_offs = (HWord)( (UChar*)from__patch_addr
777 - (UChar*)from_tte->tcptr );
778 vg_assert(from_offs < 100000/* let's say */);
779 ie.from_offs = (UInt)from_offs;
780
781 /* This is the new to_ -> from_ backlink to add. */
782 OutEdge oe;
783 OutEdge__init(&oe);
784 oe.to_sNo = to_sNo;
785 oe.to_tteNo = to_tteNo;
786 oe.from_offs = (UInt)from_offs;
787
788 /* Add .. */
789 InEdgeArr__add(&to_tte->in_edges, &ie);
790 OutEdgeArr__add(&from_tte->out_edges, &oe);
791}
792
793
794/* Unchain one patch, as described by the specified InEdge. For
795 sanity check purposes only (to check that the patched location is
796 as expected) it also requires the fast and slow entry point
797 addresses of the destination block (that is, the block that owns
798 this InEdge). */
799__attribute__((noinline))
800static void unchain_one ( VexArch vex_arch,
801 InEdge* ie,
802 void* to_fastEPaddr, void* to_slowEPaddr )
803{
804 vg_assert(ie);
805 TTEntry* tte
806 = index_tte(ie->from_sNo, ie->from_tteNo);
807 UChar* place_to_patch
808 = ((HChar*)tte->tcptr) + ie->from_offs;
809 UChar* disp_cp_chain_me
810 = VG_(fnptr_to_fnentry)(
811 ie->to_fastEP ? &VG_(disp_cp_chain_me_to_fastEP)
812 : &VG_(disp_cp_chain_me_to_slowEP)
813 );
814 UChar* place_to_jump_to_EXPECTED
815 = ie->to_fastEP ? to_fastEPaddr : to_slowEPaddr;
816
817 // stay sane: both src and dst for this unchaining are
818 // in the main code cache
819 vg_assert( is_in_the_main_TC(place_to_patch) ); // src
820 vg_assert( is_in_the_main_TC(place_to_jump_to_EXPECTED) ); // dst
821 // dst check is ok because LibVEX_UnChain checks that
822 // place_to_jump_to_EXPECTED really is the current dst, and
823 // asserts if it isn't.
824 VexInvalRange vir
825 = LibVEX_UnChain( vex_arch, place_to_patch,
826 place_to_jump_to_EXPECTED, disp_cp_chain_me );
827 VG_(invalidate_icache)( (void*)vir.start, vir.len );
828}
829
830
831/* The specified block is about to be deleted. Update the preds and
832 succs of its associated blocks accordingly. This includes undoing
833 any chained jumps to this block. */
834static
835void unchain_in_preparation_for_deletion ( VexArch vex_arch,
836 UInt here_sNo, UInt here_tteNo )
837{
838 if (0)
839 VG_(printf)("QQQ unchain_in_prep %u.%u\n", here_sNo, here_tteNo);
840 UWord i, j, n, m;
841 Int evCheckSzB = LibVEX_evCheckSzB(vex_arch);
842 TTEntry* here_tte = index_tte(here_sNo, here_tteNo);
843 vg_assert(here_tte->status == InUse);
844
845 /* Visit all InEdges owned by here_tte. */
846 n = InEdgeArr__size(&here_tte->in_edges);
847 for (i = 0; i < n; i++) {
848 InEdge* ie = InEdgeArr__index(&here_tte->in_edges, i);
849 // Undo the chaining.
850 UChar* here_slow_EP = (UChar*)here_tte->tcptr;
851 UChar* here_fast_EP = here_slow_EP + evCheckSzB;
852 unchain_one(vex_arch, ie, here_fast_EP, here_slow_EP);
853 // Find the corresponding entry in the "from" node's out_edges,
854 // and remove it.
855 TTEntry* from_tte = index_tte(ie->from_sNo, ie->from_tteNo);
856 m = OutEdgeArr__size(&from_tte->out_edges);
857 vg_assert(m > 0); // it must have at least one entry
858 for (j = 0; j < m; j++) {
859 OutEdge* oe = OutEdgeArr__index(&from_tte->out_edges, j);
860 if (oe->to_sNo == here_sNo && oe->to_tteNo == here_tteNo
861 && oe->from_offs == ie->from_offs)
862 break;
863 }
864 vg_assert(j < m); // "oe must be findable"
865 OutEdgeArr__deleteIndex(&from_tte->out_edges, j);
866 }
867
868 /* Visit all OutEdges owned by here_tte. */
869 n = OutEdgeArr__size(&here_tte->out_edges);
870 for (i = 0; i < n; i++) {
871 OutEdge* oe = OutEdgeArr__index(&here_tte->out_edges, i);
872 // Find the corresponding entry in the "to" node's in_edges,
873 // and remove it.
874 TTEntry* to_tte = index_tte(oe->to_sNo, oe->to_tteNo);
875 m = InEdgeArr__size(&to_tte->in_edges);
876 vg_assert(m > 0); // it must have at least one entry
877 for (j = 0; j < m; j++) {
878 InEdge* ie = InEdgeArr__index(&to_tte->in_edges, j);
879 if (ie->from_sNo == here_sNo && ie->from_tteNo == here_tteNo
880 && ie->from_offs == oe->from_offs)
881 break;
882 }
883 vg_assert(j < m); // "ie must be findable"
884 InEdgeArr__deleteIndex(&to_tte->in_edges, j);
885 }
886
887 InEdgeArr__makeEmpty(&here_tte->in_edges);
888 OutEdgeArr__makeEmpty(&here_tte->out_edges);
889}
sewardjfa8ec112005-01-19 11:55:34 +0000890
891
sewardj6c1bbbb2005-10-18 02:30:42 +0000892/*-------------------------------------------------------------*/
893/*--- Address-range equivalence class stuff ---*/
894/*-------------------------------------------------------------*/
895
896/* Return equivalence class number for a range. */
897
898static Int range_to_eclass ( Addr64 start, UInt len )
899{
900 UInt mask = (1 << ECLASS_WIDTH) - 1;
901 UInt lo = (UInt)start;
902 UInt hi = lo + len - 1;
903 UInt loBits = (lo >> ECLASS_SHIFT) & mask;
904 UInt hiBits = (hi >> ECLASS_SHIFT) & mask;
905 if (loBits == hiBits) {
906 vg_assert(loBits < ECLASS_N-1);
907 return loBits;
908 } else {
909 return ECLASS_MISC;
910 }
911}
912
913
914/* Calculates the equivalence class numbers for any VexGuestExtent.
915 These are written in *eclasses, which must be big enough to hold 3
916 Ints. The number written, between 1 and 3, is returned. The
917 eclasses are presented in order, and any duplicates are removed.
918*/
919
920static
921Int vexGuestExtents_to_eclasses ( /*OUT*/Int* eclasses,
922 VexGuestExtents* vge )
923{
924# define SWAP(_lv1,_lv2) \
925 do { Int t = _lv1; _lv1 = _lv2; _lv2 = t; } while (0)
926
927 Int i, j, n_ec, r;
928
929 vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
930
931 n_ec = 0;
932 for (i = 0; i < vge->n_used; i++) {
933 r = range_to_eclass( vge->base[i], (UInt)vge->len[i] );
934 if (r == ECLASS_MISC)
935 goto bad;
936 /* only add if we haven't already seen it */
937 for (j = 0; j < n_ec; j++)
938 if (eclasses[j] == r)
939 break;
940 if (j == n_ec)
941 eclasses[n_ec++] = r;
942 }
943
944 if (n_ec == 1)
945 return 1;
946
947 if (n_ec == 2) {
948 /* sort */
949 if (eclasses[0] > eclasses[1])
950 SWAP(eclasses[0], eclasses[1]);
951 return 2;
952 }
953
954 if (n_ec == 3) {
955 /* sort */
956 if (eclasses[0] > eclasses[2])
957 SWAP(eclasses[0], eclasses[2]);
958 if (eclasses[0] > eclasses[1])
959 SWAP(eclasses[0], eclasses[1]);
960 if (eclasses[1] > eclasses[2])
961 SWAP(eclasses[1], eclasses[2]);
962 return 3;
963 }
964
965 /* NOTREACHED */
966 vg_assert(0);
967
968 bad:
969 eclasses[0] = ECLASS_MISC;
970 return 1;
971
972# undef SWAP
973}
974
975
976/* Add tteno to the set of entries listed for equivalence class ec in
977 this sector. Returns used location in eclass array. */
978
979static
980UInt addEClassNo ( /*MOD*/Sector* sec, Int ec, UShort tteno )
981{
982 Int old_sz, new_sz, i, r;
983 UShort *old_ar, *new_ar;
984
985 vg_assert(ec >= 0 && ec < ECLASS_N);
986 vg_assert(tteno < N_TTES_PER_SECTOR);
987
988 if (0) VG_(printf)("ec %d gets %d\n", ec, (Int)tteno);
989
990 if (sec->ec2tte_used[ec] >= sec->ec2tte_size[ec]) {
991
992 vg_assert(sec->ec2tte_used[ec] == sec->ec2tte_size[ec]);
993
994 old_sz = sec->ec2tte_size[ec];
995 old_ar = sec->ec2tte[ec];
996 new_sz = old_sz==0 ? 8 : old_sz<64 ? 2*old_sz : (3*old_sz)/2;
sewardj291849f2012-04-20 23:58:55 +0000997 new_ar = ttaux_malloc("transtab.aECN.1",
998 new_sz * sizeof(UShort));
sewardj6c1bbbb2005-10-18 02:30:42 +0000999 for (i = 0; i < old_sz; i++)
1000 new_ar[i] = old_ar[i];
1001 if (old_ar)
sewardj291849f2012-04-20 23:58:55 +00001002 ttaux_free(old_ar);
sewardj6c1bbbb2005-10-18 02:30:42 +00001003 sec->ec2tte_size[ec] = new_sz;
1004 sec->ec2tte[ec] = new_ar;
1005
1006 if (0) VG_(printf)("expand ec %d to %d\n", ec, new_sz);
1007 }
1008
1009 /* Common case */
1010 r = sec->ec2tte_used[ec]++;
1011 vg_assert(r >= 0 && r < sec->ec2tte_size[ec]);
1012 sec->ec2tte[ec][r] = tteno;
1013 return (UInt)r;
1014}
1015
1016
1017/* 'vge' is being added to 'sec' at TT entry 'tteno'. Add appropriate
1018 eclass entries to 'sec'. */
1019
1020static
1021void upd_eclasses_after_add ( /*MOD*/Sector* sec, Int tteno )
1022{
1023 Int i, r, eclasses[3];
1024 TTEntry* tte;
1025 vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
1026
1027 tte = &sec->tt[tteno];
1028 r = vexGuestExtents_to_eclasses( eclasses, &tte->vge );
1029
1030 vg_assert(r >= 1 && r <= 3);
1031 tte->n_tte2ec = r;
1032
1033 for (i = 0; i < r; i++) {
1034 tte->tte2ec_ec[i] = eclasses[i];
1035 tte->tte2ec_ix[i] = addEClassNo( sec, eclasses[i], (UShort)tteno );
1036 }
1037}
1038
1039
1040/* Check the eclass info in 'sec' to ensure it is consistent. Returns
1041 True if OK, False if something's not right. Expensive. */
1042
1043static Bool sanity_check_eclasses_in_sector ( Sector* sec )
1044{
1045# define BAD(_str) do { whassup = (_str); goto bad; } while (0)
1046
1047 HChar* whassup = NULL;
1048 Int i, j, k, n, ec_num, ec_idx;
1049 TTEntry* tte;
1050 UShort tteno;
1051 ULong* tce;
1052
1053 /* Basic checks on this sector */
1054 if (sec->tt_n_inuse < 0 || sec->tt_n_inuse > N_TTES_PER_SECTOR_USABLE)
1055 BAD("invalid sec->tt_n_inuse");
1056 tce = sec->tc_next;
1057 if (tce < &sec->tc[0] || tce > &sec->tc[tc_sector_szQ])
1058 BAD("sec->tc_next points outside tc");
1059
1060 /* For each eclass ... */
1061 for (i = 0; i < ECLASS_N; i++) {
1062 if (sec->ec2tte_size[i] == 0 && sec->ec2tte[i] != NULL)
1063 BAD("ec2tte_size/ec2tte mismatch(1)");
1064 if (sec->ec2tte_size[i] != 0 && sec->ec2tte[i] == NULL)
1065 BAD("ec2tte_size/ec2tte mismatch(2)");
1066 if (sec->ec2tte_used[i] < 0
1067 || sec->ec2tte_used[i] > sec->ec2tte_size[i])
1068 BAD("implausible ec2tte_used");
1069 if (sec->ec2tte_used[i] == 0)
1070 continue;
1071
1072 /* For each tt reference in each eclass .. ensure the reference
1073 is to a valid tt entry, and that the entry's address ranges
1074 really include this eclass. */
1075
1076 for (j = 0; j < sec->ec2tte_used[i]; j++) {
1077 tteno = sec->ec2tte[i][j];
1078 if (tteno == EC2TTE_DELETED)
1079 continue;
1080 if (tteno >= N_TTES_PER_SECTOR)
1081 BAD("implausible tteno");
1082 tte = &sec->tt[tteno];
1083 if (tte->status != InUse)
1084 BAD("tteno points to non-inuse tte");
1085 if (tte->n_tte2ec < 1 || tte->n_tte2ec > 3)
1086 BAD("tte->n_tte2ec out of range");
1087 /* Exactly least one of tte->eclasses[0 .. tte->n_eclasses-1]
1088 must equal i. Inspect tte's eclass info. */
1089 n = 0;
1090 for (k = 0; k < tte->n_tte2ec; k++) {
1091 if (k < tte->n_tte2ec-1
1092 && tte->tte2ec_ec[k] >= tte->tte2ec_ec[k+1])
1093 BAD("tte->tte2ec_ec[..] out of order");
1094 ec_num = tte->tte2ec_ec[k];
1095 if (ec_num < 0 || ec_num >= ECLASS_N)
1096 BAD("tte->tte2ec_ec[..] out of range");
1097 if (ec_num != i)
1098 continue;
1099 ec_idx = tte->tte2ec_ix[k];
1100 if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[i])
1101 BAD("tte->tte2ec_ix[..] out of range");
1102 if (ec_idx == j)
1103 n++;
1104 }
1105 if (n != 1)
1106 BAD("tteno does not point back at eclass");
1107 }
1108 }
1109
1110 /* That establishes that for each forward pointer from TTEntrys
1111 there is a corresponding backward pointer from the eclass[]
1112 arrays. However, it doesn't rule out the possibility of other,
1113 bogus pointers in the eclass[] arrays. So do those similarly:
1114 scan through them and check the TTEntryies they point at point
1115 back. */
1116
1117 for (i = 0; i < N_TTES_PER_SECTOR_USABLE; i++) {
1118
1119 tte = &sec->tt[i];
1120 if (tte->status == Empty || tte->status == Deleted) {
1121 if (tte->n_tte2ec != 0)
1122 BAD("tte->n_eclasses nonzero for unused tte");
1123 continue;
1124 }
1125
1126 vg_assert(tte->status == InUse);
1127
1128 if (tte->n_tte2ec < 1 || tte->n_tte2ec > 3)
1129 BAD("tte->n_eclasses out of range(2)");
1130
1131 for (j = 0; j < tte->n_tte2ec; j++) {
1132 ec_num = tte->tte2ec_ec[j];
1133 if (ec_num < 0 || ec_num >= ECLASS_N)
1134 BAD("tte->eclass[..] out of range");
1135 ec_idx = tte->tte2ec_ix[j];
1136 if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[ec_num])
1137 BAD("tte->ec_idx[..] out of range(2)");
1138 if (sec->ec2tte[ec_num][ec_idx] != i)
1139 BAD("ec2tte does not point back to tte");
1140 }
1141 }
1142
1143 return True;
1144
1145 bad:
1146 if (whassup)
1147 VG_(debugLog)(0, "transtab", "eclass sanity fail: %s\n", whassup);
1148
1149# if 0
1150 VG_(printf)("eclass = %d\n", i);
1151 VG_(printf)("tteno = %d\n", (Int)tteno);
1152 switch (tte->status) {
1153 case InUse: VG_(printf)("InUse\n"); break;
1154 case Deleted: VG_(printf)("Deleted\n"); break;
1155 case Empty: VG_(printf)("Empty\n"); break;
1156 }
1157 if (tte->status != Empty) {
1158 for (k = 0; k < tte->vge.n_used; k++)
1159 VG_(printf)("0x%llx %d\n", tte->vge.base[k],
1160 (Int)tte->vge.len[k]);
1161 }
1162# endif
1163
1164 return False;
1165
1166# undef BAD
1167}
1168
1169
1170/* Sanity check absolutely everything. True == check passed. */
1171
sewardj5f76de02007-02-11 05:08:06 +00001172/* forwards */
sewardj0ec07f32006-01-12 12:32:32 +00001173static Bool sanity_check_redir_tt_tc ( void );
1174
sewardj5d0d1f32010-03-14 15:09:27 +00001175static Bool sanity_check_sector_search_order ( void )
1176{
1177 Int i, j, nListed;
1178 /* assert the array is the right size */
1179 vg_assert(N_SECTORS == (sizeof(sector_search_order)
1180 / sizeof(sector_search_order[0])));
1181 /* Check it's of the form valid_sector_numbers ++ [-1, -1, ..] */
1182 for (i = 0; i < N_SECTORS; i++) {
1183 if (sector_search_order[i] < 0 || sector_search_order[i] >= N_SECTORS)
1184 break;
1185 }
1186 nListed = i;
1187 for (/* */; i < N_SECTORS; i++) {
1188 if (sector_search_order[i] != -1)
1189 break;
1190 }
1191 if (i != N_SECTORS)
1192 return False;
1193 /* Check each sector number only appears once */
1194 for (i = 0; i < N_SECTORS; i++) {
1195 if (sector_search_order[i] == -1)
1196 continue;
1197 for (j = i+1; j < N_SECTORS; j++) {
1198 if (sector_search_order[j] == sector_search_order[i])
1199 return False;
1200 }
1201 }
1202 /* Check that the number of listed sectors equals the number
1203 in use, by counting nListed back down. */
1204 for (i = 0; i < N_SECTORS; i++) {
1205 if (sectors[i].tc != NULL)
1206 nListed--;
1207 }
1208 if (nListed != 0)
1209 return False;
1210 return True;
1211}
1212
sewardj6c1bbbb2005-10-18 02:30:42 +00001213static Bool sanity_check_all_sectors ( void )
1214{
1215 Int sno;
1216 Bool sane;
1217 Sector* sec;
1218 for (sno = 0; sno < N_SECTORS; sno++) {
1219 sec = &sectors[sno];
1220 if (sec->tc == NULL)
1221 continue;
1222 sane = sanity_check_eclasses_in_sector( sec );
1223 if (!sane)
1224 return False;
1225 }
sewardj5f76de02007-02-11 05:08:06 +00001226 if ( !sanity_check_redir_tt_tc() )
1227 return False;
sewardj5d0d1f32010-03-14 15:09:27 +00001228 if ( !sanity_check_sector_search_order() )
1229 return False;
sewardj6c1bbbb2005-10-18 02:30:42 +00001230 return True;
1231}
1232
sewardjfa8ec112005-01-19 11:55:34 +00001233
sewardj5d0d1f32010-03-14 15:09:27 +00001234
sewardjfa8ec112005-01-19 11:55:34 +00001235/*-------------------------------------------------------------*/
sewardj6c1bbbb2005-10-18 02:30:42 +00001236/*--- Add/find translations ---*/
sewardjfa8ec112005-01-19 11:55:34 +00001237/*-------------------------------------------------------------*/
1238
1239static UInt vge_osize ( VexGuestExtents* vge )
sewardjc0d8f682002-11-30 00:49:43 +00001240{
sewardjfa8ec112005-01-19 11:55:34 +00001241 UInt i, n = 0;
1242 for (i = 0; i < vge->n_used; i++)
1243 n += (UInt)vge->len[i];
1244 return n;
sewardjc0d8f682002-11-30 00:49:43 +00001245}
1246
sewardjfa8ec112005-01-19 11:55:34 +00001247static Bool isValidSector ( Int sector )
sewardj6c3769f2002-11-29 01:02:45 +00001248{
sewardjfa8ec112005-01-19 11:55:34 +00001249 if (sector < 0 || sector >= N_SECTORS)
1250 return False;
1251 return True;
1252}
1253
1254static inline UInt HASH_TT ( Addr64 key )
1255{
1256 UInt kHi = (UInt)(key >> 32);
1257 UInt kLo = (UInt)key;
sewardj6c1bbbb2005-10-18 02:30:42 +00001258 UInt k32 = kHi ^ kLo;
1259 UInt ror = 7;
1260 if (ror > 0)
1261 k32 = (k32 >> ror) | (k32 << (32-ror));
1262 return k32 % N_TTES_PER_SECTOR;
sewardjfa8ec112005-01-19 11:55:34 +00001263}
1264
sewardj291849f2012-04-20 23:58:55 +00001265static void setFastCacheEntry ( Addr64 key, ULong* tcptr )
sewardjfa8ec112005-01-19 11:55:34 +00001266{
sewardj3387dda2005-12-26 17:58:58 +00001267 UInt cno = (UInt)VG_TT_FAST_HASH(key);
sewardj5f76de02007-02-11 05:08:06 +00001268 VG_(tt_fast)[cno].guest = (Addr)key;
1269 VG_(tt_fast)[cno].host = (Addr)tcptr;
sewardjfa8ec112005-01-19 11:55:34 +00001270 n_fast_updates++;
sewardj5f76de02007-02-11 05:08:06 +00001271 /* This shouldn't fail. It should be assured by m_translate
1272 which should reject any attempt to make translation of code
1273 starting at TRANSTAB_BOGUS_GUEST_ADDR. */
1274 vg_assert(VG_(tt_fast)[cno].guest != TRANSTAB_BOGUS_GUEST_ADDR);
sewardjfa8ec112005-01-19 11:55:34 +00001275}
1276
sewardj291849f2012-04-20 23:58:55 +00001277/* Invalidate the fast cache VG_(tt_fast). */
sewardjfa8ec112005-01-19 11:55:34 +00001278static void invalidateFastCache ( void )
1279{
1280 UInt j;
sewardj65e19392005-10-19 01:32:41 +00001281 /* This loop is popular enough to make it worth unrolling a
1282 bit, at least on ppc32. */
1283 vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
1284 for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
sewardj5f76de02007-02-11 05:08:06 +00001285 VG_(tt_fast)[j+0].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1286 VG_(tt_fast)[j+1].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1287 VG_(tt_fast)[j+2].guest = TRANSTAB_BOGUS_GUEST_ADDR;
1288 VG_(tt_fast)[j+3].guest = TRANSTAB_BOGUS_GUEST_ADDR;
sewardjfa8ec112005-01-19 11:55:34 +00001289 }
sewardj5f76de02007-02-11 05:08:06 +00001290
sewardj65e19392005-10-19 01:32:41 +00001291 vg_assert(j == VG_TT_FAST_SIZE);
sewardjfa8ec112005-01-19 11:55:34 +00001292 n_fast_flushes++;
1293}
1294
1295static void initialiseSector ( Int sno )
1296{
sewardj291849f2012-04-20 23:58:55 +00001297 Int i;
1298 SysRes sres;
sewardj6c1bbbb2005-10-18 02:30:42 +00001299 Sector* sec;
sewardjfa8ec112005-01-19 11:55:34 +00001300 vg_assert(isValidSector(sno));
1301
sewardj5d0d1f32010-03-14 15:09:27 +00001302 { Bool sane = sanity_check_sector_search_order();
1303 vg_assert(sane);
1304 }
sewardj6c1bbbb2005-10-18 02:30:42 +00001305 sec = &sectors[sno];
1306
1307 if (sec->tc == NULL) {
1308
sewardjfa8ec112005-01-19 11:55:34 +00001309 /* Sector has never been used before. Need to allocate tt and
1310 tc. */
sewardj6c1bbbb2005-10-18 02:30:42 +00001311 vg_assert(sec->tt == NULL);
1312 vg_assert(sec->tc_next == NULL);
1313 vg_assert(sec->tt_n_inuse == 0);
1314 for (i = 0; i < ECLASS_N; i++) {
1315 vg_assert(sec->ec2tte_size[i] == 0);
1316 vg_assert(sec->ec2tte_used[i] == 0);
1317 vg_assert(sec->ec2tte[i] == NULL);
1318 }
sewardj291849f2012-04-20 23:58:55 +00001319 vg_assert(sec->host_extents == NULL);
sewardj45f4e7c2005-09-27 19:20:21 +00001320
1321 VG_(debugLog)(1,"transtab", "allocate sector %d\n", sno);
1322
1323 sres = VG_(am_mmap_anon_float_valgrind)( 8 * tc_sector_szQ );
njncda2f0f2009-05-18 02:12:08 +00001324 if (sr_isError(sres)) {
sewardj45f4e7c2005-09-27 19:20:21 +00001325 VG_(out_of_memory_NORETURN)("initialiseSector(TC)",
1326 8 * tc_sector_szQ );
1327 /*NOTREACHED*/
1328 }
njncda2f0f2009-05-18 02:12:08 +00001329 sec->tc = (ULong*)(AddrH)sr_Res(sres);
sewardj45f4e7c2005-09-27 19:20:21 +00001330
1331 sres = VG_(am_mmap_anon_float_valgrind)
1332 ( N_TTES_PER_SECTOR * sizeof(TTEntry) );
njncda2f0f2009-05-18 02:12:08 +00001333 if (sr_isError(sres)) {
sewardj45f4e7c2005-09-27 19:20:21 +00001334 VG_(out_of_memory_NORETURN)("initialiseSector(TT)",
1335 N_TTES_PER_SECTOR * sizeof(TTEntry) );
1336 /*NOTREACHED*/
1337 }
njncda2f0f2009-05-18 02:12:08 +00001338 sec->tt = (TTEntry*)(AddrH)sr_Res(sres);
sewardj6c1bbbb2005-10-18 02:30:42 +00001339
1340 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
1341 sec->tt[i].status = Empty;
1342 sec->tt[i].n_tte2ec = 0;
1343 }
sewardj45f4e7c2005-09-27 19:20:21 +00001344
sewardj291849f2012-04-20 23:58:55 +00001345 /* Set up the host_extents array. */
1346 sec->host_extents
1347 = VG_(newXA)(ttaux_malloc, "transtab.initialiseSector(host_extents)",
1348 ttaux_free,
1349 sizeof(HostExtent));
1350
sewardj5d0d1f32010-03-14 15:09:27 +00001351 /* Add an entry in the sector_search_order */
1352 for (i = 0; i < N_SECTORS; i++) {
1353 if (sector_search_order[i] == -1)
1354 break;
1355 }
1356 vg_assert(i >= 0 && i < N_SECTORS);
1357 sector_search_order[i] = sno;
1358
sewardjfa8ec112005-01-19 11:55:34 +00001359 if (VG_(clo_verbosity) > 2)
sewardj738856f2009-07-15 14:48:32 +00001360 VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d\n", sno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001361
sewardjfa8ec112005-01-19 11:55:34 +00001362 } else {
sewardj6c1bbbb2005-10-18 02:30:42 +00001363
1364 /* Sector has been used before. Dump the old contents. */
sewardj45f4e7c2005-09-27 19:20:21 +00001365 VG_(debugLog)(1,"transtab", "recycle sector %d\n", sno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001366 vg_assert(sec->tt != NULL);
1367 vg_assert(sec->tc_next != NULL);
1368 n_dump_count += sec->tt_n_inuse;
1369
sewardj291849f2012-04-20 23:58:55 +00001370 VexArch vex_arch = VexArch_INVALID;
1371 VG_(machine_get_VexArchInfo)( &vex_arch, NULL );
1372
sewardj6c1bbbb2005-10-18 02:30:42 +00001373 /* Visit each just-about-to-be-abandoned translation. */
sewardje25053c2012-04-23 09:53:20 +00001374 if (0) VG_(printf)("QQQ unlink-entire-sector: %d START\n", sno);
sewardjfa8ec112005-01-19 11:55:34 +00001375 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
sewardj6c1bbbb2005-10-18 02:30:42 +00001376 if (sec->tt[i].status == InUse) {
1377 vg_assert(sec->tt[i].n_tte2ec >= 1);
1378 vg_assert(sec->tt[i].n_tte2ec <= 3);
1379 n_dump_osize += vge_osize(&sec->tt[i].vge);
sewardj37867722005-10-12 10:51:01 +00001380 /* Tell the tool too. */
sewardj0b9d74a2006-12-24 02:24:11 +00001381 if (VG_(needs).superblock_discards) {
1382 VG_TDICT_CALL( tool_discard_superblock_info,
sewardj4ba057c2005-10-18 12:04:18 +00001383 sec->tt[i].entry,
sewardj6c1bbbb2005-10-18 02:30:42 +00001384 sec->tt[i].vge );
sewardj37867722005-10-12 10:51:01 +00001385 }
sewardj291849f2012-04-20 23:58:55 +00001386 unchain_in_preparation_for_deletion(vex_arch, sno, i);
sewardj6c1bbbb2005-10-18 02:30:42 +00001387 } else {
1388 vg_assert(sec->tt[i].n_tte2ec == 0);
1389 }
1390 sec->tt[i].status = Empty;
1391 sec->tt[i].n_tte2ec = 0;
1392 }
sewardje25053c2012-04-23 09:53:20 +00001393 if (0) VG_(printf)("QQQ unlink-entire-sector: %d END\n", sno);
sewardj6c1bbbb2005-10-18 02:30:42 +00001394
1395 /* Free up the eclass structures. */
1396 for (i = 0; i < ECLASS_N; i++) {
1397 if (sec->ec2tte_size[i] == 0) {
1398 vg_assert(sec->ec2tte_used[i] == 0);
1399 vg_assert(sec->ec2tte[i] == NULL);
1400 } else {
1401 vg_assert(sec->ec2tte[i] != NULL);
sewardj291849f2012-04-20 23:58:55 +00001402 ttaux_free(sec->ec2tte[i]);
sewardj6c1bbbb2005-10-18 02:30:42 +00001403 sec->ec2tte[i] = NULL;
1404 sec->ec2tte_size[i] = 0;
1405 sec->ec2tte_used[i] = 0;
sewardjfa8ec112005-01-19 11:55:34 +00001406 }
1407 }
sewardj6c1bbbb2005-10-18 02:30:42 +00001408
sewardj291849f2012-04-20 23:58:55 +00001409 /* Empty out the host extents array. */
1410 vg_assert(sec->host_extents != NULL);
1411 VG_(dropTailXA)(sec->host_extents, VG_(sizeXA)(sec->host_extents));
1412 vg_assert(VG_(sizeXA)(sec->host_extents) == 0);
1413
sewardj5d0d1f32010-03-14 15:09:27 +00001414 /* Sanity check: ensure it is already in
1415 sector_search_order[]. */
1416 for (i = 0; i < N_SECTORS; i++) {
1417 if (sector_search_order[i] == sno)
1418 break;
1419 }
1420 vg_assert(i >= 0 && i < N_SECTORS);
1421
sewardjfa8ec112005-01-19 11:55:34 +00001422 if (VG_(clo_verbosity) > 2)
sewardj738856f2009-07-15 14:48:32 +00001423 VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d\n", sno);
sewardjfa8ec112005-01-19 11:55:34 +00001424 }
1425
sewardj6c1bbbb2005-10-18 02:30:42 +00001426 sec->tc_next = sec->tc;
1427 sec->tt_n_inuse = 0;
sewardjfa8ec112005-01-19 11:55:34 +00001428
1429 invalidateFastCache();
sewardj5d0d1f32010-03-14 15:09:27 +00001430
1431 { Bool sane = sanity_check_sector_search_order();
1432 vg_assert(sane);
1433 }
sewardj6c3769f2002-11-29 01:02:45 +00001434}
1435
1436
sewardjfa8ec112005-01-19 11:55:34 +00001437/* Add a translation of vge to TT/TC. The translation is temporarily
1438 in code[0 .. code_len-1].
1439
1440 pre: youngest_sector points to a valid (although possibly full)
1441 sector.
1442*/
njn8bddf582005-05-13 23:40:55 +00001443void VG_(add_to_transtab)( VexGuestExtents* vge,
1444 Addr64 entry,
1445 AddrH code,
sewardj26412bd2005-07-07 10:05:05 +00001446 UInt code_len,
sewardj291849f2012-04-20 23:58:55 +00001447 Bool is_self_checking,
1448 Int offs_profInc,
1449 VexArch arch_host )
sewardj6c3769f2002-11-29 01:02:45 +00001450{
sewardjfa8ec112005-01-19 11:55:34 +00001451 Int tcAvailQ, reqdQ, y, i;
sewardj5f76de02007-02-11 05:08:06 +00001452 ULong *tcptr, *tcptr2;
sewardjfa8ec112005-01-19 11:55:34 +00001453 UChar* srcP;
1454 UChar* dstP;
1455
sewardj663a1bd2005-04-24 11:22:44 +00001456 vg_assert(init_done);
sewardjfa8ec112005-01-19 11:55:34 +00001457 vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
sewardje8089302006-10-17 02:15:17 +00001458
1459 /* 60000: should agree with N_TMPBUF in m_translate.c. */
1460 vg_assert(code_len > 0 && code_len < 60000);
sewardjfa8ec112005-01-19 11:55:34 +00001461
1462 if (0)
njn8bddf582005-05-13 23:40:55 +00001463 VG_(printf)("add_to_transtab(entry = 0x%llx, len = %d)\n",
sewardjfa8ec112005-01-19 11:55:34 +00001464 entry, code_len);
1465
1466 n_in_count++;
1467 n_in_tsize += code_len;
1468 n_in_osize += vge_osize(vge);
sewardj26412bd2005-07-07 10:05:05 +00001469 if (is_self_checking)
1470 n_in_sc_count++;
sewardjfa8ec112005-01-19 11:55:34 +00001471
1472 y = youngest_sector;
1473 vg_assert(isValidSector(y));
1474
1475 if (sectors[y].tc == NULL)
1476 initialiseSector(y);
1477
1478 /* Try putting the translation in this sector. */
sewardj5f76de02007-02-11 05:08:06 +00001479 reqdQ = (code_len + 7) >> 3;
sewardjfa8ec112005-01-19 11:55:34 +00001480
1481 /* Will it fit in tc? */
1482 tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
1483 - ((ULong*)(sectors[y].tc_next));
1484 vg_assert(tcAvailQ >= 0);
1485 vg_assert(tcAvailQ <= tc_sector_szQ);
1486
1487 if (tcAvailQ < reqdQ
1488 || sectors[y].tt_n_inuse >= N_TTES_PER_SECTOR_USABLE) {
1489 /* No. So move on to the next sector. Either it's never been
1490 used before, in which case it will get its tt/tc allocated
1491 now, or it has been used before, in which case it is set to be
1492 empty, hence throwing out the oldest sector. */
sewardja16ea0a2005-09-30 10:34:06 +00001493 vg_assert(tc_sector_szQ > 0);
1494 VG_(debugLog)(1,"transtab",
1495 "declare sector %d full "
1496 "(TT loading %2d%%, TC loading %2d%%)\n",
1497 y,
1498 (100 * sectors[y].tt_n_inuse)
1499 / N_TTES_PER_SECTOR,
1500 (100 * (tc_sector_szQ - tcAvailQ))
1501 / tc_sector_szQ);
sewardjfa8ec112005-01-19 11:55:34 +00001502 youngest_sector++;
1503 if (youngest_sector >= N_SECTORS)
1504 youngest_sector = 0;
1505 y = youngest_sector;
1506 initialiseSector(y);
1507 }
1508
1509 /* Be sure ... */
1510 tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
1511 - ((ULong*)(sectors[y].tc_next));
1512 vg_assert(tcAvailQ >= 0);
1513 vg_assert(tcAvailQ <= tc_sector_szQ);
1514 vg_assert(tcAvailQ >= reqdQ);
1515 vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR_USABLE);
1516 vg_assert(sectors[y].tt_n_inuse >= 0);
1517
1518 /* Copy into tc. */
sewardj5f76de02007-02-11 05:08:06 +00001519 tcptr = sectors[y].tc_next;
1520 vg_assert(tcptr >= &sectors[y].tc[0]);
1521 vg_assert(tcptr <= &sectors[y].tc[tc_sector_szQ]);
sewardjfa8ec112005-01-19 11:55:34 +00001522
sewardj5f76de02007-02-11 05:08:06 +00001523 dstP = (UChar*)tcptr;
sewardjfa8ec112005-01-19 11:55:34 +00001524 srcP = (UChar*)code;
sewardj291849f2012-04-20 23:58:55 +00001525 VG_(memcpy)(dstP, srcP, code_len);
sewardjfa8ec112005-01-19 11:55:34 +00001526 sectors[y].tc_next += reqdQ;
1527 sectors[y].tt_n_inuse++;
1528
1529 /* more paranoia */
sewardj5f76de02007-02-11 05:08:06 +00001530 tcptr2 = sectors[y].tc_next;
1531 vg_assert(tcptr2 >= &sectors[y].tc[0]);
1532 vg_assert(tcptr2 <= &sectors[y].tc[tc_sector_szQ]);
sewardjfa8ec112005-01-19 11:55:34 +00001533
1534 /* Find an empty tt slot, and use it. There must be such a slot
1535 since tt is never allowed to get completely full. */
1536 i = HASH_TT(entry);
1537 vg_assert(i >= 0 && i < N_TTES_PER_SECTOR);
sewardj6c3769f2002-11-29 01:02:45 +00001538 while (True) {
sewardjfa8ec112005-01-19 11:55:34 +00001539 if (sectors[y].tt[i].status == Empty
1540 || sectors[y].tt[i].status == Deleted)
sewardj6c3769f2002-11-29 01:02:45 +00001541 break;
1542 i++;
sewardjfa8ec112005-01-19 11:55:34 +00001543 if (i >= N_TTES_PER_SECTOR)
sewardj6c3769f2002-11-29 01:02:45 +00001544 i = 0;
1545 }
sewardj22854b92002-11-30 14:00:47 +00001546
sewardj291849f2012-04-20 23:58:55 +00001547 TTEntry__init(&sectors[y].tt[i]);
sewardjfa8ec112005-01-19 11:55:34 +00001548 sectors[y].tt[i].status = InUse;
sewardj5f76de02007-02-11 05:08:06 +00001549 sectors[y].tt[i].tcptr = tcptr;
sewardjfa8ec112005-01-19 11:55:34 +00001550 sectors[y].tt[i].count = 0;
1551 sectors[y].tt[i].weight = 1;
1552 sectors[y].tt[i].vge = *vge;
1553 sectors[y].tt[i].entry = entry;
1554
sewardj291849f2012-04-20 23:58:55 +00001555 /* Patch in the profile counter location, if necessary. */
1556 if (offs_profInc != -1) {
1557 vg_assert(offs_profInc >= 0 && offs_profInc < code_len);
1558 VexInvalRange vir
1559 = LibVEX_PatchProfInc( arch_host,
1560 dstP + offs_profInc,
1561 &sectors[y].tt[i].count );
1562 VG_(invalidate_icache)( (void*)vir.start, vir.len );
1563 }
1564
1565 VG_(invalidate_icache)( dstP, code_len );
1566
1567 /* Add this entry to the host_extents map, checking that we're
1568 adding in order. */
1569 { HostExtent hx;
1570 hx.start = (UChar*)tcptr;
1571 hx.len = code_len;
1572 hx.tteNo = i;
1573 vg_assert(hx.len > 0); /* bsearch fails w/ zero length entries */
1574 XArray* hx_array = sectors[y].host_extents;
1575 vg_assert(hx_array);
1576 Word n = VG_(sizeXA)(hx_array);
1577 if (n > 0) {
1578 HostExtent* hx_prev = (HostExtent*)VG_(indexXA)(hx_array, n-1);
1579 vg_assert(hx_prev->start + hx_prev->len <= hx.start);
1580 }
1581 VG_(addToXA)(hx_array, &hx);
1582 }
1583
sewardj6c1bbbb2005-10-18 02:30:42 +00001584 /* Update the fast-cache. */
sewardj291849f2012-04-20 23:58:55 +00001585 setFastCacheEntry( entry, tcptr );
sewardj6c1bbbb2005-10-18 02:30:42 +00001586
1587 /* Note the eclass numbers for this translation. */
1588 upd_eclasses_after_add( &sectors[y], i );
sewardj6c3769f2002-11-29 01:02:45 +00001589}
1590
1591
sewardjfa8ec112005-01-19 11:55:34 +00001592/* Search for the translation of the given guest address. If
1593 requested, a successful search can also cause the fast-caches to be
1594 updated.
sewardj6c3769f2002-11-29 01:02:45 +00001595*/
sewardj291849f2012-04-20 23:58:55 +00001596Bool VG_(search_transtab) ( /*OUT*/AddrH* res_hcode,
1597 /*OUT*/UInt* res_sNo,
1598 /*OUT*/UInt* res_tteNo,
sewardjfa8ec112005-01-19 11:55:34 +00001599 Addr64 guest_addr,
1600 Bool upd_cache )
sewardj6c3769f2002-11-29 01:02:45 +00001601{
sewardjfa8ec112005-01-19 11:55:34 +00001602 Int i, j, k, kstart, sno;
sewardj663a1bd2005-04-24 11:22:44 +00001603
1604 vg_assert(init_done);
sewardjfa8ec112005-01-19 11:55:34 +00001605 /* Find the initial probe point just once. It will be the same in
1606 all sectors and avoids multiple expensive % operations. */
1607 n_full_lookups++;
1608 k = -1;
1609 kstart = HASH_TT(guest_addr);
1610 vg_assert(kstart >= 0 && kstart < N_TTES_PER_SECTOR);
sewardj6c3769f2002-11-29 01:02:45 +00001611
sewardj5d0d1f32010-03-14 15:09:27 +00001612 /* Search in all the sectors,using sector_search_order[] as a
1613 heuristic guide as to what order to visit the sectors. */
sewardjfa8ec112005-01-19 11:55:34 +00001614 for (i = 0; i < N_SECTORS; i++) {
sewardj6c3769f2002-11-29 01:02:45 +00001615
sewardj5d0d1f32010-03-14 15:09:27 +00001616 sno = sector_search_order[i];
1617 if (UNLIKELY(sno == -1))
1618 return False; /* run out of sectors to search */
sewardj6c3769f2002-11-29 01:02:45 +00001619
sewardjfa8ec112005-01-19 11:55:34 +00001620 k = kstart;
1621 for (j = 0; j < N_TTES_PER_SECTOR; j++) {
1622 n_lookup_probes++;
1623 if (sectors[sno].tt[k].status == InUse
1624 && sectors[sno].tt[k].entry == guest_addr) {
1625 /* found it */
1626 if (upd_cache)
1627 setFastCacheEntry(
sewardj291849f2012-04-20 23:58:55 +00001628 guest_addr, sectors[sno].tt[k].tcptr );
1629 if (res_hcode)
1630 *res_hcode = (AddrH)sectors[sno].tt[k].tcptr;
1631 if (res_sNo)
1632 *res_sNo = sno;
1633 if (res_tteNo)
1634 *res_tteNo = k;
sewardj5d0d1f32010-03-14 15:09:27 +00001635 /* pull this one one step closer to the front. For large
1636 apps this more or less halves the number of required
1637 probes. */
1638 if (i > 0) {
1639 Int tmp = sector_search_order[i-1];
1640 sector_search_order[i-1] = sector_search_order[i];
1641 sector_search_order[i] = tmp;
1642 }
sewardjfa8ec112005-01-19 11:55:34 +00001643 return True;
1644 }
1645 if (sectors[sno].tt[k].status == Empty)
1646 break; /* not found in this sector */
1647 k++;
1648 if (k == N_TTES_PER_SECTOR)
1649 k = 0;
sewardj6c3769f2002-11-29 01:02:45 +00001650 }
sewardjfa8ec112005-01-19 11:55:34 +00001651
1652 /* If we fall off the end, all entries are InUse and not
1653 matching, or Deleted. In any case we did not find it in this
1654 sector. */
sewardj6c3769f2002-11-29 01:02:45 +00001655 }
sewardjfa8ec112005-01-19 11:55:34 +00001656
1657 /* Not found in any sector. */
1658 return False;
sewardj6c3769f2002-11-29 01:02:45 +00001659}
1660
1661
sewardj6c1bbbb2005-10-18 02:30:42 +00001662/*-------------------------------------------------------------*/
1663/*--- Delete translations. ---*/
1664/*-------------------------------------------------------------*/
1665
sewardj0ec07f32006-01-12 12:32:32 +00001666/* forward */
1667static void unredir_discard_translations( Addr64, ULong );
1668
sewardj6c1bbbb2005-10-18 02:30:42 +00001669/* Stuff for deleting translations which intersect with a given
1670 address range. Unfortunately, to make this run at a reasonable
1671 speed, it is complex. */
sewardjfa8ec112005-01-19 11:55:34 +00001672
1673static inline
sewardja3054502005-07-26 23:04:25 +00001674Bool overlap1 ( Addr64 s1, ULong r1, Addr64 s2, ULong r2 )
sewardjfa8ec112005-01-19 11:55:34 +00001675{
sewardja3054502005-07-26 23:04:25 +00001676 Addr64 e1 = s1 + r1 - 1ULL;
1677 Addr64 e2 = s2 + r2 - 1ULL;
sewardjfa8ec112005-01-19 11:55:34 +00001678 if (e1 < s2 || e2 < s1)
1679 return False;
1680 return True;
1681}
1682
1683static inline
sewardja3054502005-07-26 23:04:25 +00001684Bool overlaps ( Addr64 start, ULong range, VexGuestExtents* vge )
sewardjfa8ec112005-01-19 11:55:34 +00001685{
1686 if (overlap1(start, range, vge->base[0], (UInt)vge->len[0]))
1687 return True;
1688 if (vge->n_used < 2)
1689 return False;
1690 if (overlap1(start, range, vge->base[1], (UInt)vge->len[1]))
1691 return True;
1692 if (vge->n_used < 3)
1693 return False;
1694 if (overlap1(start, range, vge->base[2], (UInt)vge->len[2]))
1695 return True;
1696 return False;
1697}
1698
1699
sewardj6c1bbbb2005-10-18 02:30:42 +00001700/* Delete a tt entry, and update all the eclass data accordingly. */
1701
sewardj291849f2012-04-20 23:58:55 +00001702static void delete_tte ( /*MOD*/Sector* sec, UInt secNo, Int tteno,
1703 VexArch vex_arch )
sewardj6c1bbbb2005-10-18 02:30:42 +00001704{
1705 Int i, ec_num, ec_idx;
1706 TTEntry* tte;
1707
sewardj291849f2012-04-20 23:58:55 +00001708 /* sec and secNo are mutually redundant; cross-check. */
1709 vg_assert(sec == &sectors[secNo]);
1710
sewardj6c1bbbb2005-10-18 02:30:42 +00001711 vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
1712 tte = &sec->tt[tteno];
1713 vg_assert(tte->status == InUse);
1714 vg_assert(tte->n_tte2ec >= 1 && tte->n_tte2ec <= 3);
1715
sewardj291849f2012-04-20 23:58:55 +00001716 /* Unchain .. */
1717 unchain_in_preparation_for_deletion(vex_arch, secNo, tteno);
1718
sewardj6c1bbbb2005-10-18 02:30:42 +00001719 /* Deal with the ec-to-tte links first. */
1720 for (i = 0; i < tte->n_tte2ec; i++) {
1721 ec_num = (Int)tte->tte2ec_ec[i];
1722 ec_idx = tte->tte2ec_ix[i];
1723 vg_assert(ec_num >= 0 && ec_num < ECLASS_N);
1724 vg_assert(ec_idx >= 0);
1725 vg_assert(ec_idx < sec->ec2tte_used[ec_num]);
1726 /* Assert that the two links point at each other. */
1727 vg_assert(sec->ec2tte[ec_num][ec_idx] == (UShort)tteno);
1728 /* "delete" the pointer back to here. */
1729 sec->ec2tte[ec_num][ec_idx] = EC2TTE_DELETED;
1730 }
1731
1732 /* Now fix up this TTEntry. */
1733 tte->status = Deleted;
1734 tte->n_tte2ec = 0;
1735
1736 /* Stats .. */
1737 sec->tt_n_inuse--;
1738 n_disc_count++;
1739 n_disc_osize += vge_osize(&tte->vge);
1740
1741 /* Tell the tool too. */
sewardj0b9d74a2006-12-24 02:24:11 +00001742 if (VG_(needs).superblock_discards) {
1743 VG_TDICT_CALL( tool_discard_superblock_info,
sewardj4ba057c2005-10-18 12:04:18 +00001744 tte->entry,
sewardj6c1bbbb2005-10-18 02:30:42 +00001745 tte->vge );
1746 }
1747}
1748
1749
1750/* Delete translations from sec which intersect specified range, but
1751 only consider translations in the specified eclass. */
1752
1753static
sewardj291849f2012-04-20 23:58:55 +00001754Bool delete_translations_in_sector_eclass ( /*MOD*/Sector* sec, UInt secNo,
sewardj6c1bbbb2005-10-18 02:30:42 +00001755 Addr64 guest_start, ULong range,
sewardj291849f2012-04-20 23:58:55 +00001756 Int ec,
1757 VexArch vex_arch )
sewardj6c1bbbb2005-10-18 02:30:42 +00001758{
1759 Int i;
1760 UShort tteno;
1761 Bool anyDeld = False;
1762 TTEntry* tte;
1763
1764 vg_assert(ec >= 0 && ec < ECLASS_N);
1765
1766 for (i = 0; i < sec->ec2tte_used[ec]; i++) {
1767
1768 tteno = sec->ec2tte[ec][i];
1769 if (tteno == EC2TTE_DELETED) {
1770 /* already deleted */
1771 continue;
1772 }
1773
1774 vg_assert(tteno < N_TTES_PER_SECTOR);
1775
1776 tte = &sec->tt[tteno];
1777 vg_assert(tte->status == InUse);
1778
1779 if (overlaps( guest_start, range, &tte->vge )) {
1780 anyDeld = True;
sewardj291849f2012-04-20 23:58:55 +00001781 delete_tte( sec, secNo, (Int)tteno, vex_arch );
sewardj6c1bbbb2005-10-18 02:30:42 +00001782 }
1783
1784 }
1785
1786 return anyDeld;
1787}
1788
1789
1790/* Delete translations from sec which intersect specified range, the
1791 slow way, by inspecting all translations in sec. */
1792
1793static
sewardj291849f2012-04-20 23:58:55 +00001794Bool delete_translations_in_sector ( /*MOD*/Sector* sec, UInt secNo,
1795 Addr64 guest_start, ULong range,
1796 VexArch vex_arch )
sewardj6c1bbbb2005-10-18 02:30:42 +00001797{
1798 Int i;
1799 Bool anyDeld = False;
1800
1801 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
1802 if (sec->tt[i].status == InUse
1803 && overlaps( guest_start, range, &sec->tt[i].vge )) {
1804 anyDeld = True;
sewardj291849f2012-04-20 23:58:55 +00001805 delete_tte( sec, secNo, i, vex_arch );
sewardj6c1bbbb2005-10-18 02:30:42 +00001806 }
1807 }
1808
1809 return anyDeld;
1810}
1811
1812
sewardj45f4e7c2005-09-27 19:20:21 +00001813void VG_(discard_translations) ( Addr64 guest_start, ULong range,
1814 HChar* who )
sewardjfa8ec112005-01-19 11:55:34 +00001815{
sewardj6c1bbbb2005-10-18 02:30:42 +00001816 Sector* sec;
1817 Int sno, ec;
1818 Bool anyDeleted = False;
sewardjfa8ec112005-01-19 11:55:34 +00001819
sewardj663a1bd2005-04-24 11:22:44 +00001820 vg_assert(init_done);
1821
sewardja16ea0a2005-09-30 10:34:06 +00001822 VG_(debugLog)(2, "transtab",
sewardj45f4e7c2005-09-27 19:20:21 +00001823 "discard_translations(0x%llx, %lld) req by %s\n",
1824 guest_start, range, who );
1825
sewardj6c1bbbb2005-10-18 02:30:42 +00001826 /* Pre-deletion sanity check */
1827 if (VG_(clo_sanity_level >= 4)) {
1828 Bool sane = sanity_check_all_sectors();
1829 vg_assert(sane);
1830 }
1831
1832 if (range == 0)
1833 return;
1834
sewardj291849f2012-04-20 23:58:55 +00001835 VexArch vex_arch = VexArch_INVALID;
1836 VG_(machine_get_VexArchInfo)( &vex_arch, NULL );
1837
sewardj6c1bbbb2005-10-18 02:30:42 +00001838 /* There are two different ways to do this.
1839
1840 If the range fits within a single address-range equivalence
1841 class, as will be the case for a cache line sized invalidation,
1842 then we only have to inspect the set of translations listed in
1843 that equivalence class, and also in the "sin-bin" equivalence
1844 class ECLASS_MISC.
1845
1846 Otherwise, the invalidation is of a larger range and probably
1847 results from munmap. In this case it's (probably!) faster just
1848 to inspect all translations, dump those we don't want, and
1849 regenerate the equivalence class information (since modifying it
1850 in-situ is even more expensive).
1851 */
1852
1853 /* First off, figure out if the range falls within a single class,
1854 and if so which one. */
1855
1856 ec = ECLASS_MISC;
1857 if (range < (1ULL << ECLASS_SHIFT))
1858 ec = range_to_eclass( guest_start, (UInt)range );
1859
1860 /* if ec is ECLASS_MISC then we aren't looking at just a single
1861 class, so use the slow scheme. Else use the fast scheme,
1862 examining 'ec' and ECLASS_MISC. */
1863
1864 if (ec != ECLASS_MISC) {
1865
1866 VG_(debugLog)(2, "transtab",
1867 " FAST, ec = %d\n", ec);
1868
1869 /* Fast scheme */
1870 vg_assert(ec >= 0 && ec < ECLASS_MISC);
1871
1872 for (sno = 0; sno < N_SECTORS; sno++) {
1873 sec = &sectors[sno];
1874 if (sec->tc == NULL)
1875 continue;
1876 anyDeleted |= delete_translations_in_sector_eclass(
sewardj291849f2012-04-20 23:58:55 +00001877 sec, sno, guest_start, range, ec,
1878 vex_arch
1879 );
sewardj6c1bbbb2005-10-18 02:30:42 +00001880 anyDeleted |= delete_translations_in_sector_eclass(
sewardj291849f2012-04-20 23:58:55 +00001881 sec, sno, guest_start, range, ECLASS_MISC,
1882 vex_arch
1883 );
sewardj6c1bbbb2005-10-18 02:30:42 +00001884 }
1885
1886 } else {
1887
1888 /* slow scheme */
1889
1890 VG_(debugLog)(2, "transtab",
1891 " SLOW, ec = %d\n", ec);
1892
1893 for (sno = 0; sno < N_SECTORS; sno++) {
1894 sec = &sectors[sno];
1895 if (sec->tc == NULL)
1896 continue;
1897 anyDeleted |= delete_translations_in_sector(
sewardj291849f2012-04-20 23:58:55 +00001898 sec, sno, guest_start, range, vex_arch );
sewardj6c1bbbb2005-10-18 02:30:42 +00001899 }
1900
sewardjfa8ec112005-01-19 11:55:34 +00001901 }
1902
1903 if (anyDeleted)
1904 invalidateFastCache();
sewardj6c1bbbb2005-10-18 02:30:42 +00001905
sewardj0ec07f32006-01-12 12:32:32 +00001906 /* don't forget the no-redir cache */
1907 unredir_discard_translations( guest_start, range );
1908
sewardj6c1bbbb2005-10-18 02:30:42 +00001909 /* Post-deletion sanity check */
1910 if (VG_(clo_sanity_level >= 4)) {
1911 Int i;
1912 TTEntry* tte;
1913 Bool sane = sanity_check_all_sectors();
1914 vg_assert(sane);
1915 /* But now, also check the requested address range isn't
1916 present anywhere. */
1917 for (sno = 0; sno < N_SECTORS; sno++) {
1918 sec = &sectors[sno];
1919 if (sec->tc == NULL)
1920 continue;
1921 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
1922 tte = &sec->tt[i];
1923 if (tte->status != InUse)
1924 continue;
1925 vg_assert(!overlaps( guest_start, range, &tte->vge ));
1926 }
1927 }
1928 }
sewardjfa8ec112005-01-19 11:55:34 +00001929}
1930
1931
1932/*------------------------------------------------------------*/
sewardj0ec07f32006-01-12 12:32:32 +00001933/*--- AUXILIARY: the unredirected TT/TC ---*/
1934/*------------------------------------------------------------*/
1935
1936/* A very simple translation cache which holds a small number of
1937 unredirected translations. This is completely independent of the
1938 main tt/tc structures. When unredir_tc or unredir_tt becomes full,
1939 both structures are simply dumped and we start over.
1940
1941 Since these translations are unredirected, the search key is (by
1942 definition) the first address entry in the .vge field. */
1943
1944/* Sized to hold 500 translations of average size 1000 bytes. */
1945
1946#define UNREDIR_SZB 1000
1947
1948#define N_UNREDIR_TT 500
1949#define N_UNREDIR_TCQ (N_UNREDIR_TT * UNREDIR_SZB / sizeof(ULong))
1950
1951typedef
1952 struct {
1953 VexGuestExtents vge;
1954 Addr hcode;
1955 Bool inUse;
1956 }
1957 UTCEntry;
1958
1959/* We just allocate forwards in _tc, never deleting. */
tom78c0c092006-01-13 09:57:01 +00001960static ULong *unredir_tc;
1961static Int unredir_tc_used = N_UNREDIR_TCQ;
sewardj0ec07f32006-01-12 12:32:32 +00001962
1963/* Slots in _tt can come into use and out again (.inUse).
1964 Nevertheless _tt_highwater is maintained so that invalidations
1965 don't have to scan all the slots when only a few are in use.
1966 _tt_highwater holds the index of the highest ever allocated
1967 slot. */
1968static UTCEntry unredir_tt[N_UNREDIR_TT];
1969static Int unredir_tt_highwater;
1970
1971
1972static void init_unredir_tt_tc ( void )
1973{
1974 Int i;
tom78c0c092006-01-13 09:57:01 +00001975 if (unredir_tc == NULL) {
njncda2f0f2009-05-18 02:12:08 +00001976 SysRes sres = VG_(am_mmap_anon_float_valgrind)
1977 ( N_UNREDIR_TT * UNREDIR_SZB );
1978 if (sr_isError(sres)) {
1979 VG_(out_of_memory_NORETURN)("init_unredir_tt_tc",
1980 N_UNREDIR_TT * UNREDIR_SZB);
tom78c0c092006-01-13 09:57:01 +00001981 /*NOTREACHED*/
1982 }
njncda2f0f2009-05-18 02:12:08 +00001983 unredir_tc = (ULong *)(AddrH)sr_Res(sres);
tom78c0c092006-01-13 09:57:01 +00001984 }
sewardj0ec07f32006-01-12 12:32:32 +00001985 unredir_tc_used = 0;
1986 for (i = 0; i < N_UNREDIR_TT; i++)
1987 unredir_tt[i].inUse = False;
1988 unredir_tt_highwater = -1;
1989}
1990
1991/* Do a sanity check; return False on failure. */
1992static Bool sanity_check_redir_tt_tc ( void )
1993{
1994 Int i;
1995 if (unredir_tt_highwater < -1) return False;
1996 if (unredir_tt_highwater >= N_UNREDIR_TT) return False;
1997
1998 for (i = unredir_tt_highwater+1; i < N_UNREDIR_TT; i++)
1999 if (unredir_tt[i].inUse)
2000 return False;
2001
2002 if (unredir_tc_used < 0) return False;
2003 if (unredir_tc_used > N_UNREDIR_TCQ) return False;
2004
2005 return True;
2006}
2007
2008
2009/* Add an UNREDIRECTED translation of vge to TT/TC. The translation
2010 is temporarily in code[0 .. code_len-1].
2011*/
2012void VG_(add_to_unredir_transtab)( VexGuestExtents* vge,
2013 Addr64 entry,
2014 AddrH code,
njn1dcee092009-02-24 03:07:37 +00002015 UInt code_len )
sewardj0ec07f32006-01-12 12:32:32 +00002016{
2017 Int i, j, code_szQ;
2018 HChar *srcP, *dstP;
2019
2020 vg_assert(sanity_check_redir_tt_tc());
2021
2022 /* This is the whole point: it's not redirected! */
2023 vg_assert(entry == vge->base[0]);
2024
2025 /* How many unredir_tt slots are needed */
2026 code_szQ = (code_len + 7) / 8;
2027
2028 /* Look for an empty unredir_tc slot */
2029 for (i = 0; i < N_UNREDIR_TT; i++)
2030 if (!unredir_tt[i].inUse)
2031 break;
2032
2033 if (i >= N_UNREDIR_TT || code_szQ > (N_UNREDIR_TCQ - unredir_tc_used)) {
2034 /* It's full; dump everything we currently have */
2035 init_unredir_tt_tc();
2036 i = 0;
2037 }
2038
2039 vg_assert(unredir_tc_used >= 0);
2040 vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
2041 vg_assert(code_szQ > 0);
2042 vg_assert(code_szQ + unredir_tc_used <= N_UNREDIR_TCQ);
2043 vg_assert(i >= 0 && i < N_UNREDIR_TT);
2044 vg_assert(unredir_tt[i].inUse == False);
2045
2046 if (i > unredir_tt_highwater)
2047 unredir_tt_highwater = i;
2048
2049 dstP = (HChar*)&unredir_tc[unredir_tc_used];
2050 srcP = (HChar*)code;
2051 for (j = 0; j < code_len; j++)
2052 dstP[j] = srcP[j];
2053
sewardj291849f2012-04-20 23:58:55 +00002054 VG_(invalidate_icache)( dstP, code_len );
sewardjc0a02f82006-04-07 12:47:05 +00002055
sewardj0ec07f32006-01-12 12:32:32 +00002056 unredir_tt[i].inUse = True;
2057 unredir_tt[i].vge = *vge;
2058 unredir_tt[i].hcode = (Addr)dstP;
2059
2060 unredir_tc_used += code_szQ;
2061 vg_assert(unredir_tc_used >= 0);
2062 vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
2063
2064 vg_assert(&dstP[code_len] <= (HChar*)&unredir_tc[unredir_tc_used]);
2065}
2066
2067Bool VG_(search_unredir_transtab) ( /*OUT*/AddrH* result,
2068 Addr64 guest_addr )
2069{
2070 Int i;
2071 for (i = 0; i < N_UNREDIR_TT; i++) {
2072 if (!unredir_tt[i].inUse)
2073 continue;
2074 if (unredir_tt[i].vge.base[0] == guest_addr) {
2075 *result = (AddrH)unredir_tt[i].hcode;
2076 return True;
2077 }
2078 }
2079 return False;
2080}
2081
2082static void unredir_discard_translations( Addr64 guest_start, ULong range )
2083{
2084 Int i;
2085
2086 vg_assert(sanity_check_redir_tt_tc());
2087
2088 for (i = 0; i <= unredir_tt_highwater; i++) {
2089 if (unredir_tt[i].inUse
2090 && overlaps( guest_start, range, &unredir_tt[i].vge))
2091 unredir_tt[i].inUse = False;
2092 }
2093}
2094
2095
2096/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002097/*--- Initialisation. ---*/
2098/*------------------------------------------------------------*/
2099
sewardjc0d8f682002-11-30 00:49:43 +00002100void VG_(init_tt_tc) ( void )
2101{
sewardj6c1bbbb2005-10-18 02:30:42 +00002102 Int i, j, avg_codeszQ;
sewardjc0d8f682002-11-30 00:49:43 +00002103
sewardj663a1bd2005-04-24 11:22:44 +00002104 vg_assert(!init_done);
2105 init_done = True;
2106
sewardj4ccf7072004-11-28 16:58:05 +00002107 /* Otherwise lots of things go wrong... */
sewardjfa8ec112005-01-19 11:55:34 +00002108 vg_assert(sizeof(ULong) == 8);
2109 vg_assert(sizeof(Addr64) == 8);
sewardj5f76de02007-02-11 05:08:06 +00002110 /* check fast cache entries really are 2 words long */
2111 vg_assert(sizeof(Addr) == sizeof(void*));
2112 vg_assert(sizeof(FastCacheEntry) == 2 * sizeof(Addr));
2113 /* check fast cache entries are packed back-to-back with no spaces */
2114 vg_assert(sizeof( VG_(tt_fast) ) == VG_TT_FAST_SIZE * sizeof(FastCacheEntry));
2115 /* check fast cache is aligned as we requested. Not fatal if it
2116 isn't, but we might as well make sure. */
2117 vg_assert(VG_IS_16_ALIGNED( ((Addr) & VG_(tt_fast)[0]) ));
sewardjfa8ec112005-01-19 11:55:34 +00002118
2119 if (VG_(clo_verbosity) > 2)
2120 VG_(message)(Vg_DebugMsg,
2121 "TT/TC: VG_(init_tt_tc) "
sewardj738856f2009-07-15 14:48:32 +00002122 "(startup of code management)\n");
sewardjfa8ec112005-01-19 11:55:34 +00002123
2124 /* Figure out how big each tc area should be. */
njn43b9a8a2005-05-10 04:37:01 +00002125 avg_codeszQ = (VG_(details).avg_translation_sizeB + 7) / 8;
2126 tc_sector_szQ = N_TTES_PER_SECTOR_USABLE * (1 + avg_codeszQ);
sewardjfa8ec112005-01-19 11:55:34 +00002127
sewardjc0d8f682002-11-30 00:49:43 +00002128 /* Ensure the calculated value is not way crazy. */
sewardjfa8ec112005-01-19 11:55:34 +00002129 vg_assert(tc_sector_szQ >= 2 * N_TTES_PER_SECTOR_USABLE);
sewardj1e0fff62011-01-10 15:01:03 +00002130 vg_assert(tc_sector_szQ <= 100 * N_TTES_PER_SECTOR_USABLE);
sewardjc0d8f682002-11-30 00:49:43 +00002131
sewardjfa8ec112005-01-19 11:55:34 +00002132 /* Initialise the sectors */
2133 youngest_sector = 0;
2134 for (i = 0; i < N_SECTORS; i++) {
2135 sectors[i].tc = NULL;
2136 sectors[i].tt = NULL;
2137 sectors[i].tc_next = NULL;
2138 sectors[i].tt_n_inuse = 0;
sewardj6c1bbbb2005-10-18 02:30:42 +00002139 for (j = 0; j < ECLASS_N; j++) {
2140 sectors[i].ec2tte_size[j] = 0;
2141 sectors[i].ec2tte_used[j] = 0;
2142 sectors[i].ec2tte[j] = NULL;
2143 }
sewardj291849f2012-04-20 23:58:55 +00002144 sectors[i].host_extents = NULL;
sewardjc0d8f682002-11-30 00:49:43 +00002145 }
sewardjc0d8f682002-11-30 00:49:43 +00002146
sewardj5d0d1f32010-03-14 15:09:27 +00002147 /* Initialise the sector_search_order hint table. */
2148 for (i = 0; i < N_SECTORS; i++)
2149 sector_search_order[i] = -1;
2150
sewardj291849f2012-04-20 23:58:55 +00002151 /* Initialise the fast cache. */
sewardjfa8ec112005-01-19 11:55:34 +00002152 invalidateFastCache();
sewardjc0d8f682002-11-30 00:49:43 +00002153
sewardj0ec07f32006-01-12 12:32:32 +00002154 /* and the unredir tt/tc */
2155 init_unredir_tt_tc();
2156
sewardjc0d8f682002-11-30 00:49:43 +00002157 if (VG_(clo_verbosity) > 2) {
2158 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002159 "TT/TC: cache: %d sectors of %d bytes each = %d total\n",
sewardjfa8ec112005-01-19 11:55:34 +00002160 N_SECTORS, 8 * tc_sector_szQ,
2161 N_SECTORS * 8 * tc_sector_szQ );
sewardjc0d8f682002-11-30 00:49:43 +00002162 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002163 "TT/TC: table: %d total entries, max occupancy %d (%d%%)\n",
sewardjfa8ec112005-01-19 11:55:34 +00002164 N_SECTORS * N_TTES_PER_SECTOR,
2165 N_SECTORS * N_TTES_PER_SECTOR_USABLE,
2166 SECTOR_TT_LIMIT_PERCENT );
2167 }
sewardj45f4e7c2005-09-27 19:20:21 +00002168
2169 VG_(debugLog)(2, "transtab",
2170 "cache: %d sectors of %d bytes each = %d total\n",
2171 N_SECTORS, 8 * tc_sector_szQ,
2172 N_SECTORS * 8 * tc_sector_szQ );
2173 VG_(debugLog)(2, "transtab",
2174 "table: %d total entries, max occupancy %d (%d%%)\n",
2175 N_SECTORS * N_TTES_PER_SECTOR,
2176 N_SECTORS * N_TTES_PER_SECTOR_USABLE,
2177 SECTOR_TT_LIMIT_PERCENT );
sewardjfa8ec112005-01-19 11:55:34 +00002178}
2179
2180
2181/*------------------------------------------------------------*/
2182/*--- Printing out statistics. ---*/
2183/*------------------------------------------------------------*/
2184
2185static ULong safe_idiv( ULong a, ULong b )
2186{
2187 return (b == 0 ? 0 : a / b);
2188}
2189
2190UInt VG_(get_bbs_translated) ( void )
2191{
2192 return n_in_count;
2193}
2194
2195void VG_(print_tt_tc_stats) ( void )
2196{
2197 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002198 " tt/tc: %'llu tt lookups requiring %'llu probes\n",
sewardjfa8ec112005-01-19 11:55:34 +00002199 n_full_lookups, n_lookup_probes );
2200 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002201 " tt/tc: %'llu fast-cache updates, %'llu flushes\n",
sewardjfa8ec112005-01-19 11:55:34 +00002202 n_fast_updates, n_fast_flushes );
2203
2204 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00002205 " transtab: new %'lld "
sewardj738856f2009-07-15 14:48:32 +00002206 "(%'llu -> %'llu; ratio %'llu:10) [%'llu scs]\n",
sewardjfa8ec112005-01-19 11:55:34 +00002207 n_in_count, n_in_osize, n_in_tsize,
sewardj26412bd2005-07-07 10:05:05 +00002208 safe_idiv(10*n_in_tsize, n_in_osize),
2209 n_in_sc_count);
sewardjfa8ec112005-01-19 11:55:34 +00002210 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002211 " transtab: dumped %'llu (%'llu -> ?" "?)\n",
sewardjfa8ec112005-01-19 11:55:34 +00002212 n_dump_count, n_dump_osize );
2213 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00002214 " transtab: discarded %'llu (%'llu -> ?" "?)\n",
sewardjfa8ec112005-01-19 11:55:34 +00002215 n_disc_count, n_disc_osize );
sewardj6c1bbbb2005-10-18 02:30:42 +00002216
2217 if (0) {
2218 Int i;
2219 VG_(printf)("\n");
2220 for (i = 0; i < ECLASS_N; i++) {
2221 VG_(printf)(" %4d", sectors[0].ec2tte_used[i]);
2222 if (i % 16 == 15)
2223 VG_(printf)("\n");
2224 }
2225 VG_(printf)("\n\n");
2226 }
sewardjfa8ec112005-01-19 11:55:34 +00002227}
2228
2229/*------------------------------------------------------------*/
2230/*--- Printing out of profiling results. ---*/
2231/*------------------------------------------------------------*/
2232
sewardjfa8ec112005-01-19 11:55:34 +00002233static ULong score ( TTEntry* tte )
2234{
2235 return ((ULong)tte->weight) * ((ULong)tte->count);
2236}
2237
njn2025cf92005-06-26 20:44:48 +00002238ULong VG_(get_BB_profile) ( BBProfEntry tops[], UInt n_tops )
sewardjfa8ec112005-01-19 11:55:34 +00002239{
sewardjfa8ec112005-01-19 11:55:34 +00002240 Int sno, i, r, s;
njn2025cf92005-06-26 20:44:48 +00002241 ULong score_total;
sewardjfa8ec112005-01-19 11:55:34 +00002242
2243 /* First, compute the total weighted count, and find the top N
njn2025cf92005-06-26 20:44:48 +00002244 ttes. tops contains pointers to the most-used n_tops blocks, in
sewardjfa8ec112005-01-19 11:55:34 +00002245 descending order (viz, tops[0] is the highest scorer). */
njn2025cf92005-06-26 20:44:48 +00002246 for (i = 0; i < n_tops; i++) {
2247 tops[i].addr = 0;
2248 tops[i].score = 0;
2249 }
sewardjfa8ec112005-01-19 11:55:34 +00002250
2251 score_total = 0;
2252
2253 for (sno = 0; sno < N_SECTORS; sno++) {
2254 if (sectors[sno].tc == NULL)
2255 continue;
2256 for (i = 0; i < N_TTES_PER_SECTOR; i++) {
2257 if (sectors[sno].tt[i].status != InUse)
2258 continue;
2259 score_total += score(&sectors[sno].tt[i]);
2260 /* Find the rank for sectors[sno].tt[i]. */
njn2025cf92005-06-26 20:44:48 +00002261 r = n_tops-1;
sewardjfa8ec112005-01-19 11:55:34 +00002262 while (True) {
2263 if (r == -1)
2264 break;
njn2025cf92005-06-26 20:44:48 +00002265 if (tops[r].addr == 0) {
sewardjfa8ec112005-01-19 11:55:34 +00002266 r--;
2267 continue;
2268 }
njn2025cf92005-06-26 20:44:48 +00002269 if ( score(&sectors[sno].tt[i]) > tops[r].score ) {
sewardjfa8ec112005-01-19 11:55:34 +00002270 r--;
2271 continue;
2272 }
2273 break;
2274 }
2275 r++;
njn2025cf92005-06-26 20:44:48 +00002276 vg_assert(r >= 0 && r <= n_tops);
sewardjfa8ec112005-01-19 11:55:34 +00002277 /* This bb should be placed at r, and bbs above it shifted
2278 upwards one slot. */
njn2025cf92005-06-26 20:44:48 +00002279 if (r < n_tops) {
2280 for (s = n_tops-1; s > r; s--)
sewardjfa8ec112005-01-19 11:55:34 +00002281 tops[s] = tops[s-1];
njn2025cf92005-06-26 20:44:48 +00002282 tops[r].addr = sectors[sno].tt[i].entry;
2283 tops[r].score = score( &sectors[sno].tt[i] );
sewardjfa8ec112005-01-19 11:55:34 +00002284 }
2285 }
sewardjc0d8f682002-11-30 00:49:43 +00002286 }
2287
njn2025cf92005-06-26 20:44:48 +00002288 return score_total;
sewardjc0d8f682002-11-30 00:49:43 +00002289}
2290
sewardjde4a1d02002-03-22 01:27:54 +00002291/*--------------------------------------------------------------------*/
njn8bddf582005-05-13 23:40:55 +00002292/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00002293/*--------------------------------------------------------------------*/