~ubuntu-branches/ubuntu/karmic/valgrind/karmic

« back to all changes in this revision

Viewing changes to coregrind/m_transtab.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2008-01-06 11:28:10 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080106112810-segj25s87z9zd7i5
Tags: 1:3.3.0-1ubuntu1
* Merge with Debian, remaining changes:
 - Add 91_build_with_fno_stack_protector.dpatch
 - Add lpia to Architecture

Show diffs side-by-side

added added

removed removed

Lines of Context:
84
84
 
85
85
/*------------------ TYPES ------------------*/
86
86
 
87
 
/* A translation-cache entry is two parts:
88
 
   - The guest address of the first (entry) bb in the translation,
89
 
     as a 64-bit word.
90
 
   - One or more 64-bit words containing the code.
91
 
   It is supposed to be 64-bit aligned.
92
 
*/
93
 
/*
94
 
typedef
95
 
   struct {
96
 
      Addr64 orig_addr;
97
 
      ULong  code[0];
98
 
   }
99
 
   TCEntry;
100
 
*/
101
 
 
102
87
/* A translation-table entry.  This indicates precisely which areas of
103
88
   guest code are included in the translation, and contains all other
104
89
   auxiliary info too.  */
117
102
         deletion, hence the Deleted state. */
118
103
      enum { InUse, Deleted, Empty } status;
119
104
 
120
 
      /* Pointer to the corresponding TCEntry (must be in the same
121
 
         sector!) */
122
 
      ULong* tce;
 
105
      /* 64-bit aligned pointer to one or more 64-bit words containing
 
106
         the corresponding host code (must be in the same sector!)
 
107
         This is a pointer into the sector's tc (code) area. */
 
108
      ULong* tcptr;
123
109
 
124
110
      /* This is the original guest address that purportedly is the
125
111
         entry point of the translation.  You might think that .entry
214
200
static Int    tc_sector_szQ;
215
201
 
216
202
 
217
 
/* Fast helper for the TC.  A direct-mapped cache which holds a
218
 
   pointer to a TC entry which may or may not be the correct one, but
219
 
   which we hope usually is.  This array is referred to directly from
220
 
   <arch>/dispatch.S.
 
203
/* Fast helper for the TC.  A direct-mapped cache which holds a set of
 
204
   recently used (guest address, host address) pairs.  This array is
 
205
   referred to directly from m_dispatch/dispatch-<platform>.S.
221
206
 
222
 
   Entries in tt_fast may point to any valid TC entry, regardless of
 
207
   Entries in tt_fast may refer to any valid TC entry, regardless of
223
208
   which sector it's in.  Consequently we must be very careful to
224
209
   invalidate this cache when TC entries are changed or disappear.
225
210
 
226
 
   A special TCEntry -- bogus_tc_entry -- must be pointed at to cause
227
 
   that cache entry to miss.  This relies on the assumption that no
228
 
   guest code actually has an address of 0x1.
229
 
*/
230
 
/*global*/ ULong* VG_(tt_fast)[VG_TT_FAST_SIZE];
231
 
 
232
 
static ULong bogus_tc_entry = (Addr64)1;
233
 
 
 
211
   A special .guest address - TRANSTAB_BOGUS_GUEST_ADDR -- must be
 
212
   pointed at to cause that cache entry to miss.  This relies on the
 
213
   assumption that no guest code actually has that address, hence a
 
214
   value 0x1 seems good.  m_translate gives the client a synthetic
 
215
   segfault if it tries to execute at this address.
 
216
*/
 
217
/*
 
218
typedef
 
219
   struct { 
 
220
      Addr guest;
 
221
      Addr host;
 
222
   }
 
223
   FastCacheEntry;
 
224
*/
 
225
/*global*/ __attribute__((aligned(16)))
 
226
           FastCacheEntry VG_(tt_fast)[VG_TT_FAST_SIZE];
 
227
/*
 
228
#define TRANSTAB_BOGUS_GUEST_ADDR ((Addr)1)
 
229
*/
234
230
 
