View | Details | Raw Unified | Return to bug 33299
Collapse All | Expand All

(-)conf/files.i386 (+1 lines)
Lines 288-293 Link Here
288
i386/linux/linux_locore.s	optional	compat_linux		\
288
i386/linux/linux_locore.s	optional	compat_linux		\
289
	dependency 	"linux_assym.h"
289
	dependency 	"linux_assym.h"
290
i386/linux/linux_machdep.c	optional	compat_linux
290
i386/linux/linux_machdep.c	optional	compat_linux
291
i386/linux/linux_ptrace.c	optional	compat_linux
291
i386/linux/linux_sysent.c	optional	compat_linux
292
i386/linux/linux_sysent.c	optional	compat_linux
292
i386/linux/linux_sysvec.c	optional	compat_linux
293
i386/linux/linux_sysvec.c	optional	compat_linux
293
i386/pci/pci_cfgreg.c		optional	pci
294
i386/pci/pci_cfgreg.c		optional	pci
(-)kern/sys_process.c (-1 / +1 lines)
Lines 419-425 Link Here
419
	case PT_STEP:
419
	case PT_STEP:
420
	case PT_CONTINUE:
420
	case PT_CONTINUE:
421
	case PT_DETACH:
421
	case PT_DETACH:
422
		if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG))
422
		if ((uap->req != PT_STEP) && ((unsigned)uap->data > _SIG_MAXSIG))
423
			return (EINVAL);
423
			return (EINVAL);
424
424
425
		PHOLD(p);
425
		PHOLD(p);
(-)i386/linux/linux_ptrace.c (+499 lines)
Added Link Here
1
/*
2
 * Copyright (c) 2001 Alexander Kabaev
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer 
10
 *    in this position and unchanged.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * $FreeBSD:$
29
 */
30
31
#include <sys/param.h>
32
#include <sys/systm.h>
33
#include <sys/lock.h>
34
#include <sys/mutex.h>
35
#include <sys/proc.h>
36
#include <sys/ptrace.h>
37
#include <sys/sysproto.h>
38
#include <sys/user.h>
39
40
#include <machine/md_var.h>
41
#include <machine/npx.h>
42
#include <machine/reg.h>
43
44
#include <i386/linux/linux.h>
45
#include <i386/linux/linux_proto.h>
46
#include <compat/linux/linux_util.h>
47
48
/* 
49
 *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
50
 *   except for MD ones and PT_ATTACH/PT_DETACH.
51
 */
52
#define	PTRACE_TRACEME		0
53
#define	PTRACE_PEEKTEXT		1
54
#define	PTRACE_PEEKDATA		2
55
#define	PTRACE_PEEKUSR		3
56
#define	PTRACE_POKETEXT		4
57
#define	PTRACE_POKEDATA		5
58
#define	PTRACE_POKEUSR		6
59
#define	PTRACE_CONT		7
60
#define	PTRACE_KILL		8
61
#define	PTRACE_SINGLESTEP	9
62
63
#define PTRACE_ATTACH		16
64
#define PTRACE_DETACH		17
65
66
#define	PTRACE_SYSCALL		24
67
68
#define PTRACE_GETREGS		12
69
#define PTRACE_SETREGS		13
70
#define PTRACE_GETFPREGS	14
71
#define PTRACE_SETFPREGS	15
72
#define PTRACE_GETFPXREGS	18
73
#define PTRACE_SETFPXREGS	19
74
75
#define PTRACE_SETOPTIONS	21
76
77
/*
78
 * Linux keeps debug registers at the following
79
 * offset in the user struct
80
 */
81
#define LINUX_DBREG_OFFSET	252
82
#define LINUX_DBREG_SIZE	8*sizeof(l_int)
83
84
static __inline__ int 
85
map_signum(int signum)
86
{
87
#ifndef __alpha__
88
	if (signum > 0 && signum <= LINUX_SIGTBLSZ)
89
		signum = linux_to_bsd_signal[_SIG_IDX(signum)];
90
#endif
91
	return ((signum == SIGSTOP)? 0 : signum);
92
}
93
94
struct linux_pt_reg {
95
	l_long	ebx;
96
	l_long	ecx;
97
	l_long	edx;
98
	l_long	esi;
99
	l_long	edi;
100
	l_long	ebp;
101
	l_long	eax;
102
	l_int	xds;
103
	l_int	xes;
104
	l_int	xfs;
105
	l_int	xgs;
106
	l_long	orig_eax;
107
	l_long	eip;
108
	l_int	xcs;
109
	l_long	eflags;
110
	l_long	esp;
111
	l_int	xss;
112
};
113
114
115
/* 
116
 *   Translate i386 ptrace registers between Linux and FreeBSD formats.
117
 *   The translation is pretty straighforward, for all registers, but
118
 *   orig_eax in Linux side and r_trapno and r_err in FreeBSD
119
 */
