blob: 6d746029b3d2bf39713d45a325b02223eaa00963 [file] [log] [blame]
sewardj92a59562002-09-30 00:53:10 +00001
2/*--------------------------------------------------------------------*/
3/*--- Simulation of Local Descriptor Tables vg_ldt.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
njnc9539842002-10-02 13:26:35 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardj92a59562002-09-30 00:53:10 +00009
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
sewardjbe4015a2002-10-03 16:14:57 +0000216 if (0)
217 VG_(printf)("translate_to_hw_format: base %p, limit %d\n",
218 inn->base_addr, inn->limit );
219
sewardj92a59562002-09-30 00:53:10 +0000220 /* Allow LDTs to be cleared by the user. */
221 if (inn->base_addr == 0 && inn->limit == 0) {
222 if (oldmode ||
223 (inn->contents == 0 &&
224 inn->read_exec_only == 1 &&
225 inn->seg_32bit == 0 &&
226 inn->limit_in_pages == 0 &&
227 inn->seg_not_present == 1 &&
228 inn->useable == 0 )) {
229 entry_1 = 0;
230 entry_2 = 0;
231 goto install;
232 }
233 }
234
235 entry_1 = ((inn->base_addr & 0x0000ffff) << 16) |
236 (inn->limit & 0x0ffff);
237 entry_2 = (inn->base_addr & 0xff000000) |
238 ((inn->base_addr & 0x00ff0000) >> 16) |
239 (inn->limit & 0xf0000) |
240 ((inn->read_exec_only ^ 1) << 9) |
241 (inn->contents << 10) |
242 ((inn->seg_not_present ^ 1) << 15) |
243 (inn->seg_32bit << 22) |
244 (inn->limit_in_pages << 23) |
245 0x7000;
246 if (!oldmode)
247 entry_2 |= (inn->useable << 20);
248
249 /* Install the new entry ... */
250 install:
251 out->LdtEnt.Words.word1 = entry_1;
252 out->LdtEnt.Words.word2 = entry_2;
253}
254
255
256/*
257 * linux/kernel/ldt.c
258 *
259 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
260 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
261 */
262
263/*
264 * read_ldt() is not really atomic - this is not a problem since
265 * synchronization of reads and writes done to the LDT has to be
266 * assured by user-space anyway. Writes are atomic, to protect
267 * the security checks done on new descriptors.
268 */
269static
270Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount )
271{
272 Int err;
273 UInt i, size;
274 Char* ldt;
275
sewardjc4a71322002-09-30 22:06:28 +0000276 if (0)
njn854e7152002-09-30 10:47:35 +0000277 VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n",
278 tid, ptr, bytecount );
sewardj92a59562002-09-30 00:53:10 +0000279
280 ldt = (Char*)(VG_(threads)[tid].ldt);
281 err = 0;
282 if (ldt == NULL)
283 /* LDT not allocated, meaning all entries are null */
284 goto out;
285
286 size = VG_M_LDT_ENTRIES * VG_LDT_ENTRY_SIZE;
287 if (size > bytecount)
288 size = bytecount;
289
290 err = size;
291 for (i = 0; i < size; i++)
292 ptr[i] = ldt[i];
293
294 out:
295 return err;
296}
297
298
299static
300Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode )
301{
302 Int error;
303 VgLdtEntry* ldt;
304 struct vki_modify_ldt_ldt_s* ldt_info;
305
sewardjc4a71322002-09-30 22:06:28 +0000306 if (0)
njn854e7152002-09-30 10:47:35 +0000307 VG_(printf)("write_ldt: tid = %d, ptr = %p, "
308 "bytecount = %d, oldmode = %d\n",
309 tid, ptr, bytecount, oldmode );
sewardj92a59562002-09-30 00:53:10 +0000310
311 ldt = VG_(threads)[tid].ldt;
312 ldt_info = (struct vki_modify_ldt_ldt_s*)ptr;
313
314 error = -VKI_EINVAL;
315 if (bytecount != sizeof(struct vki_modify_ldt_ldt_s))
316 goto out;
317
318 error = -VKI_EINVAL;
319 if (ldt_info->entry_number >= VG_M_LDT_ENTRIES)
320 goto out;
321 if (ldt_info->contents == 3) {
322 if (oldmode)
323 goto out;
324 if (ldt_info->seg_not_present == 0)
325 goto out;
326 }
327
328 /* If this thread doesn't have an LDT, we'd better allocate it
329 now. */
330 if (ldt == NULL) {
331 ldt = VG_(allocate_LDT_for_thread)( NULL );
332 VG_(threads)[tid].ldt = ldt;
333 }
334
335 /* Install the new entry ... */
336 translate_to_hw_format ( ldt_info, &ldt[ldt_info->entry_number], oldmode );
337 error = 0;
338
339 out:
340 return error;
341}
342
343
344Int VG_(sys_modify_ldt) ( ThreadId tid,
345 Int func, void* ptr, UInt bytecount )
346{
347 Int ret = -VKI_ENOSYS;
348
349 switch (func) {
350 case 0:
351 ret = read_ldt(tid, ptr, bytecount);
352 break;
353 case 1:
354 ret = write_ldt(tid, ptr, bytecount, 1);
355 break;
356 case 2:
357 VG_(unimplemented)("sys_modify_ldt: func == 2");
358 /* god knows what this is about */
359 /* ret = read_default_ldt(ptr, bytecount); */
360 /*UNREACHED*/
361 break;
362 case 0x11:
363 ret = write_ldt(tid, ptr, bytecount, 0);
364 break;
365 }
366 return ret;
367}
368
369
370/*--------------------------------------------------------------------*/
371/*--- end vg_ldt.c ---*/
372/*--------------------------------------------------------------------*/