235
231
/* For profiling, we have a parallel array of pointers to .count
236
232
   fields in TT entries.  Again, these pointers must be invalidated
237
233
   when translations disappear.  A NULL pointer suffices to indicate
238
234
   an unused slot.
239
235
 
240
 
   tt_fast and tt_fastN change together: if tt_fast[i] points to
241
 
   bogus_tc_entry then the corresponding tt_fastN[i] must be null.  If
242
 
   tt_fast[i] points to some TC entry somewhere, then tt_fastN[i]
243
 
   *must* point to the .count field of the corresponding TT entry.
 
236
   When not profiling (the normal case, VG_(clo_profile_flags) == 0),
 
237
   all tt_fastN entries are set to NULL at startup and never read nor
 
238
   written after that.
 
239
 
 
240
   When profiling (VG_(clo_profile_flags) > 0), tt_fast and tt_fastN
 
241
   change together: if tt_fast[i].guest is TRANSTAB_BOGUS_GUEST_ADDR
 
242
   then the corresponding tt_fastN[i] must be null.  If
 
243
   tt_fast[i].guest is any other value, then tt_fastN[i] *must* point
 
244
   to the .count field of the corresponding TT entry.
244
245
 
245
246
   tt_fast and tt_fastN are referred to from assembly code
246
247
   (dispatch.S).
557
558
 
558
559
/* Sanity check absolutely everything.  True == check passed. */
559
560
 
560
 
/* forward */
 
561
/* forwards */
561
562
static Bool sanity_check_redir_tt_tc ( void );
 
563
static Bool sanity_check_fastcache ( void );
562
564
 
563
565
static Bool sanity_check_all_sectors ( void )
564
566
{
573
575
      if (!sane)
574
576
         return False;
575
577
   }
576
 
   if (!sanity_check_redir_tt_tc() )
 
578
   if ( !sanity_check_redir_tt_tc() )
 
579
      return False;
 
580
   if ( !sanity_check_fastcache() )
577
581
      return False;
578
582
   return True;
579
583
}
609
613
   return k32 % N_TTES_PER_SECTOR;
610
614
}
611
615
 
612
 
static void setFastCacheEntry ( Addr64 key, ULong* tce, UInt* count )
 
616
static void setFastCacheEntry ( Addr64 key, ULong* tcptr, UInt* count )
613
617
{
614
618
   UInt cno = (UInt)VG_TT_FAST_HASH(key);
615
 
   VG_(tt_fast)[cno]  = tce;
616
 
   VG_(tt_fastN)[cno] = count;
 
619
   VG_(tt_fast)[cno].guest = (Addr)key;
 
620
   VG_(tt_fast)[cno].host  = (Addr)tcptr;
 
621
   if (VG_(clo_profile_flags) > 0)
 
622
      VG_(tt_fastN)[cno] = count;
617
623
   n_fast_updates++;
 
624
   /* This shouldn't fail.  It should be assured by m_translate
 
625
      which should reject any attempt to make translation of code
 
626
      starting at TRANSTAB_BOGUS_GUEST_ADDR. */
 
627
   vg_assert(VG_(tt_fast)[cno].guest != TRANSTAB_BOGUS_GUEST_ADDR);
618
628
}
619
629
 
620
 
static void invalidateFastCache ( void )
 
630
/* Invalidate the fast cache's counter array, VG_(tt_fastN). */
 
631
static void invalidateFastNCache ( void )
621
632
{
622
633
   UInt j;
623
 
   /* This loop is popular enough to make it worth unrolling a
624
 
      bit, at least on ppc32. */
625
634
   vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
626
635
   for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
627
 
      VG_(tt_fast)[j+0]  = &bogus_tc_entry;
628
 
      VG_(tt_fast)[j+1]  = &bogus_tc_entry;
629
 
      VG_(tt_fast)[j+2]  = &bogus_tc_entry;
630
 
      VG_(tt_fast)[j+3]  = &bogus_tc_entry;
631
636
      VG_(tt_fastN)[j+0] = NULL;
632
637
      VG_(tt_fastN)[j+1] = NULL;
633
638
      VG_(tt_fastN)[j+2] = NULL;
634
639
      VG_(tt_fastN)[j+3] = NULL;
635
640
   }