120
static int 
121
map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
122
{
123
	linux_r->ebx = bsd_r->r_ebx;
124
	linux_r->ecx = bsd_r->r_ecx;
125
	linux_r->edx = bsd_r->r_edx;
126
	linux_r->esi = bsd_r->r_esi;
127
	linux_r->edi = bsd_r->r_edi;
128
	linux_r->ebp = bsd_r->r_ebp;
129
	linux_r->eax = bsd_r->r_eax;
130
	linux_r->xds = bsd_r->r_ds;
131
	linux_r->xes = bsd_r->r_es;
132
	linux_r->xfs = bsd_r->r_fs;
133
	linux_r->xgs = bsd_r->r_gs;
134
	linux_r->orig_eax = bsd_r->r_eax;
135
	linux_r->eip = bsd_r->r_eip;
136
	linux_r->xcs = bsd_r->r_cs;
137
	linux_r->eflags = bsd_r->r_eflags;
138
	linux_r->esp = bsd_r->r_esp;
139
	linux_r->xss = bsd_r->r_ss;
140
	return (0);
141
}
142
143
static int 
144
map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
145
{
146
	bsd_r->r_ebx = linux_r->ebx;
147
	bsd_r->r_ecx = linux_r->ecx;
148
	bsd_r->r_edx = linux_r->edx;
149
	bsd_r->r_esi = linux_r->esi;
150
	bsd_r->r_edi = linux_r->edi;
151
	bsd_r->r_ebp = linux_r->ebp;
152
	bsd_r->r_eax = linux_r->eax;
153
	bsd_r->r_ds  = linux_r->xds;
154
	bsd_r->r_es  = linux_r->xes;
155
	bsd_r->r_fs  = linux_r->xfs;
156
	bsd_r->r_gs  = linux_r->xgs;
157
	bsd_r->r_eip = linux_r->eip;
158
	bsd_r->r_cs  = linux_r->xcs;
159
	bsd_r->r_eflags = linux_r->eflags;
160
	bsd_r->r_esp = linux_r->esp;
161
	bsd_r->r_ss = linux_r->xss;
162
	return (0);
163
}
164
165
struct linux_pt_fpreg {
166
	l_long cwd;
167
	l_long swd;
168
	l_long twd;
169
	l_long fip;
170
	l_long fcs;
171
	l_long foo;
172
	l_long fos;
173
	l_long st_space[2*10];
174
};
175
176
static int 
177
map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
178
{
179
	linux_r->cwd = bsd_r->fpr_env[0];
180
	linux_r->swd = bsd_r->fpr_env[1];
181
	linux_r->twd = bsd_r->fpr_env[2];
182
	linux_r->fip = bsd_r->fpr_env[3];
183
	linux_r->fcs = bsd_r->fpr_env[4];
184
	linux_r->foo = bsd_r->fpr_env[5];
185
	linux_r->fos = bsd_r->fpr_env[6];
186
	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
187
	return (0);
188
}
189
190
static int 
191
map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
192
{
193
	bsd_r->fpr_env[0] = linux_r->cwd;
194
	bsd_r->fpr_env[1] = linux_r->swd;
195
	bsd_r->fpr_env[2] = linux_r->twd;
196
	bsd_r->fpr_env[3] = linux_r->fip;
197
	bsd_r->fpr_env[4] = linux_r->fcs;
198
	bsd_r->fpr_env[5] = linux_r->foo;
199
	bsd_r->fpr_env[6] = linux_r->fos;
200
	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
201
	return (0);
202
}
203
204
struct linux_pt_fpxreg {
205
	l_ushort	cwd;
206
	l_ushort	swd;
207
	l_ushort	twd;
208
	l_ushort	fop;
209
	l_long		fip;
210
	l_long		fcs;
211
	l_long		foo;
212
	l_long		fos;
213
	l_long		mxcsr;
214
	l_long		reserved;
215
	l_long		st_space[32];
216
	l_long		xmm_space[32];
217
	l_long		padding[56];
218
};
219
220
static int 
221
linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 
222
{
223
#ifdef CPU_ENABLE_SSE
224
	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
225
		printf("linux: savexmm != linux_pt_fpxreg\n");
226
		return (EIO);
227
	}
