blob: 3f3b760965306db9d3faf786cfd34e0b91349d92 [file] [log] [blame]
sewardj92a59562002-09-30 00:53:10 +00001
2/*--------------------------------------------------------------------*/
3/*--- Simulation of Local Descriptor Tables vg_ldt.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2000-2002 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
sewardj874f3882002-09-30 22:56:26 +000031/* Details of the LDT simulation
32 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33
34 When a program runs natively, the linux kernel allows each *thread*
35 in it to have its own LDT. Almost all programs never do this --
36 it's wildly unportable, after all -- and so the kernel never
37 allocates the structure, which is just as well as an LDT occupies
38 64k of memory (8192 entries of size 8 bytes).
39
40 A thread may choose to modify its LDT entries, by doing the
41 __NR_modify_ldt syscall. In such a situation the kernel will then
42 allocate an LDT structure for it. Each LDT entry is basically a
43 (base, limit) pair. A virtual address in a specific segment is
44 translated to a linear address by adding the segment's base value.
45 In addition, the virtual address must not exceed the limit value.
46
47 To use an LDT entry, a thread loads one of the segment registers
48 (%cs, %ss, %ds, %es, %fs, %gs) with the index of the LDT entry (0
49 .. 8191) it wants to use. In fact, the required value is (index <<
50 3) + 7, but that's not important right now. Any normal instruction
51 which includes an addressing mode can then be made relative to that
52 LDT entry by prefixing the insn with a so-called segment-override
53 prefix, a byte which indicates which of the 6 segment registers
54 holds the LDT index.
55
56 Now, a key constraint is that valgrind's address checks operate in
57 terms of linear addresses. So we have to explicitly translate
58 virtual addrs into linear addrs, and that means doing a complete
59 LDT simulation.
60
61 Calls to modify_ldt are intercepted. For each thread, we maintain
62 an LDT (with the same normally-never-allocated optimisation that
63 the kernel does). This is updated as expected via calls to
64 modify_ldt.
65
66 When a thread does an amode calculation involving a segment
67 override prefix, the relevant LDT entry for the thread is
68 consulted. It all works.
69
70 There is a conceptual problem, which appears when switching back to
71 native execution, either temporarily to pass syscalls to the
72 kernel, or permanently, when debugging V. Problem at such points
73 is that it's pretty pointless to copy the simulated machine's
74 segment registers to the real machine, because we'd also need to
75 copy the simulated LDT into the real one, and that's prohibitively
76 expensive.
77
78 Fortunately it looks like no syscalls rely on the segment regs or
79 LDT being correct, so we can get away with it. Apart from that the
80 simulation is pretty straightforward. All 6 segment registers are
81 tracked, although only %ds, %es, %fs and %gs are allowed as
82 prefixes. Perhaps it could be restricted even more than that -- I
83 am not sure what is and isn't allowed in user-mode.
84*/
85
sewardj92a59562002-09-30 00:53:10 +000086#include "vg_include.h"
87/* Allocate and deallocate LDTs for threads. */
88
89/* Create an LDT. If the parent_ldt is NULL, zero out the
90 new one. If non-NULL, copy the parent. */
91VgLdtEntry* VG_(allocate_LDT_for_thread) ( VgLdtEntry* parent_ldt )
92{
93 UInt nbytes, i;
94 VgLdtEntry* ldt;
95
sewardjc4a71322002-09-30 22:06:28 +000096 if (0)
njn854e7152002-09-30 10:47:35 +000097 VG_(printf)("allocate_LDT_for_thread: parent = %p\n", parent_ldt );
sewardj92a59562002-09-30 00:53:10 +000098 vg_assert(VG_LDT_ENTRY_SIZE == sizeof(VgLdtEntry));
99 nbytes = VG_M_LDT_ENTRIES * VG_LDT_ENTRY_SIZE;
100
101 if (parent_ldt == NULL) {
102 /* Allocate a new zeroed-out one. */
103 ldt = (VgLdtEntry*)VG_(arena_calloc)(VG_AR_CORE, nbytes, 1);
104 } else {
105 ldt = (VgLdtEntry*)VG_(arena_malloc)(VG_AR_CORE, nbytes);
106 for (i = 0; i < VG_M_LDT_ENTRIES; i++)
107 ldt[i] = parent_ldt[i];
108 }
109
110 return ldt;
111}
112
113/* Free an LDT created by the above function. */
114void VG_(deallocate_LDT_for_thread) ( VgLdtEntry* ldt )
115{
sewardjc4a71322002-09-30 22:06:28 +0000116 if (0)
njn854e7152002-09-30 10:47:35 +0000117 VG_(printf)("deallocate_LDT_for_thread: ldt = %p\n", ldt );
sewardj92a59562002-09-30 00:53:10 +0000118 if (ldt != NULL)
119 VG_(arena_free)(VG_AR_CORE, ldt);
120}
121
122
123
124/* Fish the base field out of an VgLdtEntry. This is the only part we
125 are particularly interested in. */
126
127static
128void *wine_ldt_get_base( const VgLdtEntry *ent )
129{
130 return (void *)(ent->LdtEnt.Bits.BaseLow |
131 ((unsigned long)ent->LdtEnt.Bits.BaseMid) << 16 |
132 ((unsigned long)ent->LdtEnt.Bits.BaseHi) << 24);
133}
134
sewardje1042472002-09-30 12:33:11 +0000135static
136unsigned int wine_ldt_get_limit( const VgLdtEntry *ent )
sewardj92a59562002-09-30 00:53:10 +0000137{
sewardje1042472002-09-30 12:33:11 +0000138 unsigned int limit = ent->LdtEnt.Bits.LimitLow
139 | (ent->LdtEnt.Bits.LimitHi << 16);
140 if (ent->LdtEnt.Bits.Granularity) limit = (limit << 12) | 0xfff;
sewardj92a59562002-09-30 00:53:10 +0000141 return limit;
142}
sewardj92a59562002-09-30 00:53:10 +0000143
144
sewardje1042472002-09-30 12:33:11 +0000145/* Actually _DO_ the segment translation. This is the whole entire
146 point of this accursed, overcomplicated, baroque, pointless
147 segment-override-and-LDT/GDT garbage foisted upon us all by Intel,
148 in its infinite wisdom.
149
150 THIS IS CALLED FROM GENERATED CODE (AND SO RUNS ON REAL CPU).
151*/
152Addr VG_(do_useseg) ( UInt seg_selector, Addr virtual_addr )
153{
154 Addr base;
155 UInt limit;
156 VgLdtEntry* the_ldt;
157
sewardjc4a71322002-09-30 22:06:28 +0000158 if (0)
159 VG_(printf)("do_useseg: seg_selector = %p, vaddr = %p\n",
160 seg_selector, virtual_addr);
sewardje1042472002-09-30 12:33:11 +0000161
162 seg_selector &= 0x0000FFFF;
163
164 /* Sanity check the segment selector. Ensure that TI=1 (LDT) and
165 that RPL=11b (least priviledge). These form the bottom 3 bits
166 of the selector. */
167 vg_assert((seg_selector & 7) == 7);
168
169 /* convert it onto a table index */
170 seg_selector >>= 3;
171 vg_assert(seg_selector >= 0 && seg_selector < 8192);
172
173 /* Come up with a suitable LDT entry. We look at the thread's LDT,
174 which is pointed to by a VG_(baseBlock) entry. If null, we will
175 use an implied zero-entry -- although this usually implies the
176 program is in deep trouble, since it is using LDT entries which
177 it probably hasn't set up. */
178 the_ldt = (VgLdtEntry*)VG_(baseBlock)[VGOFF_(ldt)];
179 if (the_ldt == NULL) {
180 base = 0;
181 limit = 0;
sewardjc4a71322002-09-30 22:06:28 +0000182 VG_(message)(
183 Vg_UserMsg,
184 "Warning: segment-override prefix encountered, but thread has no LDT"
185 );
sewardje1042472002-09-30 12:33:11 +0000186 } else {
187 base = (Addr)wine_ldt_get_base ( &the_ldt[seg_selector] );
188 limit = (UInt)wine_ldt_get_limit ( &the_ldt[seg_selector] );
189 }
190
sewardj874f3882002-09-30 22:56:26 +0000191 /* Note, this check is just slightly too slack. Really it should
192 be "if (virtual_addr + size - 1 >= limit)," but we don't have the
193 size info to hand. Getting it could be significantly complex. */
sewardje1042472002-09-30 12:33:11 +0000194 if (virtual_addr >= limit) {
sewardjc4a71322002-09-30 22:06:28 +0000195 VG_(message)(
196 Vg_UserMsg,
197 "Warning: segment access: virtual addr %d exceeds segment limit of %d",
198 virtual_addr, limit
199 );
sewardje1042472002-09-30 12:33:11 +0000200 }
201
202 return base + virtual_addr;
203}
204
sewardj92a59562002-09-30 00:53:10 +0000205
206/* Translate a struct modify_ldt_ldt_s to an VgLdtEntry, using the
207 Linux kernel's logic (cut-n-paste of code in linux/kernel/ldt.c). */
208
209static
210void translate_to_hw_format ( /* IN */ struct vki_modify_ldt_ldt_s* inn,
211 /* OUT */ VgLdtEntry* out,
212 Int oldmode )
213{
214 UInt entry_1, entry_2;
215
216 /* Allow LDTs to be cleared by the user. */
217 if (inn->base_addr == 0 && inn->limit == 0) {
218 if (oldmode ||
219 (inn->contents == 0 &&
220 inn->read_exec_only == 1 &&
221 inn->seg_32bit == 0 &&
222 inn->limit_in_pages == 0 &&
223 inn->seg_not_present == 1 &&
224 inn->useable == 0 )) {
225 entry_1 = 0;
226 entry_2 = 0;
227 goto install;
228 }
229 }
230
231 entry_1 = ((inn->base_addr & 0x0000ffff) << 16) |
232 (inn->limit & 0x0ffff);
233 entry_2 = (inn->base_addr & 0xff000000) |
234 ((inn->base_addr & 0x00ff0000) >> 16) |
235 (inn->limit & 0xf0000) |
236 ((inn->read_exec_only ^ 1) << 9) |
237 (inn->contents << 10) |
238 ((inn->seg_not_present ^ 1) << 15) |
239 (inn->seg_32bit << 22) |
240 (inn->limit_in_pages << 23) |
241 0x7000;
242 if (!oldmode)
243 entry_2 |= (inn->useable << 20);
244
245 /* Install the new entry ... */
246 install:
247 out->LdtEnt.Words.word1 = entry_1;
248 out->LdtEnt.Words.word2 = entry_2;
249}
250
251
252/*
253 * linux/kernel/ldt.c
254 *
255 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
256 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
257 */
258
259/*
260 * read_ldt() is not really atomic - this is not a problem since
261 * synchronization of reads and writes done to the LDT has to be
262 * assured by user-space anyway. Writes are atomic, to protect
263 * the security checks done on new descriptors.
264 */
265static
266Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount )
267{
268 Int err;
269 UInt i, size;
270 Char* ldt;
271
sewardjc4a71322002-09-30 22:06:28 +0000272 if (0)
njn854e7152002-09-30 10:47:35 +0000273 VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n",
274 tid, ptr, bytecount );
sewardj92a59562002-09-30 00:53:10 +0000275
276 ldt = (Char*)(VG_(threads)[tid].ldt);
277 err = 0;
278 if (ldt == NULL)
279 /* LDT not allocated, meaning all entries are null */
280 goto out;
281
282 size = VG_M_LDT_ENTRIES * VG_LDT_ENTRY_SIZE;
283 if (size > bytecount)
284 size = bytecount;
285
286 err = size;
287 for (i = 0; i < size; i++)
288 ptr[i] = ldt[i];
289
290 out:
291 return err;
292}
293
294
295static
296Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode )
297{
298 Int error;
299 VgLdtEntry* ldt;
300 struct vki_modify_ldt_ldt_s* ldt_info;
301
sewardjc4a71322002-09-30 22:06:28 +0000302 if (0)
njn854e7152002-09-30 10:47:35 +0000303 VG_(printf)("write_ldt: tid = %d, ptr = %p, "
304 "bytecount = %d, oldmode = %d\n",
305 tid, ptr, bytecount, oldmode );
sewardj92a59562002-09-30 00:53:10 +0000306
307 ldt = VG_(threads)[tid].ldt;
308 ldt_info = (struct vki_modify_ldt_ldt_s*)ptr;
309
310 error = -VKI_EINVAL;
311 if (bytecount != sizeof(struct vki_modify_ldt_ldt_s))
312 goto out;
313
314 error = -VKI_EINVAL;
315 if (ldt_info->entry_number >= VG_M_LDT_ENTRIES)
316 goto out;
317 if (ldt_info->contents == 3) {
318 if (oldmode)
319 goto out;
320 if (ldt_info->seg_not_present == 0)
321 goto out;
322 }
323
324 /* If this thread doesn't have an LDT, we'd better allocate it
325 now. */
326 if (ldt == NULL) {
327 ldt = VG_(allocate_LDT_for_thread)( NULL );
328 VG_(threads)[tid].ldt = ldt;
329 }
330
331 /* Install the new entry ... */
332 translate_to_hw_format ( ldt_info, &ldt[ldt_info->entry_number], oldmode );
333 error = 0;
334
335 out:
336 return error;
337}
338
339
340Int VG_(sys_modify_ldt) ( ThreadId tid,
341 Int func, void* ptr, UInt bytecount )
342{
343 Int ret = -VKI_ENOSYS;
344
345 switch (func) {
346 case 0:
347 ret = read_ldt(tid, ptr, bytecount);
348 break;
349 case 1:
350 ret = write_ldt(tid, ptr, bytecount, 1);
351 break;
352 case 2:
353 VG_(unimplemented)("sys_modify_ldt: func == 2");
354 /* god knows what this is about */
355 /* ret = read_default_ldt(ptr, bytecount); */
356 /*UNREACHED*/
357 break;
358 case 0x11:
359 ret = write_ldt(tid, ptr, bytecount, 0);
360 break;
361 }
362 return ret;
363}
364
365
366/*--------------------------------------------------------------------*/
367/*--- end vg_ldt.c ---*/
368/*--------------------------------------------------------------------*/