|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1993 NeXT Computer, Inc.
27: *
28: * PC support Real mode emulation.
29: *
30: * HISTORY
31: *
32: * 23 Mar 1993 ? at NeXT
33: * Created.
34: */
35:
36: #import <mach/mach_types.h>
37:
38: #import <architecture/i386/sel.h>
39: #import <machdep/i386/trap.h>
40: #import <machdep/i386/err_inline.h>
41:
42: #import "PCprivate.h"
43: #import "PCmiscInline.h"
44: #import "PCtaskInline.h"
45:
46: struct inst_prefix {
47: unsigned int opnd :1,
48: addr :1;
49: };
50:
51: static __inline__
52: vm_offset_t
53: segment_base(
54: sel_t sel
55: )
56: {
57: return ((*(unsigned short *)&sel) << 4);
58: }
59:
60: static __inline__
61: fetch_segment_byte(
62: thread_t thread,
63: sel_t sel,
64: unsigned short offset,
65: unsigned char *data
66: )
67: {
68: vm_offset_t base = segment_base(sel);
69:
70: return (fetchByte(thread, base + offset, data));
71: }
72:
73: static __inline__
74: fetch_segment_2byte(
75: thread_t thread,
76: sel_t sel,
77: unsigned short offset,
78: unsigned short *data
79: )
80: {
81: vm_offset_t base = segment_base(sel);
82:
83: return (fetch2Byte(thread, base + offset, data));
84: }
85:
86: static __inline__
87: store_segment_2byte(
88: thread_t thread,
89: sel_t sel,
90: unsigned short offset,
91: unsigned short data
92: )
93: {
94: vm_offset_t base = segment_base(sel);
95:
96: return (store2Byte(thread, base + offset, data));
97: }
98:
99: static __inline__
100: fetch_segment_4byte(
101: thread_t thread,
102: sel_t sel,
103: unsigned short offset,
104: unsigned int *data
105: )
106: {
107: vm_offset_t base = segment_base(sel);
108:
109: return (fetch4Byte(thread, base + offset, data));
110: }
111:
112: static __inline__
113: store_segment_4byte(
114: thread_t thread,
115: sel_t sel,
116: unsigned short offset,
117: unsigned int data
118: )
119: {
120: vm_offset_t base = segment_base(sel);
121:
122: return (store4Byte(thread, base + offset, data));
123: }
124:
125: static __inline__
126: boolean_t
127: fetch_segment(
128: thread_t thread,
129: sel_t sel,
130: unsigned short offset,
131: void *data,
132: unsigned int length
133: )
134: {
135: #define sdata ((unsigned short *)data)
136: vm_offset_t base = segment_base(sel);
137:
138: thread->recover = (vm_offset_t)&&fault;
139:
140: while (length > 0) {
141: asm volatile(
142: "movw %%fs:%1,%0"
143: : "=q" (*sdata)
144: : "m" (*(unsigned short *)(base + offset)));
145:
146: sdata++; offset += sizeof (*sdata); length -= sizeof (*sdata);
147: }
148:
149: thread->recover = 0;
150: return (TRUE);
151:
152: fault:
153: thread->recover = 0;
154: return (FALSE);
155: #undef sdata
156: }
157:
158: static __inline__
159: boolean_t
160: store_segment(
161: thread_t thread,
162: sel_t sel,
163: unsigned short offset,
164: void *data,
165: unsigned int length
166: )
167: {
168: #define sdata ((unsigned short *)data)
169: vm_offset_t base = segment_base(sel);
170:
171: thread->recover = (vm_offset_t)&&fault;
172:
173: while (length > 0) {
174: asm volatile(
175: "movw %0,%%fs:%1"
176: :
177: : "r" (*sdata), "m" (*(unsigned short *)(base + offset)));
178:
179: sdata++; offset += sizeof (*sdata); length -= sizeof (*sdata);
180: }
181:
182: thread->recover = 0;
183: return (TRUE);
184:
185: fault:
186: thread->recover = 0;
187: return (FALSE);
188: #undef sdata
189: }
190:
191: static
192: boolean_t
193: handle_bop(
194: thread_t thread,
195: thread_saved_state_t *state
196: )
197: {
198: PCcontext_t context = threadPCContext(thread);
199: unsigned int inst;
200: unsigned char bbyte;
201:
202: if (!fetch_segment_4byte(
203: thread,
204: state->frame.cs, state->frame.eip,
205: &inst))
206: return (FALSE);
207:
208: if (*(unsigned short *)&inst != 0xC4C4)
209: return (FALSE);
210:
211: bbyte = *((unsigned char *)&inst + 2);
212:
213: if (bbyte == 0xFE) {
214: PCcancelTimers(context);
215:
216: context->callHandler = PC_HANDLE_EXIT;
217:
218: PCcallMonitor(thread, state);
219: /* NOTREACHED */
220: }
221: else if (bbyte == 0xFA) {
222: PCbopFA_t args;
223:
224: if (!fetch_segment(
225: thread,
226: state->frame.ss, state->frame.esp,
227: &args, sizeof (args)))
228: return (FALSE);
229:
230: return (PCbopFA(thread, state, &args));
231: /* NOTREACHED */
232: }
233: else if (bbyte == 0xFC) {
234: PCbopFC_t args;
235:
236: if (!fetch_segment(
237: thread,
238: state->frame.ss, state->frame.esp,
239: &args, sizeof (args)))
240: return (FALSE);
241:
242: return (PCbopFC(thread, state, &args));
243: /* NOTREACHED */
244: }
245: else if (bbyte == 0xFD) {
246: PCbopFD_t args;
247:
248: if (!fetch_segment(
249: thread,
250: state->frame.ss, state->frame.esp,
251: &args, sizeof (args)))
252: return (FALSE);
253:
254: PCbopFD(thread, state, &args);
255: /* NOTREACHED */
256: }
257: else {
258: context->trapNum = bbyte;
259: context->callHandler = PC_HANDLE_BOP;
260:
261: PCcallMonitor(thread, state);
262: /* NOTREACHED */
263: }
264: }
265:
266: static __inline__
267: boolean_t
268: fetch_inst(
269: thread_t thread,
270: thread_saved_state_t *state,
271: int *offset,
272: unsigned char *inst,
273: struct inst_prefix *prefix
274: )
275: {
276: sel_t cs;
277: unsigned short ip;
278: unsigned char ibyte;
279: int n;
280:
281: cs = state->frame.cs;
282: ip = state->frame.eip;
283:
284: for (n = 0; n < 15; n++) { // a reasonable limit
285: if (!fetch_segment_byte(thread, cs, ip + n, &ibyte))
286: break;
287:
288: switch (ibyte) {
289:
290: case 0x66: // Operand-size prefix
291: prefix->opnd = TRUE;
292: break;
293:
294: case 0xf0: // LOCK prefix
295: break;
296:
297: default:
298: *offset = (ip + n) - ip;
299: *inst = ibyte - 0x90;
300:
301: return (TRUE);
302: }
303: }
304:
305: return (FALSE);
306: }
307:
308: static
309: boolean_t
310: emulate_CLI(
311: thread_t thread,
312: thread_saved_state_t *state,
313: int offset,
314: struct inst_prefix prefix
315: )
316: {
317: PCcontext_t context = threadPCContext(thread);
318:
319: (unsigned short)state->frame.eip += (offset + 1);
320:
321: context->IF_flag = FALSE;
322:
323: return (TRUE);
324: }
325:
326: static
327: boolean_t
328: emulate_STI(
329: thread_t thread,
330: thread_saved_state_t *state,
331: int offset,
332: struct inst_prefix prefix
333: )
334: {
335: PCcontext_t context = threadPCContext(thread);
336:
337: (unsigned short)state->frame.eip += (offset + 1);
338:
339: if (!context->IF_flag) {
340: context->IF_flag = TRUE;
341:
342: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
343: }
344:
345: return (TRUE);
346: }
347:
348: static boolean_t emulate_PUSHFD(
349: thread_t thread,
350: thread_saved_state_t *state,
351: int offset,
352: struct inst_prefix prefix);
353:
354: static
355: boolean_t
356: emulate_PUSHF(
357: thread_t thread,
358: thread_saved_state_t *state,
359: int offset,
360: struct inst_prefix prefix
361: )
362: {
363: PCcontext_t context;
364: struct {
365: unsigned short flags;
366: } frame;
367:
368: if (prefix.opnd)
369: return (emulate_PUSHFD(thread, state, offset, prefix));
370:
371: context = threadPCContext(thread);
372:
373: frame.flags = state->frame.eflags;
374: if (context->IF_flag)
375: frame.flags |= EFL_IF;
376: else
377: frame.flags &= ~EFL_IF;
378:
379: frame.flags |= (context->X_flags & (EFL_NT | EFL_IOPL));
380:
381: if (!store_segment_2byte(
382: thread,
383: state->frame.ss, state->frame.esp - sizeof (frame),
384: frame.flags))
385: return (FALSE);
386:
387: (unsigned short)state->frame.eip += (offset + 1);
388:
389: (unsigned short)state->frame.esp -= sizeof (frame);
390:
391: return (TRUE);
392: }
393:
394: static
395: boolean_t
396: emulate_PUSHFD(
397: thread_t thread,
398: thread_saved_state_t *state,
399: int offset,
400: struct inst_prefix prefix
401: )
402: {
403: PCcontext_t context;
404: struct {
405: unsigned int eflags;
406: } frame;
407:
408: context = threadPCContext(thread);
409:
410: frame.eflags = state->frame.eflags;
411: if (context->IF_flag)
412: frame.eflags |= EFL_IF;
413: else
414: frame.eflags &= ~EFL_IF;
415:
416: frame.eflags |= (context->X_flags & (EFL_NT | EFL_IOPL));
417:
418: if (!store_segment_4byte(
419: thread,
420: state->frame.ss, state->frame.esp - sizeof (frame),
421: frame.eflags))
422: return (FALSE);
423:
424: (unsigned short)state->frame.eip += (offset + 1);
425:
426: (unsigned short)state->frame.esp -= sizeof (frame);
427:
428: return (TRUE);
429: }
430:
431: static boolean_t emulate_POPFD(
432: thread_t thread,
433: thread_saved_state_t *state,
434: int offset,
435: struct inst_prefix prefix);
436:
437: static
438: boolean_t
439: emulate_POPF(
440: thread_t thread,
441: thread_saved_state_t *state,
442: int offset,
443: struct inst_prefix prefix
444: )
445: {
446: PCcontext_t context;
447: struct {
448: unsigned short flags;
449: } frame;
450:
451: if (prefix.opnd)
452: return (emulate_POPFD(thread, state, offset, prefix));
453:
454: context = threadPCContext(thread);
455:
456: if (!fetch_segment_2byte(
457: thread,
458: state->frame.ss, state->frame.esp,
459: &frame.flags))
460: return (FALSE);
461:
462: if ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) != 0)
463: frame.flags |= (state->frame.eflags & EFL_TF);
464: (unsigned short)state->frame.eflags = frame.flags;
465: state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR );
466: state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET );
467:
468: (unsigned short)state->frame.eip += (offset + 1);
469: (unsigned short)state->frame.esp += sizeof (frame);
470:
471: context->X_flags = (frame.flags & (EFL_NT | EFL_IOPL));
472:
473: if (frame.flags & EFL_IF) {
474: if (!context->IF_flag)
475: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
476:
477: context->IF_flag = TRUE;
478: }
479: else
480: context->IF_flag = FALSE;
481:
482: return (TRUE);
483: }
484:
485: static
486: boolean_t
487: emulate_POPFD(
488: thread_t thread,
489: thread_saved_state_t *state,
490: int offset,
491: struct inst_prefix prefix
492: )
493: {
494: PCcontext_t context;
495: struct {
496: unsigned long eflags;
497: } frame;
498:
499: context = threadPCContext(thread);
500:
501: if (!fetch_segment_4byte(
502: thread,
503: state->frame.ss, state->frame.esp,
504: &frame.eflags))
505: return (FALSE);
506:
507: if ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) != 0)
508: frame.eflags |= (state->frame.eflags & EFL_TF);
509: state->frame.eflags = frame.eflags;
510: state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR );
511: state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET );
512:
513: (unsigned short)state->frame.eip += (offset + 1);
514: (unsigned short)state->frame.esp += sizeof (frame);
515:
516: context->X_flags = (frame.eflags & (EFL_NT | EFL_IOPL));
517:
518: if (frame.eflags & EFL_IF) {
519: if (!context->IF_flag)
520: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
521:
522: context->IF_flag = TRUE;
523: }
524: else
525: context->IF_flag = FALSE;
526:
527: return (TRUE);
528: }
529:
530: static boolean_t emulate_IRETD(
531: thread_t thread,
532: thread_saved_state_t *state,
533: int offset,
534: struct inst_prefix prefix);
535:
536: static
537: boolean_t
538: emulate_IRET(
539: thread_t thread,
540: thread_saved_state_t *state,
541: int offset,
542: struct inst_prefix prefix
543: )
544: {
545: PCcontext_t context;
546: struct {
547: unsigned short ip;
548: sel_t cs;
549: unsigned short flags;
550: } frame;
551:
552: if (prefix.opnd)
553: return (emulate_IRETD(thread, state, offset, prefix));
554:
555: context = threadPCContext(thread);
556:
557: if (!fetch_segment(
558: thread,
559: state->frame.ss, state->frame.esp,
560: &frame, sizeof (frame)))
561: return (FALSE);
562:
563: (unsigned short)state->frame.eip = frame.ip;
564: state->frame.cs = frame.cs;
565:
566: if ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) != 0)
567: frame.flags |= (state->frame.eflags & EFL_TF);
568: (unsigned short)state->frame.eflags = frame.flags;
569: state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR );
570: state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET );
571:
572: (unsigned short)state->frame.esp += sizeof (frame);
573:
574: context->X_flags = (frame.flags & (EFL_NT | EFL_IOPL));
575:
576: if (frame.flags & EFL_IF) {
577: if (!context->IF_flag)
578: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
579:
580: context->IF_flag = TRUE;
581: }
582: else
583: context->IF_flag = FALSE;
584:
585: return (TRUE);
586: }
587:
588: static
589: boolean_t
590: emulate_IRETD(
591: thread_t thread,
592: thread_saved_state_t *state,
593: int offset,
594: struct inst_prefix prefix
595: )
596: {
597: PCcontext_t context;
598: struct {
599: unsigned long eip;
600: sel_t cs;
601: unsigned long eflags;
602: } frame;
603:
604: context = threadPCContext(thread);
605:
606: if (!fetch_segment(
607: thread,
608: state->frame.ss, state->frame.esp,
609: &frame, sizeof (frame)))
610: return (FALSE);
611:
612: state->frame.eip = frame.eip;
613: state->frame.cs = frame.cs;
614:
615: if ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) != 0)
616: frame.eflags |= (state->frame.eflags & EFL_TF);
617: state->frame.eflags = frame.eflags;
618: state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR );
619: state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET );
620:
621: (unsigned short)state->frame.esp += sizeof (frame);
622:
623: context->X_flags = (frame.eflags & (EFL_NT | EFL_IOPL));
624:
625: if (frame.eflags & EFL_IF) {
626: if (!context->IF_flag)
627: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
628:
629: context->IF_flag = TRUE;
630: }
631: else
632: context->IF_flag = FALSE;
633:
634: return (TRUE);
635: }
636:
637: static
638: boolean_t
639: emulate_exception(
640: thread_t thread,
641: thread_saved_state_t *state,
642: int trapno
643: )
644: {
645: PCcontext_t context;
646: struct {
647: unsigned short ip;
648: sel_t cs;
649: unsigned short flags;
650: } frame;
651: struct {
652: unsigned short ip;
653: sel_t cs;
654: } vector;
655:
656: context = threadPCContext(thread);
657:
658: frame.ip = state->frame.eip;
659: frame.cs = state->frame.cs;
660:
661: frame.flags = state->frame.eflags;
662: if (context->IF_flag)
663: frame.flags |= EFL_IF;
664: else
665: frame.flags &= ~EFL_IF;
666:
667: frame.flags |= (context->X_flags & (EFL_NT | EFL_IOPL));
668:
669: if (!store_segment(
670: thread,
671: state->frame.ss, state->frame.esp - sizeof (frame),
672: &frame, sizeof (frame)))
673: return (FALSE);
674:
675: if (!fetch4Byte(thread, (trapno << 2), (unsigned long *)&vector))
676: return (FALSE);
677:
678: (unsigned short)state->frame.esp -= sizeof (frame);
679:
680: state->frame.eip = vector.ip;
681: state->frame.cs = vector.cs;
682:
683: context->IF_flag = FALSE;
684:
685: if ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) == 0)
686: state->frame.eflags &= ~EFL_TF;
687:
688: return (TRUE);
689: }
690:
691: static
692: boolean_t
693: emulate_INTn(
694: thread_t thread,
695: thread_saved_state_t *state,
696: int offset,
697: struct inst_prefix prefix
698: )
699: {
700: PCshared_t shared;
701: PCcontext_t context;
702: unsigned char trapno;
703:
704: shared = threadPCShared(thread);
705: context = currentContext(shared);
706:
707: if (!fetch_segment_byte(
708: thread,
709: state->frame.cs, state->frame.eip + offset + 1,
710: &trapno))
711: return (FALSE);
712:
713: if (maskIsSet(&shared->intNMask, trapno)) {
714: context->trapNum = trapno;
715: context->errCode = 0;
716: if (trapno <= 7)
717: context->callHandler = PC_HANDLE_FAULT;
718: else
719: context->callHandler = PC_HANDLE_INTN;
720:
721: PCcallMonitor(thread, state);
722: /* NOTREACHED */
723: }
724:
725: (unsigned short)state->frame.eip += (offset + 2);
726:
727: if (!emulate_exception(thread, state, trapno)) {
728: (unsigned short)state->frame.eip -= (offset + 2);
729: return (FALSE);
730: }
731:
732: return (TRUE);
733: }
734:
735: static
736: boolean_t
737: handle_exception(
738: thread_t thread,
739: thread_saved_state_t *state
740: )
741: {
742: PCshared_t shared;
743: PCcontext_t context;
744:
745: shared = threadPCShared(thread);
746: context = currentContext(shared);
747:
748: if (maskIsSet(&shared->faultMask, state->trapno)) {
749: context->trapNum = state->trapno;
750: context->errCode = err_to_error_code(state->frame.err);
751: context->callHandler = PC_HANDLE_FAULT;
752:
753: PCcallMonitor(thread, state);
754: /* NOTREACHED */
755: }
756:
757: if (!emulate_exception(thread, state, state->trapno))
758: return (FALSE);
759:
760: return (TRUE);
761: }
762:
763: #define none 0
764: #define STI emulate_STI
765: #define CLI emulate_CLI
766: #define PUSHF emulate_PUSHF
767: #define POPF emulate_POPF
768: #define IRET emulate_IRET
769: #define INTn emulate_INTn
770:
771: static
772: boolean_t (*inst_table[256])() =
773: {
774: /* 90 */ none, /* 91 */ none, /* 92 */ none, /* 93 */ none,
775: /* 94 */ none, /* 95 */ none, /* 96 */ none, /* 97 */ none,
776: /* 98 */ none, /* 99 */ none, /* 9A */ none, /* 9B */ none,
777: /* 9C */PUSHF, /* 9D */ POPF, /* 9E */ none, /* 9F */ none,
778: /* A0 */ none, /* A1 */ none, /* A2 */ none, /* A3 */ none,
779: /* A4 */ none, /* A5 */ none, /* A6 */ none, /* A7 */ none,
780: /* A8 */ none, /* A9 */ none, /* AA */ none, /* AB */ none,
781: /* AC */ none, /* AD */ none, /* AE */ none, /* AF */ none,
782: /* B0 */ none, /* B1 */ none, /* B2 */ none, /* B3 */ none,
783: /* B4 */ none, /* B5 */ none, /* B6 */ none, /* B7 */ none,
784: /* B8 */ none, /* B9 */ none, /* BA */ none, /* BB */ none,
785: /* BC */ none, /* BD */ none, /* BE */ none, /* BF */ none,
786: /* C0 */ none, /* C1 */ none, /* C2 */ none, /* C3 */ none,
787: /* C4 */ none, /* C5 */ none, /* C6 */ none, /* C7 */ none,
788: /* C8 */ none, /* C9 */ none, /* CA */ none, /* CB */ none,
789: /* CC */ none, /* CD */ INTn, /* CE */ none, /* CF */ IRET,
790: /* D0 */ none, /* D1 */ none, /* D2 */ none, /* D3 */ none,
791: /* D4 */ none, /* D5 */ none, /* D6 */ none, /* D7 */ none,
792: /* D8 */ none, /* D9 */ none, /* DA */ none, /* DB */ none,
793: /* DC */ none, /* DD */ none, /* DE */ none, /* DF */ none,
794: /* E0 */ none, /* E1 */ none, /* E2 */ none, /* E3 */ none,
795: /* E4 */ none, /* E5 */ none, /* E6 */ none, /* E7 */ none,
796: /* E8 */ none, /* E9 */ none, /* EA */ none, /* EB */ none,
797: /* EC */ none, /* ED */ none, /* EE */ none, /* EF */ none,
798: /* F0 */ none, /* F1 */ none, /* F2 */ none, /* F3 */ none,
799: /* F4 */ none, /* F5 */ none, /* F6 */ none, /* F7 */ none,
800: /* F8 */ none, /* F9 */ none, /* FA */ CLI, /* FB */ STI,
801: /* FC */ none, /* FD */ none, /* FE */ none, /* FF */ none,
802: };
803:
804: static
805: boolean_t
806: emulate_instruction(
807: thread_t thread,
808: thread_saved_state_t *state
809: )
810: {
811: int offset;
812: unsigned char inst;
813: struct inst_prefix prefix = { 0 };
814: boolean_t (*emul)();
815:
816: return (
817: fetch_inst(thread, state, &offset, &inst, &prefix) &&
818: (emul = inst_table[inst]) != 0 &&
819: (*emul)(thread, state, offset, prefix));
820: }
821:
822: boolean_t
823: PCemulateREAL(
824: thread_t thread,
825: thread_saved_state_t *state
826: )
827: {
828: if (state->trapno == T_GENERAL_PROTECTION) {
829: if (!emulate_instruction(thread,state))
830: return handle_exception(thread, state);
831: else
832: return TRUE;
833: }
834: else
835: if (state->trapno == T_INVALID_OPCODE) {
836: if (!handle_bop(thread, state))
837: return handle_exception(thread, state);
838: else
839: return TRUE;
840: }
841: else
842: return handle_exception(thread, state);
843: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.