228
	if (cpu_fxsr == 0)
229
#endif
230
		return (EIO);
231
	bcopy(&td->td_pcb->pcb_save.sv_xmm, fpxregs, sizeof *fpxregs);
232
	return (0);
233
}
234
235
static int 
236
linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
237
{
238
#ifdef CPU_ENABLE_SSE
239
	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
240
		printf("linux: savexmm != linux_pt_fpxreg\n");
241
		return (EIO);
242
	}
243
	if (cpu_fxsr == 0)
244
#endif
245
		return (EIO);
246
	bcopy(fpxregs, &td->td_pcb->pcb_save.sv_xmm, sizeof *fpxregs);
247
	return (0);
248
}
249
250
251
int
252
linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
253
{
254
	struct ptrace_args bsd_args;
255
	int	error;
256
	caddr_t	sg;
257
	union {
258
		struct linux_pt_reg	reg;
259
		struct linux_pt_fpreg	fpreg;
260
		struct linux_pt_fpxreg	fpxreg;
261
	} r;
262
263
	sg = stackgap_init();
264
265
	error = 0;
266
267
	/* by default, just copy data intact */
268
	bsd_args.req  = uap->req;
269
	bsd_args.pid  = (pid_t)uap->pid;
270
	bsd_args.addr = (caddr_t)uap->addr;
271
	bsd_args.data = uap->data;
272
273
	switch (uap->req) {
274
	case PTRACE_TRACEME:
275
	case PTRACE_POKETEXT:
276
	case PTRACE_POKEDATA:
277
	case PTRACE_KILL:
278
		error = ptrace(td, &bsd_args);
279
		break;
280
	case PTRACE_PEEKTEXT:
281
	case PTRACE_PEEKDATA: {
282
		/* need to preserve return value */
283
		int rval = td->td_retval[0];
284
		bsd_args.data = 0;
285
		error = ptrace(td, &bsd_args);
286
		if (error == 0)
287
			error = copyout(td->td_retval,
288
			    (caddr_t)uap->data, sizeof(l_int));
289
		td->td_retval[0] = rval;
290
		break;
291
	}
292
	case PTRACE_DETACH:
293
		bsd_args.req = PT_DETACH;
294
		/* fall through */
295
	case PTRACE_SINGLESTEP:
296
	case PTRACE_CONT:
297
		bsd_args.data = map_signum(uap->data);
298
		bsd_args.addr = (caddr_t)1;
299
		error = ptrace(td, &bsd_args);
300
		break;
301
	case PTRACE_ATTACH:
302
		bsd_args.req = PT_ATTACH;
303
		error = ptrace(td, &bsd_args);
304
		break;
305
	case PTRACE_GETREGS: {
306
		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
307
                    sizeof(*bsd_r));
308
		/* Linux is using data where FreeBSD is using addr */
309
		bsd_args.req  = PT_GETREGS;
310
		bsd_args.addr = (caddr_t)bsd_r;
311
		bsd_args.data = 0;
312
		error = ptrace(td, &bsd_args);
313
		if (error == 0)
314
			error = map_regs_to_linux(bsd_r, &r.reg);
315
		if (error == 0)
316
			error = copyout(&r.reg, (caddr_t)uap->data, sizeof r.reg);
317
		break;
318
	}
319
	case PTRACE_SETREGS: {
320
		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
321
                    sizeof(*bsd_r));
322
		/* Linux is using data where FreeBSD is using addr */
323
		bsd_args.req  = PT_SETREGS;
324
		bsd_args.addr = (caddr_t)bsd_r;
325
		bsd_args.data = 0;
326
		error = copyin((caddr_t)uap->data, &r.reg, sizeof r.reg);
327
		if (error == 0)
328
			error = map_regs_from_linux(bsd_r, &r.reg);
329
		if (error == 0)
330
			error = ptrace(td, &bsd_args);
331
		break;
332
	}
333
	case PTRACE_GETFPREGS: {
334
		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
335
                    sizeof(*bsd_r));
336
		/* Linux is using data where FreeBSD is using addr */
337
		bsd_args.req  = PT_GETFPREGS;
338
		bsd_args.addr = (caddr_t)bsd_r;