636
641
   vg_assert(j == VG_TT_FAST_SIZE);
 
642
}
 
643
 
 
644
/* Invalidate the fast cache VG_(tt_fast).  If profiling, also
 
645
   invalidate the fast cache's counter array VG_(tt_fastN), otherwise
 
646
   don't touch it. */
 
647
static void invalidateFastCache ( void )
 
648
{
 
649
   UInt j;
 
650
   /* This loop is popular enough to make it worth unrolling a
 
651
      bit, at least on ppc32. */
 
652
   vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
 
653
   for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
 
654
      VG_(tt_fast)[j+0].guest = TRANSTAB_BOGUS_GUEST_ADDR;
 
655
      VG_(tt_fast)[j+1].guest = TRANSTAB_BOGUS_GUEST_ADDR;
 
656
      VG_(tt_fast)[j+2].guest = TRANSTAB_BOGUS_GUEST_ADDR;
 
657
      VG_(tt_fast)[j+3].guest = TRANSTAB_BOGUS_GUEST_ADDR;
 
658
   }
 
659
 
 
660
   if (VG_(clo_profile_flags) > 0)
 
661
      invalidateFastNCache();
 
662
 
 
663
   vg_assert(j == VG_TT_FAST_SIZE);
637
664
   n_fast_flushes++;
638
665
}
639
666
 
 
667
static Bool sanity_check_fastcache ( void )
 
668
{
 
669
   UInt j;
 
670
   if (0) VG_(printf)("sanity check fastcache\n");
 
671
   if (VG_(clo_profile_flags) > 0) {
 
672
      /* profiling */
 
673
      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
 
674
         if (VG_(tt_fastN)[j] == NULL 
 
675
             && VG_(tt_fast)[j].guest != TRANSTAB_BOGUS_GUEST_ADDR)
 
676
            return False;
 
677
         if (VG_(tt_fastN)[j] != NULL 
 
678
             && VG_(tt_fast)[j].guest == TRANSTAB_BOGUS_GUEST_ADDR)
 
679
            return False;
 
680
      }
 
681
   } else {
 
682
      /* not profiling */
 
683
      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
 
684
         if (VG_(tt_fastN)[j] != NULL)
 
685
            return False;
 
686
      }
 
687
   }
 
688
   return True;
 
689
}
 
690
 
640
691
static void initialiseSector ( Int sno )
641
692
{
642
693
   Int    i;
667
718
                                     8 * tc_sector_szQ );
668
719
         /*NOTREACHED*/
669
720
      }
670
 
      sec->tc = (ULong*)sres.val;
 
721
      sec->tc = (ULong*)sres.res;
671
722
 
672
723
      sres = VG_(am_mmap_anon_float_valgrind)
673
724
                ( N_TTES_PER_SECTOR * sizeof(TTEntry) );
676
727
                                     N_TTES_PER_SECTOR * sizeof(TTEntry) );
677
728
         /*NOTREACHED*/
678
729
      }
679
 
      sec->tt = (TTEntry*)sres.val;
 
730
      sec->tt = (TTEntry*)sres.res;
680
731
 
681
732
      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
682
733
         sec->tt[i].status   = Empty;
701
752
            vg_assert(sec->tt[i].n_tte2ec <= 3);
702
753
            n_dump_osize += vge_osize(&sec->tt[i].vge);
703
754
            /* Tell the tool too. */
