m_transtab.c revision 132bfccd21960e462352175f8553a5bdce8a210c
1de4a1d01951937632098a6cda45859afa587a06fsewardj
2de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
3de4a1d01951937632098a6cda45859afa587a06fsewardj/*--- Management of the translation table and cache.               ---*/
48bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn/*---                                                 m_transtab.c ---*/
5de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
6de4a1d01951937632098a6cda45859afa587a06fsewardj
7de4a1d01951937632098a6cda45859afa587a06fsewardj/*
8b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   This file is part of Valgrind, a dynamic binary instrumentation
9b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   framework.
10de4a1d01951937632098a6cda45859afa587a06fsewardj
11fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Copyright (C) 2000-2005 Julian Seward
12de4a1d01951937632098a6cda45859afa587a06fsewardj      jseward@acm.org
13de4a1d01951937632098a6cda45859afa587a06fsewardj
14de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is free software; you can redistribute it and/or
15de4a1d01951937632098a6cda45859afa587a06fsewardj   modify it under the terms of the GNU General Public License as
16de4a1d01951937632098a6cda45859afa587a06fsewardj   published by the Free Software Foundation; either version 2 of the
17de4a1d01951937632098a6cda45859afa587a06fsewardj   License, or (at your option) any later version.
18de4a1d01951937632098a6cda45859afa587a06fsewardj
19de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is distributed in the hope that it will be useful, but
20de4a1d01951937632098a6cda45859afa587a06fsewardj   WITHOUT ANY WARRANTY; without even the implied warranty of
21de4a1d01951937632098a6cda45859afa587a06fsewardj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22de4a1d01951937632098a6cda45859afa587a06fsewardj   General Public License for more details.
23de4a1d01951937632098a6cda45859afa587a06fsewardj
24de4a1d01951937632098a6cda45859afa587a06fsewardj   You should have received a copy of the GNU General Public License
25de4a1d01951937632098a6cda45859afa587a06fsewardj   along with this program; if not, write to the Free Software
26de4a1d01951937632098a6cda45859afa587a06fsewardj   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27de4a1d01951937632098a6cda45859afa587a06fsewardj   02111-1307, USA.
28de4a1d01951937632098a6cda45859afa587a06fsewardj
29e49d8e7dfd3a9c96feb9935b5920973dfc0b170anjn   The GNU General Public License is contained in the file COPYING.
30de4a1d01951937632098a6cda45859afa587a06fsewardj*/
31de4a1d01951937632098a6cda45859afa587a06fsewardj
32f1e5e1554292c92840da50ed4cf89062b69be597nethercote#include "core.h"
33ea27e4627518665dd6c81213c0ba1f7ff0218e1anjn#include "pub_core_debuginfo.h"
3497405b2d134b52880d6dbec3eb2929e2002c2542njn#include "pub_core_libcbase.h"
35132bfccd21960e462352175f8553a5bdce8a210cnjn#include "pub_core_libcassert.h"
3636a20fa5f779a0a6fb7b4a90dcaa6376481f1faanjn#include "pub_core_libcprint.h"
372024234c590f408994b373abfb00bc2cd2a90c48njn#include "pub_core_options.h"
3843b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn#include "pub_core_tooliface.h"
398bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn// XXX: this module should not depend on m_translate!
403cbfbc1be6a4334e57ec4213a8044c1180836b8dnjn#include "pub_core_translate.h"
418bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn#include "pub_core_transtab.h"
42de4a1d01951937632098a6cda45859afa587a06fsewardj
4318d7513cc08bf982711c8a22b70d56af6aa87b33sewardj/* #define DEBUG_TRANSTAB */
4418d7513cc08bf982711c8a22b70d56af6aa87b33sewardj
45de4a1d01951937632098a6cda45859afa587a06fsewardj
466c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*-------------------------------------------------------------*/
476c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*--- Management of the FIFO-based translation table+cache. ---*/
486c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*-------------------------------------------------------------*/
49de4a1d01951937632098a6cda45859afa587a06fsewardj
506c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ CONSTANTS ------------------*/
51de4a1d01951937632098a6cda45859afa587a06fsewardj
52fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of sectors the TC is divided into.  If you need a larger
53fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   overall translation cache, increase this value. */
54fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define N_SECTORS 8
55de4a1d01951937632098a6cda45859afa587a06fsewardj
56fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of TC entries in each sector.  This needs to be a prime
57fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   number to work properly, and it is strongly recommended not to
58fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   change this. */
59fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define N_TTES_PER_SECTOR /*30011*/ 40009
60de4a1d01951937632098a6cda45859afa587a06fsewardj
61fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Because each sector contains a hash table of TTEntries, we need to
62fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   specify the maximum allowable loading, after which the sector is
63fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   deemed full. */
64fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define SECTOR_TT_LIMIT_PERCENT 60
65de4a1d01951937632098a6cda45859afa587a06fsewardj
66fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The sector is deemed full when this many entries are in it. */
67fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define N_TTES_PER_SECTOR_USABLE \
68fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj           ((N_TTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
696c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
70de4a1d01951937632098a6cda45859afa587a06fsewardj
716c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ TYPES ------------------*/
72de4a1d01951937632098a6cda45859afa587a06fsewardj
73fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* A translation-cache entry is two parts:
74fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   - The guest address of the first (entry) bb in the translation,
75fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj     as a 64-bit word.
76fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   - One or more 64-bit words containing the code.
77fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   It is supposed to be 64-bit aligned.
78fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
79fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*
806c3769f487145a08c01b58d6e5db3ba274062ad4sewardjtypedef
81fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   struct {
82fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      Addr64 orig_addr;
83fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong  code[0];
846c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
856c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   TCEntry;
86fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
876c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
88fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* A translation-table entry.  This indicates precisely which areas of
89fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   guest code are included in the translation, and contains all other
90fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   auxiliary info too.  */
916c3769f487145a08c01b58d6e5db3ba274062ad4sewardjtypedef
926c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   struct {
93fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Profiling only: the count and weight (arbitrary meaning) for
94fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         this translation.  Weight is a property of the translation
95fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         itself and computed once when the translation is created.
96fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         Count is an entry count for the translation and is
97fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         incremented by 1 every time the translation is used, if we
98fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         are profiling. */
99fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      UInt     count;
100fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      UShort   weight;
101fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
102fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Status of the slot.  Note, we need to be able to do lazy
103fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         deletion, hence the Deleted state. */
104fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      enum { InUse, Deleted, Empty } status;
105fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
106fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Pointer to the corresponding TCEntry (must be in the same
107fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         sector!) */
108fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong* tce;
109fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
110fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This is the original guest address that purportedly is the
111fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         entry point of the translation.  You might think that .entry
112fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         should be the same as .vge->base[0], and most of the time it
113fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         is.  However, when doing redirections, that is not the case.
114fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         .vge must always correctly describe the guest code sections
115fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         from which this translation was made.  However, .entry may or
116fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         may not be a lie, depending on whether or not we're doing
117fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         redirection. */
118fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      Addr64 entry;
119fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
120fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This structure describes precisely what ranges of guest code
121fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         the translation covers, so we can decide whether or not to
122fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         delete it when translations of a given address range are
123fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         invalidated. */
124fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VexGuestExtents vge;
1256c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
1266c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   TTEntry;
1276c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
1284ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
129fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Finally, a sector itself.  Each sector contains an array of
130fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   TCEntries, which hold code, and an array of TTEntries, containing
131fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   all required administrative info.  Profiling is supported using the
132fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   TTEntry .count and .weight fields, if required.  Each sector is
133fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   independent in that no cross-sector references are allowed.
1344ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
135fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   If the sector is not in use, all three pointers are NULL and
136fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_n_inuse is zero.
137fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
138fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjtypedef
139fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   struct {
140fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The TCEntry area.  Size of this depends on the average
141fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         translation size.  We try and size it so it becomes full
142fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         precisely when this sector's translation table (tt) reaches
143fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         its load limit (SECTOR_TT_LIMIT_PERCENT). */
144fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong* tc;
1454ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
146fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The TTEntry array.  This is a fixed size, always containing
147fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         exactly N_TTES_PER_SECTOR entries. */
148fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      TTEntry* tt;
1496c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
150fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This points to the current allocation point in tc. */
151fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong* tc_next;
152de4a1d01951937632098a6cda45859afa587a06fsewardj
153fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The count of tt entries with state InUse. */
154fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      Int tt_n_inuse;
155fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
156fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Sector;
157de4a1d01951937632098a6cda45859afa587a06fsewardj
158de4a1d01951937632098a6cda45859afa587a06fsewardj
1596c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ DECLS ------------------*/
1606c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
161fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The root data structure is an array of sectors.  The index of the
162fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   youngest sector is recorded, and new translations are put into that
163fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sector.  When it fills up, we move along to the next sector and
164fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   start to fill that up, wrapping around at the end of the array.
165fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   That way, once all N_TC_SECTORS have been bought into use for the
166fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   first time, and are full, we then re-use the oldest sector,
167fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   endlessly.
168fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
169fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   When running, youngest sector should be between >= 0 and <
170fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   N_TC_SECTORS.  The initial -1 value indicates the TT/TC system is
171fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   not yet initialised.
172fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
173fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Sector sectors[N_SECTORS];
174fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Int    youngest_sector = -1;
1756c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
176fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The number of ULongs in each TCEntry area.  This is computed once
177fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   at startup and does not change. */
178fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Int    tc_sector_szQ;
1796c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
1806c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
181fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Fast helper for the TC.  A direct-mapped cache which holds a
182fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   pointer to a TC entry which may or may not be the correct one, but
183fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   which we hope usually is.  This array is referred to directly from
184fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   <arch>/dispatch.S.
1856c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
186fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Entries in tt_fast may point to any valid TC entry, regardless of
187fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   which sector it's in.  Consequently we must be very careful to
188fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidate this cache when TC entries are changed or disappear.
189c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
190fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   A special TCEntry -- bogus_tc_entry -- must be pointed at to cause
191fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   that cache entry to miss.  This relies on the assumption that no
192fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   guest code actually has an address of 0x1.
193fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
194fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*global*/ ULong* VG_(tt_fast)[VG_TT_FAST_SIZE];
19592e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
196fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic ULong bogus_tc_entry = (Addr64)1;
19792e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
19892e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
199fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* For profiling, we have a parallel array of pointers to .count
200fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   fields in TT entries.  Again, these pointers must be invalidated
201fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   when translations disappear.  A NULL pointer suffices to indicate
202fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   an unused slot.
2036c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
204fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_fast and tt_fastN change together: if tt_fast[i] points to
205fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   bogus_tc_entry then the corresponding tt_fastN[i] must be null.  If
206fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_fast[i] points to some TC entry somewhere, then tt_fastN[i]
207fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   *must* point to the .count field of the corresponding TT entry.
2086c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
209fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_fast and tt_fastN are referred to from assembly code
210fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   (dispatch.S).
211fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
212fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*global*/ UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
213de4a1d01951937632098a6cda45859afa587a06fsewardj
214de4a1d01951937632098a6cda45859afa587a06fsewardj
215663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj/* Make sure we're not used before initialisation. */
216663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardjstatic Bool init_done = False;
217663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
218663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
219fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------ STATS DECLS ------------------*/
220de4a1d01951937632098a6cda45859afa587a06fsewardj
221fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of fast-cache updates and flushes done. */
222fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_fast_flushes = 0;
223fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_fast_updates = 0;
22422854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
225fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of full lookups done. */
226fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_full_lookups = 0;
227fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_lookup_probes = 0;
22822854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
229fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number/osize/tsize of translations entered. */
230fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_in_count = 0;
231fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_in_osize = 0;
232fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_in_tsize = 0;
233de4a1d01951937632098a6cda45859afa587a06fsewardj
234fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number/osize of translations discarded due to lack of space. */
235fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_dump_count = 0;
236fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_dump_osize = 0;
237fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
238fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number/osize of translations discarded due to requests to do so. */
239fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_disc_count = 0;
240fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_disc_osize = 0;
241fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
242fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
243fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
244fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*-------------------------------------------------------------*/
245fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Add/delete/find translations                          ---*/
246fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*-------------------------------------------------------------*/
247fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
248fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic UInt vge_osize ( VexGuestExtents* vge )
249c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj{
250fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt i, n = 0;
251fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < vge->n_used; i++)
252fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n += (UInt)vge->len[i];
253fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return n;
254c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj}
255c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
256fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Bool isValidSector ( Int sector )
2576c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
258fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (sector < 0 || sector >= N_SECTORS)
259fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
260fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return True;
2616c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
262de4a1d01951937632098a6cda45859afa587a06fsewardj
263fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline UInt HASH_TT ( Addr64 key )
264de4a1d01951937632098a6cda45859afa587a06fsewardj{
265fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt kHi = (UInt)(key >> 32);
266fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt kLo = (UInt)key;
267fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return (kHi ^ kLo) % N_TTES_PER_SECTOR;
268de4a1d01951937632098a6cda45859afa587a06fsewardj}
269de4a1d01951937632098a6cda45859afa587a06fsewardj
270fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic void setFastCacheEntry ( Addr64 key, ULong* tce, UInt* count )
271de4a1d01951937632098a6cda45859afa587a06fsewardj{
272fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt cno = ((UInt)key) & VG_TT_FAST_MASK;
273fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(tt_fast)[cno]  = tce;
274fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(tt_fastN)[cno] = count;
275fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_fast_updates++;
2766c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
277de4a1d01951937632098a6cda45859afa587a06fsewardj
278fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic void invalidateFastCache ( void )
2796c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
280fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt j;
281fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (j = 0; j < VG_TT_FAST_SIZE; j++) {
282fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(tt_fast)[j]  = &bogus_tc_entry;
283fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(tt_fastN)[j] = NULL;
2846c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
285fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_fast_flushes++;
2866c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
287de4a1d01951937632098a6cda45859afa587a06fsewardj
288fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic void initialiseSector ( Int sno )
2896c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
290fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int i;
291fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(isValidSector(sno));
292fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
293fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (sectors[sno].tc == NULL) {
294fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Sector has never been used before.  Need to allocate tt and
295fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         tc. */
296fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      vg_assert(sectors[sno].tt == NULL);
297fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      vg_assert(sectors[sno].tc_next == NULL);
298fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      vg_assert(sectors[sno].tt_n_inuse == 0);
299fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[sno].tc
300fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         = VG_(get_memory_from_mmap)
301fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              ( 8 * tc_sector_szQ, "sectors[sno].tc" );
302fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[sno].tt
303fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         = VG_(get_memory_from_mmap)
304fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              ( N_TTES_PER_SECTOR * sizeof(TTEntry), "sectors[sno].tt" );
305fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (VG_(clo_verbosity) > 2)
306fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d", sno);
307fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   } else {
308fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Sector has been used before. */
309fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      vg_assert(sectors[sno].tt != NULL);
310fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      vg_assert(sectors[sno].tc_next != NULL);
311fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n_dump_count += sectors[sno].tt_n_inuse;
312fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
313fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[i].status == InUse) {
314fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            n_dump_osize += vge_osize(&sectors[sno].tt[i].vge);
315fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
316fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      }
317fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (VG_(clo_verbosity) > 2)
318fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d", sno);
3196c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
3204ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
321fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[sno].tc_next = sectors[sno].tc;
322fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[sno].tt_n_inuse = 0;
323fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_TTES_PER_SECTOR; i++)
324fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[sno].tt[i].status = Empty;
325fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
326fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidateFastCache();
3276c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
328de4a1d01951937632098a6cda45859afa587a06fsewardj
329de4a1d01951937632098a6cda45859afa587a06fsewardj
330fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Add a translation of vge to TT/TC.  The translation is temporarily
331fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   in code[0 .. code_len-1].
332de4a1d01951937632098a6cda45859afa587a06fsewardj
333fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   pre: youngest_sector points to a valid (although possibly full)
334fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sector.
335fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
3368bddf58af8cc7342d4bde6712c5a6a33bf2850d4njnvoid VG_(add_to_transtab)( VexGuestExtents* vge,
3378bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn                           Addr64           entry,
3388bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn                           AddrH            code,
3398bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn                           UInt             code_len )
34022854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj{
341fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int    tcAvailQ, reqdQ, y, i;
342fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   ULong  *tce, *tce2;
343fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UChar* srcP;
344fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UChar* dstP;
345fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
346663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
347fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
348fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(code_len > 0 && code_len < 20000);
349fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
350fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (0)
3518bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn      VG_(printf)("add_to_transtab(entry = 0x%llx, len = %d)\n",
352fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  entry, code_len);
353fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
354fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_count++;
355fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_tsize += code_len;
356fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_osize += vge_osize(vge);
357fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
358fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   y = youngest_sector;
359fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(isValidSector(y));
360fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
361fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (sectors[y].tc == NULL)
362fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      initialiseSector(y);
363fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
364fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Try putting the translation in this sector. */
365fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   reqdQ = 1 + ((code_len + 7) >> 3);
366fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
367fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Will it fit in tc? */
368fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
369fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              - ((ULong*)(sectors[y].tc_next));
370fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= 0);
371fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ <= tc_sector_szQ);
372fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
373fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (tcAvailQ < reqdQ
374fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj       || sectors[y].tt_n_inuse >= N_TTES_PER_SECTOR_USABLE) {
375fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* No.  So move on to the next sector.  Either it's never been
376fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         used before, in which case it will get its tt/tc allocated
377fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         now, or it has been used before, in which case it is set to be
378fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         empty, hence throwing out the oldest sector. */
379fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      youngest_sector++;
380fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (youngest_sector >= N_SECTORS)
381fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         youngest_sector = 0;
382fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      y = youngest_sector;
383fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      initialiseSector(y);
384fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
38522854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
386fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Be sure ... */
387fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
388fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              - ((ULong*)(sectors[y].tc_next));
389fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= 0);
390fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ <= tc_sector_szQ);
391fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= reqdQ);
392fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR_USABLE);
393fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sectors[y].tt_n_inuse >= 0);
394fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
395fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Copy into tc. */
396fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tce = sectors[y].tc_next;
397fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tce >= &sectors[y].tc[0]);
398fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tce <= &sectors[y].tc[tc_sector_szQ]);
399fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
400fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tce[0] = entry;
401fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   dstP = (UChar*)(&tce[1]);
402fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   srcP = (UChar*)code;
403fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < code_len; i++)
404fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      dstP[i] = srcP[i];
405fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tc_next += reqdQ;
406fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt_n_inuse++;
407fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
408fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* more paranoia */
409fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tce2 = sectors[y].tc_next;
410fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tce2 >= &sectors[y].tc[0]);
411fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tce2 <= &sectors[y].tc[tc_sector_szQ]);
412fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
413fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Find an empty tt slot, and use it.  There must be such a slot
414fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      since tt is never allowed to get completely full. */
415fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   i = HASH_TT(entry);
416fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(i >= 0 && i < N_TTES_PER_SECTOR);
41722854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj   while (True) {
418fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[y].tt[i].status == Empty
419fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          || sectors[y].tt[i].status == Deleted)
420fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         break;
421fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      i++;
422fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (i >= N_TTES_PER_SECTOR)
423fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         i = 0;
42422854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj   }
425fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
426fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].status = InUse;
427fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].tce    = tce;
428fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].count  = 0;
429fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].weight = 1;
430fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].vge    = *vge;
431fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].entry  = entry;
432fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
433fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   setFastCacheEntry( entry, tce, &sectors[y].tt[i].count );
43422854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj}
43522854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
436fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
437fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Search for the translation of the given guest address.  If
438fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   requested, a successful search can also cause the fast-caches to be
439fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   updated.
440fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
441fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjBool VG_(search_transtab) ( /*OUT*/AddrH* result,
442fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                            Addr64        guest_addr,
443fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                            Bool          upd_cache )
4446c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
445fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int i, j, k, kstart, sno;
446663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
447663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
448fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Find the initial probe point just once.  It will be the same in
449fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      all sectors and avoids multiple expensive % operations. */
450fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_full_lookups++;
451fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   k      = -1;
452fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   kstart = HASH_TT(guest_addr);
453fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(kstart >= 0 && kstart < N_TTES_PER_SECTOR);
454fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
455fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Search in all the sectors.  Although the order should not matter,
456fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      it might be most efficient to search in the order youngest to
457fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      oldest. */
458fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sno = youngest_sector;
459fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_SECTORS; i++) {
460fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
461fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[sno].tc == NULL)
462fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         goto notfound; /* sector not in use. */
463fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
464fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      k = kstart;
465fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (j = 0; j < N_TTES_PER_SECTOR; j++) {
466fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         n_lookup_probes++;
467fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[k].status == InUse
468fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             && sectors[sno].tt[k].entry == guest_addr) {
469fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            /* found it */
470fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (upd_cache)
471fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               setFastCacheEntry(
472fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  guest_addr, sectors[sno].tt[k].tce,
473fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                              &sectors[sno].tt[k].count );
474fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (result)
475fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               *result = sizeof(Addr64) + (AddrH)sectors[sno].tt[k].tce;
476fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            return True;
477fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
478fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[k].status == Empty)
479fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            break; /* not found in this sector */
480fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         k++;
481fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (k == N_TTES_PER_SECTOR)
482fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            k = 0;
4836c3769f487145a08c01b58d6e5db3ba274062ad4sewardj      }
484fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
485fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* If we fall off the end, all entries are InUse and not
486fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         matching, or Deleted.  In any case we did not find it in this
487fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         sector. */
488fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
489fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj     notfound:
490fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* move to the next oldest sector */
491fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sno = sno==0 ? (N_SECTORS-1) : (sno-1);
4926c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
493fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
494fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Not found in any sector. */
495fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return False;
4966c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
497de4a1d01951937632098a6cda45859afa587a06fsewardj
498de4a1d01951937632098a6cda45859afa587a06fsewardj
499fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Delete all translations which intersect with any part of the
500fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   specified guest address range.  Note, this is SLOW.
501fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
502fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
503fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline
504fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjBool overlap1 ( Addr64 s1, UInt r1, Addr64 s2, UInt r2 )
5056c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
506fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Addr64 e1 = s1 + (ULong)r1 - 1ULL;
507fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Addr64 e2 = s2 + (ULong)r1 - 1ULL;
508fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (e1 < s2 || e2 < s1)
509fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
510fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return True;
5116c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
512de4a1d01951937632098a6cda45859afa587a06fsewardj
513fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline
514fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjBool overlaps ( Addr64 start, UInt range, VexGuestExtents* vge )
5156c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
516fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[0], (UInt)vge->len[0]))
517fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
518fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (vge->n_used < 2)
519fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
520fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[1], (UInt)vge->len[1]))
521fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
522fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (vge->n_used < 3)
523fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
524fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[2], (UInt)vge->len[2]))
525fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
526fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return False;
5276c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
528de4a1d01951937632098a6cda45859afa587a06fsewardj
529de4a1d01951937632098a6cda45859afa587a06fsewardj
530fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(discard_translations) ( Addr64 guest_start, UInt range )
5316c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
532fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int sno, i;
533fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Bool anyDeleted = False;
5346c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
535663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
536663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
537fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (sno = 0; sno < N_SECTORS; sno++) {
538fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[sno].tc == NULL)
539fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         continue;
540fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
541fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[i].status == InUse
542fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             && overlaps( guest_start, range, &sectors[sno].tt[i].vge )) {
543fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            sectors[sno].tt[i].status = Deleted;
544fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            sectors[sno].tt_n_inuse--;
545fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              anyDeleted = True;
546fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            n_disc_count++;
547fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            n_disc_osize += vge_osize(&sectors[sno].tt[i].vge);
548fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
549fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      }
550de4a1d01951937632098a6cda45859afa587a06fsewardj   }
551de4a1d01951937632098a6cda45859afa587a06fsewardj
552fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (anyDeleted)
553fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      invalidateFastCache();
554fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj}
5556c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
5566c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
557fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
558fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Sanity checking                                      ---*/
559fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
560de4a1d01951937632098a6cda45859afa587a06fsewardj
561fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(sanity_check_tt_tc) ( Char* who )
562fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
5636c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
5646c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
5656c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
566fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
567fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Initialisation.                                      ---*/
568fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
569fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
570fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(init_tt_tc) ( void )
5716c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
572fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int i, avg_codeszQ;
573de4a1d01951937632098a6cda45859afa587a06fsewardj
574663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(!init_done);
575663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   init_done = True;
576663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
577fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Otherwise lots of things go wrong... */
578fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sizeof(ULong) == 8);
579fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sizeof(Addr64) == 8);
580de4a1d01951937632098a6cda45859afa587a06fsewardj
581fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (VG_(clo_verbosity) > 2)
582fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
583fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                   "TT/TC: VG_(init_tt_tc) "
584fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                   "(startup of code management)");
585fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
586fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Figure out how big each tc area should be.  */
58743b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn   avg_codeszQ   = (VG_(details).avg_translation_sizeB + 7) / 8;
58843b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn   tc_sector_szQ = N_TTES_PER_SECTOR_USABLE * (1 + avg_codeszQ);
589fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
590fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Ensure the calculated value is not way crazy. */
591fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tc_sector_szQ >= 2 * N_TTES_PER_SECTOR_USABLE);
592fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tc_sector_szQ <= 50 * N_TTES_PER_SECTOR_USABLE);
593fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
594fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Initialise the sectors */
595fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   youngest_sector = 0;
596fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_SECTORS; i++) {
597fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tc = NULL;
598fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tt = NULL;
599fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tc_next = NULL;
600fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tt_n_inuse = 0;
6016c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
6024ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
603fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* and the fast caches. */
604fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidateFastCache();
605fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
606fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (VG_(clo_verbosity) > 2) {
607fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
608fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         "TT/TC: cache: %d sectors of %d bytes each = %d total",
609fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          N_SECTORS, 8 * tc_sector_szQ,
610fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          N_SECTORS * 8 * tc_sector_szQ );
611fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
612fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         "TT/TC: table: %d total entries, max occupancy %d (%d%%)",
613fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         N_SECTORS * N_TTES_PER_SECTOR,
614fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         N_SECTORS * N_TTES_PER_SECTOR_USABLE,
615fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         SECTOR_TT_LIMIT_PERCENT );
616fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
617de4a1d01951937632098a6cda45859afa587a06fsewardj}
618de4a1d01951937632098a6cda45859afa587a06fsewardj
6194ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
620fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
621fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Printing out statistics.                             ---*/
622fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
623fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
624fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic ULong safe_idiv( ULong a, ULong b )
62592e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote{
62692e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   return (b == 0 ? 0 : a / b);
62792e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote}
62892e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
629fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjUInt VG_(get_bbs_translated) ( void )
630fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
631fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return n_in_count;
632fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj}
633fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
634fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(print_tt_tc_stats) ( void )
63592e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote{
63692e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
637fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      "    tt/tc: %llu tt lookups requiring %llu probes",
638fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n_full_lookups, n_lookup_probes );
63992e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
640fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      "    tt/tc: %llu fast-cache updates, %llu flushes",
641fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n_fast_updates, n_fast_flushes );
642fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
64392e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
644fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                "translate: new        %lld (%lld -> %lld; ratio %lld:10)",
645fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_in_count, n_in_osize, n_in_tsize,
646fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                safe_idiv(10*n_in_tsize, n_in_osize));
64792e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
648fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                "translate: dumped     %lld (%lld -> ?" "?)",
649fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_dump_count, n_dump_osize );
650fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(message)(Vg_DebugMsg,
651fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                "translate: discarded  %lld (%lld -> ?" "?)",
652fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_disc_count, n_disc_osize );
65392e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote}
654de4a1d01951937632098a6cda45859afa587a06fsewardj
655fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
656fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Printing out of profiling results.                   ---*/
657fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
6584ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
659fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Only the top N_MAX bbs will be displayed. */
660f9f1949469b24847644c3ae9d62773f97ae1b994sewardj#define N_MAX 200
661c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
662fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic TTEntry* tops[N_MAX];
663c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
664fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic ULong score ( TTEntry* tte )
665fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
666fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return ((ULong)tte->weight) * ((ULong)tte->count);
667de4a1d01951937632098a6cda45859afa587a06fsewardj}
668de4a1d01951937632098a6cda45859afa587a06fsewardj
669fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Bool heavier ( TTEntry* t1, TTEntry* t2 )
670fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
671fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return score(t1) > score(t2);
672fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj}
673de4a1d01951937632098a6cda45859afa587a06fsewardj
674fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Print n/m in form xx.yy% */
675fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic
676fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid percentify ( ULong n, ULong m, Int field_width, Char* buf)
677de4a1d01951937632098a6cda45859afa587a06fsewardj{
678fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int i, len, space;
679fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   ULong lo, hi;
680fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (m == 0) m = 1; /* stay sane */
681fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   hi = (n * 100) / m;
682fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   lo = (((n * 100) - hi * m) * 100) / m;
683fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(lo < 100);
684fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (lo < 10)
685fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(sprintf)(buf, "%lld.0%lld%%", hi, lo);
686fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   else
687fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(sprintf)(buf, "%lld.%lld%%", hi, lo);
688fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
689fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   len = VG_(strlen)(buf);
690fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   space = field_width - len;
691fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (space < 0) space = 0;     /* Allow for v. small field_width */
692fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   i = len;
693fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
694fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Right justify in field */
695fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (     ; i >= 0;    i--)  buf[i + space] = buf[i];
696fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < space; i++)  buf[i] = ' ';
697de4a1d01951937632098a6cda45859afa587a06fsewardj}
698de4a1d01951937632098a6cda45859afa587a06fsewardj
699de4a1d01951937632098a6cda45859afa587a06fsewardj
700fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(show_BB_profile) ( void )
701de4a1d01951937632098a6cda45859afa587a06fsewardj{
702fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Char  name[64];
703fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int   sno, i, r, s;
704fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   ULong score_total, score_cumul, score_here;
705fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Char  buf_cumul[10];
706fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Char  buf_here[10];
707fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
708fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* First, compute the total weighted count, and find the top N
709fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ttes.  tops contains pointers to the most-used N_MAX blocks, in
710fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      descending order (viz, tops[0] is the highest scorer). */
711fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_MAX; i++)
712fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      tops[i] = NULL;
713fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
714fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   score_total = 0;
715fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
716fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (sno = 0; sno < N_SECTORS; sno++) {
717fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[sno].tc == NULL)
71818d7513cc08bf982711c8a22b70d56af6aa87b33sewardj         continue;
719fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
720fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[i].status != InUse)
721fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            continue;
722fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         score_total += score(&sectors[sno].tt[i]);
723fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         /* Find the rank for sectors[sno].tt[i]. */
724fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         r = N_MAX-1;
725fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         while (True) {
726fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (r == -1)
727fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               break;
728fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             if (tops[r] == NULL) {
729fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               r--;
730fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               continue;
731fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             }
732fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             if (heavier(&sectors[sno].tt[i], tops[r])) {
733fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                r--;
734fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                continue;
735fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             }
736fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             break;
737fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
738fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         r++;
739fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         vg_assert(r >= 0 && r <= N_MAX);
740fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         /* This bb should be placed at r, and bbs above it shifted
741fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            upwards one slot. */
742fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (r < N_MAX) {
743fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            for (s = N_MAX-1; s > r; s--)
744fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               tops[s] = tops[s-1];
745fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            tops[r] = &sectors[sno].tt[i];
746fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
747de4a1d01951937632098a6cda45859afa587a06fsewardj      }
748de4a1d01951937632098a6cda45859afa587a06fsewardj   }
749de4a1d01951937632098a6cda45859afa587a06fsewardj
750fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
751fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
752fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("--- BEGIN BB Profile (summary of scores)                 ---\n");
753fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
754fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
755de4a1d01951937632098a6cda45859afa587a06fsewardj
756fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("Total score = %lld\n\n", score_total);
757de4a1d01951937632098a6cda45859afa587a06fsewardj
758fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   score_cumul = 0;
759fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (r = 0; r < N_MAX; r++) {
760fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (tops[r] == NULL)
761fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         continue;
762fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      name[0] = 0;
763fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(get_fnname_w_offset)(tops[r]->entry, name, 64);
764fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      name[63] = 0;
765fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      score_here = score(tops[r]);
766fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      score_cumul += score_here;
767fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      percentify(score_cumul, score_total, 6, buf_cumul);
768fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      percentify(score_here,  score_total, 6, buf_here);
769fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("%3d: (%9lld %s)   %9lld %s      0x%llx %s\n",
770fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  r,
771fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  score_cumul, buf_cumul,
772fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  score_here,  buf_here, tops[r]->entry, name );
773c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj   }
774c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
775fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
776fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
777fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("--- BB Profile (BB details)                              ---\n");
778fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
779fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
780c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
781fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   score_cumul = 0;
782fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (r = 0; r < N_MAX; r++) {
783fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (tops[r] == NULL)
784fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         continue;
785fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      name[0] = 0;
786fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(get_fnname_w_offset)(tops[r]->entry, name, 64);
787fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      name[63] = 0;
788fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      score_here = score(tops[r]);
789fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      score_cumul += score_here;
790fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      percentify(score_cumul, score_total, 6, buf_cumul);
791fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      percentify(score_here,  score_total, 6, buf_here);
792fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("\n");
793fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("=-=-=-=-=-=-=-=-=-=-=-=-=-= begin BB rank %d "
794fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  "=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n", r);
795fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("%3d: (%9lld %s)   %9lld %s      0x%llx %s\n",
796fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  r,
797fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  score_cumul, buf_cumul,
798fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  score_here,  buf_here, tops[r]->entry, name );
799fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("\n");
800fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(translate)(0, tops[r]->entry, True, VG_(clo_profile_flags));
801fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(printf)("=-=-=-=-=-=-=-=-=-=-=-=-=-=  end BB rank %d  "
802fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  "=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n", r);
803c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj   }
804c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
805fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
806fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
807fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("--- END BB Profile                                       ---\n");
808fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("------------------------------------------------------------\n");
809fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(printf)("\n");
810c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj}
811c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
812fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
813de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
8148bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn/*--- end                                                          ---*/
815de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
816