339
		bsd_args.data = 0;
340
		error = ptrace(td, &bsd_args);
341
		if (error == 0)
342
			error = map_fpregs_to_linux(bsd_r, &r.fpreg);
343
		if (error == 0)
344
			error = copyout(&r.fpreg, (caddr_t)uap->data, sizeof r.fpreg);
345
		break;
346
	}
347
	case PTRACE_SETFPREGS: {
348
		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
349
                    sizeof(*bsd_r));
350
		/* Linux is using data where FreeBSD is using addr */
351
		bsd_args.req  = PT_SETFPREGS;
352
		bsd_args.addr = (caddr_t)bsd_r;
353
		bsd_args.data = 0;
354
		error = copyin((caddr_t)uap->data, &r.fpreg, sizeof r.fpreg);
355
		if (error == 0)
356
			error = map_fpregs_from_linux(bsd_r, &r.fpreg);
357
		if (error == 0)
358
			error = ptrace(td, &bsd_args);
359
		break;
360
	}
361
	case PTRACE_SETFPXREGS:
362
	case PTRACE_GETFPXREGS: {
363
		struct proc *p;
364
		struct fpreg *bsd_r;
365
366
		/*
367
		 * Use FreeBSD PT_GETFPREGS for permisson testing.
368
		 */
369
		bsd_r = (struct fpreg*)stackgap_alloc(&sg,
370
                    sizeof(*bsd_r));
371
		bsd_args.req  = PT_GETFPREGS;
372
		bsd_args.addr = (caddr_t)bsd_r;
373
		bsd_args.data = 0;
374
		error = ptrace(td, &bsd_args);
375
		/*
376
		 * If this fails, PTRACE_GETFPXREGS should fail
377
		 * for exactly the same reason. 
378
		*/
379
		if (error != 0) 			     
380
			break;
381
382
		if ((p = pfind(uap->pid)) == NULL) {
383
			error = ESRCH;
384
			break;
385
		}
386
		if (uap->req == PTRACE_GETFPXREGS) {
387
			PHOLD(p);
388
			error = linux_proc_read_fpxregs(
389
				&p->p_thread, &r.fpxreg);
390
			PRELE(p);
391
			if (error == 0)
392
				error = copyout(&r.fpxreg,
393
				    (caddr_t)uap->data, sizeof r.fpxreg);
394
		} else {
395
			error = copyin((caddr_t)uap->data,
396
			    &r.fpxreg, sizeof r.fpxreg);
397
			if (error == 0) {
398
				/* clear dangerous bits exactly as Linux does*/
399
				r.fpxreg.mxcsr &= 0xffbf;
400
				PHOLD(p);
401
				error = linux_proc_write_fpxregs(
402
					&p->p_thread, &r.fpxreg);
403
				PRELE(p);
404
			}
405
		}
406
		break;
407
	}
408
	case PTRACE_PEEKUSR:
409
	case PTRACE_POKEUSR: {
410
		error = EIO;
411
412
		/* check addr for alignment */
413
		if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
414
			break;
415
		/* 
416
		 * Allow linux programs to access register values in
417
		 * user struct. We simulate this through PT_GET/SETREGS
418
		 * as necessary.
419
		 */
420
		if (uap->addr < sizeof(struct linux_pt_reg)) {
421
			struct reg *bsd_r;
422
423
			bsd_r = (struct reg*)stackgap_alloc(&sg,
424
			    sizeof(*bsd_r));
425
			bsd_args.req  = PT_GETREGS;
426
			bsd_args.addr = (caddr_t)bsd_r;
427
			bsd_args.data = 0;
428
429
			error = ptrace(td, &bsd_args);
430
			if (error != 0)
431
				break;
432
			
433
			error = map_regs_to_linux(bsd_r, &r.reg);
434
			if (error != 0)
435
				break;
436
437
			if (uap->req == PTRACE_PEEKUSR) {
438
				error = copyout((char *)&r.reg + uap->addr,
439
				    (caddr_t)uap->data, sizeof(l_int));
440
				break;
441
			}
442
443
			*(l_int *)((char *)&r.reg + uap->addr) = (l_int)uap->data;
444
445
			error = map_regs_from_linux(bsd_r, &r.reg);
446
			if (error != 0)
447
				break;
448
449
			bsd_args.req  = PT_SETREGS;
450
			bsd_args.addr = (caddr_t)bsd_r;
451
			bsd_args.data = 0;
452
			error = ptrace(td, &bsd_args);
453
		}
454
		
455
		/* 
456
		 * Simulate debug registers access
457
		 */
458
		if (uap->addr >= LINUX_DBREG_OFFSET && 
459
		    uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
460
			struct dbreg *bsd_r;
461
462
			bsd_r = (struct dbreg*)stackgap_alloc(&sg,
463
			    sizeof(*bsd_r));
464
			bsd_args.req  = PT_GETDBREGS;
465
			bsd_args.addr = (caddr_t)bsd_r;
466
			bsd_args.data = 0;
467
			error = ptrace(td, &bsd_args);
468
			if (error != 0)
469
				break;
470
			
471
			uap->addr -= LINUX_DBREG_OFFSET;
472
			if (uap->req == PTRACE_PEEKUSR) {
473
				error = copyout((char *)bsd_r + uap->addr,
474
				    (caddr_t)uap->data, sizeof(l_int));
475
				break;
476
			}
477
478
			*(l_int *)((char *)bsd_r + uap->addr) = uap->data;
479
			bsd_args.req  = PT_SETDBREGS;
480
			bsd_args.addr = (caddr_t)bsd_r;
481
			bsd_args.data = 0;
482
			error = ptrace(td, &bsd_args);
483
		}
484
485
		break;
486
	}
