The GNU General Public License is contained in the file COPYING.
*/
+/* Details of the LDT simulation
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ When a program runs natively, the linux kernel allows each *thread*
+ in it to have its own LDT. Almost all programs never do this --
+ it's wildly unportable, after all -- and so the kernel never
+ allocates the structure, which is just as well as an LDT occupies
+ 64k of memory (8192 entries of size 8 bytes).
+
+ A thread may choose to modify its LDT entries, by doing the
+ __NR_modify_ldt syscall. In such a situation the kernel will then
+ allocate an LDT structure for it. Each LDT entry is basically a
+ (base, limit) pair. A virtual address in a specific segment is
+ translated to a linear address by adding the segment's base value.
+ In addition, the virtual address must not exceed the limit value.
+
+ To use an LDT entry, a thread loads one of the segment registers
+ (%cs, %ss, %ds, %es, %fs, %gs) with the index of the LDT entry (0
+ .. 8191) it wants to use. In fact, the required value is (index <<
+ 3) + 7, but that's not important right now. Any normal instruction
+ which includes an addressing mode can then be made relative to that
+ LDT entry by prefixing the insn with a so-called segment-override
+ prefix, a byte which indicates which of the 6 segment registers
+ holds the LDT index.
+
+ Now, a key constraint is that valgrind's address checks operate in
+ terms of linear addresses. So we have to explicitly translate
+ virtual addrs into linear addrs, and that means doing a complete
+ LDT simulation.
+
+ Calls to modify_ldt are intercepted. For each thread, we maintain
+ an LDT (with the same normally-never-allocated optimisation that
+ the kernel does). This is updated as expected via calls to
+ modify_ldt.
+
+ When a thread does an amode calculation involving a segment
+ override prefix, the relevant LDT entry for the thread is
+ consulted. It all works.
+
+ There is a conceptual problem, which appears when switching back to
+ native execution, either temporarily to pass syscalls to the
+ kernel, or permanently, when debugging V. Problem at such points
+ is that it's pretty pointless to copy the simulated machine's
+ segment registers to the real machine, because we'd also need to
+ copy the simulated LDT into the real one, and that's prohibitively
+ expensive.
+
+ Fortunately it looks like no syscalls rely on the segment regs or
+ LDT being correct, so we can get away with it. Apart from that the
+ simulation is pretty straightforward. All 6 segment registers are
+ tracked, although only %ds, %es, %fs and %gs are allowed as
+ prefixes. Perhaps it could be restricted even more than that -- I
+ am not sure what is and isn't allowed in user-mode.
+*/
+
#include "vg_include.h"
/* Allocate and deallocate LDTs for threads. */
limit = (UInt)wine_ldt_get_limit ( &the_ldt[seg_selector] );
}
+ /* Note, this check is just slightly too slack. Really it should
+ be "if (virtual_addr + size - 1 >= limit)," but we don't have the
+ size info to hand. Getting it could be significantly complex. */
if (virtual_addr >= limit) {
VG_(message)(
Vg_UserMsg,