704
 
            if (VG_(needs).basic_block_discards) {
705
 
               VG_TDICT_CALL( tool_discard_basic_block_info,
 
755
            if (VG_(needs).superblock_discards) {
 
756
               VG_TDICT_CALL( tool_discard_superblock_info,
706
757
                              sec->tt[i].entry,
707
758
                              sec->tt[i].vge );
708
759
            }
746
797
   Addr addr;
747
798
   VexArchInfo vai;
748
799
 
 
800
   if (nbytes == 0) return;
 
801
   vg_assert(nbytes > 0);
 
802
 
749
803
   VG_(machine_get_VexArchInfo)( NULL, &vai );
750
804
   cls = vai.ppc_cache_line_szB;
751
805
 
785
839
                           Bool             is_self_checking )
786
840
{
787
841
   Int    tcAvailQ, reqdQ, y, i;
788
 
   ULong  *tce, *tce2;
 
842
   ULong  *tcptr, *tcptr2;
789
843
   UChar* srcP;
790
844
   UChar* dstP;
791
845
 
792
846
   vg_assert(init_done);
793
847
   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
794
 
   vg_assert(code_len > 0 && code_len < 20000);
 
848
 
 
849
   /* 60000: should agree with N_TMPBUF in m_translate.c. */
 
850
   vg_assert(code_len > 0 && code_len < 60000);
795
851
 
796
852
   if (0)
797
853
      VG_(printf)("add_to_transtab(entry = 0x%llx, len = %d)\n",
810
866
      initialiseSector(y);
811
867
 
812
868
   /* Try putting the translation in this sector. */
813
 
   reqdQ = 1 + ((code_len + 7) >> 3);
 
869
   reqdQ = (code_len + 7) >> 3;
814
870
 
815
871
   /* Will it fit in tc? */
816
872
   tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
850
906
   vg_assert(sectors[y].tt_n_inuse >= 0);
851
907
 
852
908
   /* Copy into tc. */
853
 
   tce = sectors[y].tc_next;
854
 
   vg_assert(tce >= &sectors[y].tc[0]);
855
 
   vg_assert(tce <= &sectors[y].tc[tc_sector_szQ]);
 
909
   tcptr = sectors[y].tc_next;
 
910
   vg_assert(tcptr >= &sectors[y].tc[0]);
 
911
   vg_assert(tcptr <= &sectors[y].tc[tc_sector_szQ]);
856
912
 
857
 
   tce[0] = entry;
858
 
   dstP = (UChar*)(&tce[1]);
 
913
   dstP = (UChar*)tcptr;
859
914
   srcP = (UChar*)code;
860
915
   for (i = 0; i < code_len; i++)
861
916
      dstP[i] = srcP[i];
865
920
   invalidate_icache( dstP, code_len );
866
921
 
867
922
   /* more paranoia */
868
 
   tce2 = sectors[y].tc_next;
869
 
   vg_assert(tce2 >= &sectors[y].tc[0]);
870
 
   vg_assert(tce2 <= &sectors[y].tc[tc_sector_szQ]);
 
923
   tcptr2 = sectors[y].tc_next;
 
924
   vg_assert(tcptr2 >= &sectors[y].tc[0]);
 
925
   vg_assert(tcptr2 <= &sectors[y].tc[tc_sector_szQ]);
871
926
 
872
927
   /* Find an empty tt slot, and use it.  There must be such a slot
873
928
      since tt is never allowed to get completely full. */
883
938
   }
884
939
 
885
940
   sectors[y].tt[i].status = InUse;
886
 
   sectors[y].tt[i].tce    = tce;
 
941
   sectors[y].tt[i].tcptr  = tcptr;
887
942
   sectors[y].tt[i].count  = 0;
888
943
   sectors[y].tt[i].weight = 1;
889
944
   sectors[y].tt[i].vge    = *vge;
890
945
   sectors[y].tt[i].entry  = entry;
891
946
 
892
947
   /* Update the fast-cache. */
893
 
   setFastCacheEntry( entry, tce, &sectors[y].tt[i].count );
 
948
   setFastCacheEntry( entry, tcptr, &sectors[y].tt[i].count );
894
949
 
895
950
   /* Note the eclass numbers for this translation. */
896
951
   upd_eclasses_after_add( &sectors[y], i );
932
987
            /* found it */
933
988
            if (upd_cache)
934
989
               setFastCacheEntry( 
935
 
                  guest_addr, sectors[sno].tt[k].tce, 
 
990
                  guest_addr, sectors[sno].tt[k].tcptr, 
936
991
                              &sectors[sno].tt[k].count );
937
992
            if (result)
938
 
               *result = sizeof(Addr64) + (AddrH)sectors[sno].tt[k].tce;
 
993
               *result = (AddrH)sectors[sno].tt[k].tcptr;
939
994
            return True;
940
995
         }
941
996
         if (sectors[sno].tt[k].status == Empty)
1032
1087
   n_disc_osize += vge_osize(&tte->vge);
1033
1088
 
1034
1089
   /* Tell the tool too. */
1035
 
   if (VG_(needs).basic_block_discards) {
1036
 
      VG_TDICT_CALL( tool_discard_basic_block_info,
 
1090
   if (VG_(needs).superblock_discards) {
 
1091
      VG_TDICT_CALL( tool_discard_superblock_info,
1037
1092
                     tte->entry,
1038
1093
                     tte->vge );
1039
1094
   }
1262
1317
         VG_(out_of_memory_NORETURN)("init_unredir_tt_tc", N_UNREDIR_TT * UNREDIR_SZB);
1263
1318
         /*NOTREACHED*/
1264
1319
      }
1265
 
      unredir_tc = (ULong *)sres.val;
 
1320
      unredir_tc = (ULong *)sres.res;
1266
1321
   }
1267
1322
   unredir_tc_used = 0;
1268
1323
   for (i = 0; i < N_UNREDIR_TT; i++)
1390
1445
   /* Otherwise lots of things go wrong... */
1391
1446
   vg_assert(sizeof(ULong) == 8);
1392
1447
   vg_assert(sizeof(Addr64) == 8);
 
1448
   /* check fast cache entries really are 2 words long */
 
1449
   vg_assert(sizeof(Addr) == sizeof(void*));
 
1450
   vg_assert(sizeof(FastCacheEntry) == 2 * sizeof(Addr));
 
1451
   /* check fast cache entries are packed back-to-back with no spaces */
 
1452
   vg_assert(sizeof( VG_(tt_fast) ) == VG_TT_FAST_SIZE * sizeof(FastCacheEntry));
 
1453
   /* check fast cache is aligned as we requested.  Not fatal if it
 
1454
      isn't, but we might as well make sure. */
 
1455
   vg_assert(VG_IS_16_ALIGNED( ((Addr) & VG_(tt_fast)[0]) ));
1393
1456
 
1394
1457
   if (VG_(clo_verbosity) > 2)
1395
1458
      VG_(message)(Vg_DebugMsg, 
1402
1465
 
1403
1466
   /* Ensure the calculated value is not way crazy. */
1404
1467
   vg_assert(tc_sector_szQ >= 2 * N_TTES_PER_SECTOR_USABLE);
1405
 
   vg_assert(tc_sector_szQ <= 50 * N_TTES_PER_SECTOR_USABLE);
 
1468
   vg_assert(tc_sector_szQ <= 80 * N_TTES_PER_SECTOR_USABLE);
1406
1469
 
1407
1470
   /* Initialise the sectors */
1408
1471
   youngest_sector = 0;
1418
1481
      }
1419
1482
   }
1420
1483
 
1421
 
   /* and the fast caches. */
 
1484
   /* Initialise the fast caches.  If not profiling (the usual case),
 
1485
      we have to explicitly invalidate the fastN cache as
 
1486
      invalidateFastCache() won't do that for us. */
1422
1487
   invalidateFastCache();
 
1488
   if (VG_(clo_profile_flags) == 0)
 
1489
      invalidateFastNCache();
1423
1490
 
1424
1491
   /* and the unredir tt/tc */
1425
1492
   init_unredir_tt_tc();