487
	case PTRACE_SYSCALL:
488
		/* fall through */
489
	default:
490
		error = EINVAL;
491
		goto noimpl;
492
	}
493
	return (error);
494
495
 noimpl:
496
	printf("linux: ptrace(%u, ...) not implemented\n",
497
	    (u_int32_t)uap->req);
498
	return (error);
499
}
(-)i386/linux/linux_dummy.c (-1 lines)
Lines 38-44 Link Here
38
38
39
DUMMY(stat);
39
DUMMY(stat);
40
DUMMY(stime);
40
DUMMY(stime);
41
DUMMY(ptrace);
42
DUMMY(fstat);
41
DUMMY(fstat);
43
DUMMY(olduname);
42
DUMMY(olduname);
44
DUMMY(syslog);
43
DUMMY(syslog);
(-)i386/linux/syscalls.master (-1 / +2 lines)
Lines 65-71 Link Here
65
23	STD	LINUX	{ int linux_setuid16(l_uid16_t uid); }
65
23	STD	LINUX	{ int linux_setuid16(l_uid16_t uid); }
66
24	STD	LINUX	{ int linux_getuid16(void); }
66
24	STD	LINUX	{ int linux_getuid16(void); }
67
25	STD	LINUX	{ int linux_stime(void); }
67
25	STD	LINUX	{ int linux_stime(void); }
68
26	STD	LINUX	{ int linux_ptrace(void); }
68
26	STD	LINUX	{ int linux_ptrace(l_long req, l_long pid, l_long addr, \
69
                            l_long data); }
69
27	STD	LINUX	{ int linux_alarm(l_uint secs); }
70
27	STD	LINUX	{ int linux_alarm(l_uint secs); }
70
28	STD	LINUX	{ int linux_fstat(l_uint fd, struct ostat *up); }
71
28	STD	LINUX	{ int linux_fstat(l_uint fd, struct ostat *up); }
71
29	STD	LINUX	{ int linux_pause(void); }
72
29	STD	LINUX	{ int linux_pause(void); }
(-)modules/linux/Makefile (-1 / +3 lines)
Lines 8-14 Link Here
8
SRCS=	linux_dummy.c linux_file.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
8
SRCS=	linux_dummy.c linux_file.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
9
	linux_machdep.c linux_mib.c linux_misc.c linux_signal.c linux_socket.c \
9
	linux_machdep.c linux_mib.c linux_misc.c linux_signal.c linux_socket.c \
10
	linux_stats.c linux_sysctl.c linux_sysent.c linux_sysvec.c \
10
	linux_stats.c linux_sysctl.c linux_sysent.c linux_sysvec.c \
11
	linux_util.c opt_compat.h opt_linux.h opt_vmpage.h vnode_if.h
11
	linux_util.c linux_ptrace.c opt_compat.h opt_linux.h opt_vmpage.h \
12
	vnode_if.h
13
12
OBJS=	linux_locore.o
14
OBJS=	linux_locore.o
13
15
14
.if ${MACHINE_ARCH} == "i386"
16
.if ${MACHINE_ARCH} == "i386"

Return to bug 33299