Second half of the LDT support.  It basically works now.

- New core uinstrs, GETSEG, PUTSEG (save and restore segment regs)

- New core uinstr USESEG, which takes a segment selector and a
  virtual address, and returns a linear address -- and also does
  a limit check.  This calls through to VG_(use_ldt) in vg_ldt.c.

- Insn parser (disAMode) made aware of segment override prefixes

- Obvious fixes to insn emitter and translators

None of the skins understand these new uinstrs, so only --skin=none
works with them at the mo.  This and some other rough edges still
need to be fixed.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1139 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_ldt.c b/coregrind/vg_ldt.c
index 02806af..0d70435 100644
--- a/coregrind/vg_ldt.c
+++ b/coregrind/vg_ldt.c
@@ -77,16 +77,66 @@
                     ((unsigned long)ent->LdtEnt.Bits.BaseHi) << 24);
 }
 
-#if 0
-inline static unsigned int wine_ldt_get_limit( const VgLdtEntry *ent )
+static 
+unsigned int wine_ldt_get_limit( const VgLdtEntry *ent )
 {
-    unsigned int limit = ent->LimitLow | (ent->HighWord.Bits.LimitHi << 16);
-    if (ent->HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff;
+    unsigned int limit = ent->LdtEnt.Bits.LimitLow 
+                         | (ent->LdtEnt.Bits.LimitHi << 16);
+    if (ent->LdtEnt.Bits.Granularity) limit = (limit << 12) | 0xfff;
     return limit;
 }
-#endif
 
 
+/* Actually _DO_ the segment translation.  This is the whole entire
+   point of this accursed, overcomplicated, baroque, pointless
+   segment-override-and-LDT/GDT garbage foisted upon us all by Intel,
+   in its infinite wisdom. 
+
+   THIS IS CALLED FROM GENERATED CODE (AND SO RUNS ON REAL CPU). 
+*/
+Addr VG_(do_useseg) ( UInt seg_selector, Addr virtual_addr )
+{
+   Addr        base;
+   UInt        limit;
+   VgLdtEntry* the_ldt;
+
+   VG_(printf)("do_useseg: seg_selector = %p, vaddr = %p\n", 
+               seg_selector, virtual_addr);
+
+   seg_selector &= 0x0000FFFF;
+  
+   /* Sanity check the segment selector.  Ensure that TI=1 (LDT) and
+      that RPL=11b (least priviledge).  These form the bottom 3 bits
+      of the selector. */
+   vg_assert((seg_selector & 7) == 7);
+
+   /* convert it onto a table index */
+   seg_selector >>= 3;
+   vg_assert(seg_selector >= 0 && seg_selector < 8192);
+
+   /* Come up with a suitable LDT entry.  We look at the thread's LDT,
+      which is pointed to by a VG_(baseBlock) entry.  If null, we will
+      use an implied zero-entry -- although this usually implies the
+      program is in deep trouble, since it is using LDT entries which
+      it probably hasn't set up. */
+   the_ldt = (VgLdtEntry*)VG_(baseBlock)[VGOFF_(ldt)];
+   if (the_ldt == NULL) {
+      base = 0;
+      limit = 0;
+      VG_(printf)("warning! thread has no LDT!  this is really bad.\n");
+   } else {
+      base = (Addr)wine_ldt_get_base ( &the_ldt[seg_selector] );
+      limit = (UInt)wine_ldt_get_limit ( &the_ldt[seg_selector] );
+   }
+
+   if (virtual_addr >= limit) {
+      VG_(printf)("FATAL: do_useseg: vaddr %d exceeds segment limit %d\n", 
+                  virtual_addr, limit );
+   }
+
+   return base + virtual_addr;
+}
+
 
 /* Translate a struct modify_ldt_ldt_s to an VgLdtEntry, using the
    Linux kernel's logic (cut-n-paste of code in linux/kernel/ldt.c).  */