Log in

View Full Version : INT1 question


0rp
December 22nd, 2004, 22:15
hi,

is there a programmatically detectable difference between an INT1 that is caused by an enabled trap flag in the EFlags reg and an INT1 that is caused by an "INT 1" instruction ?

thx

FrankRizzo
December 23rd, 2004, 01:34
not that I recall, I reversed "CopyLock" a LONG time ago, and it made extensive use of INTs 1 & 3. IIRC, they both just call the INT 1 int. vector, so there should be NO difference. (Unless the INT 1 handler checked the flags to see).

bilbo
December 23rd, 2004, 06:06
Hi Orp,

one macroscopic difference is that, if you are in USER MODE (RING 3) an "INT 1" instruction generates an access violation exception, not a single step exception.

In all cases (RING 0 or RING 3), your handler can always peek at the opcode which generated the exception.

On the other hand, it is useless for the exception handler to look at the EFLAGS, as FrankRizzo suggested, because the Trace Flag is automatically reset by the hardware as soon as the exception is generated.

Have a look at the following VisualC snippet:
Code:

#include <windows.h>
#include <stdio.h>

//#define INT_1

void
main(void)
{
LPEXCEPTION_POINTERS pep = 0;

__try {
#ifdef INT_1
__asm int 1;
#else
__asm {
pushfd
or dword ptr [esp], 0x100
popfd
nop
nop // <-- exception here
}
#endif
}
// copy the pointers to "pep" be accessed by the handler later
__except (pep=GetExceptionInformation(), EXCEPTION_EXECUTE_HANDLER) {
printf("%x EIP=%x TRACEFLAG=%x opcode=%x\n",
pep->ExceptionRecord->ExceptionCode,
pep->ExceptionRecord->ExceptionAddress,
pep->ContextRecord->EFlags & 0x100,
*(LPBYTE)pep->ExceptionRecord->ExceptionAddress);
exit(0);
}
}


If you compile the code with INT_1 defined, you will see the output
Quote:

c0000005 EIP=401034 TRACEFLAG=0 opcode=cd

C0000005 is the code for STATUS_ACCESS_VIOLATION, CD is the opcode for "int N"

If you compile the code with INT_1 not defined, you will see the output
Quote:

80000004 EIP=40103e TRACEFLAG=0 opcode=90

80000004 is the code for STATUS_SINGLE_STEP, 90 is the opcode for "nop"

Regards, bilbo

user
December 23rd, 2004, 07:40
There are actually a few differences :

- Considering u use INT1 aka ICEBP (0xF1), the trap flag is set immediatly on next opcode versus what happens with playing with TF (i.e. one opcode latency).
- If you use INT 1 (0xCD 0x01), the result won't be what u think and may lead to bilbo's note.

Please note as well that the CPU may induce a slightly different behaviour:

- An AMD K6 will not like ICEBP as is, it will trigger a fault (that's a bug). One need to adjust the DPL for it to work as expected.
- There are probably some other flavour behaving differently but I don't remember them.

Some drivers may alter functionnality too :

- DbgMsg.vxd on 98SE will trash the result and induce infinite loops and what not. Their handler interferes and do not pass back the correct information to real handler.

Generally speaking using INT1 is a bad idea if u don't make sure about the behaviour, i.e. install your own handler.

That should clarify things, I hope.

omega_red
December 23rd, 2004, 07:58
INT1 (0xf1) opcode is NOT DEFINED in Intel's IA-32 architecture manuals. By using it, you are relying on undocumented CPU behaviour.

user
December 23rd, 2004, 10:57
That point is innacurate, you can find definition in previous incarnation of the manual: the current table has an empty entry, which is strange you will admit, they just do not advertise about it anymore. If you check AMD ref, it is defined there... even in the x86-64 flavour.

Nevertheless, since every INTEL cpu have a consistant and exact execution of that so-called "undocumented" instruction (well since recently), and that the only issues highlighted were from other vendors WHICH documents it and where it was inconsistant with their own definitions, it's difficult to agree with you. The initial question being about differences between int1 and setting EFlags.TF=1, this has to be mentioned.

This being said I'd not advocate to use this particular instruction, not because I know of some silicon mistakes on some now defunct CPU, but, more importantly, because of some potential software interference. But we are now far from the initial subject of this thread.

Japheth
December 23rd, 2004, 13:16
> one macroscopic difference is that, if you are in USER MODE
> (RING 3) an "INT 1" instruction generates an access
> violation exception, not a single step exception.

An access violation will only occur - in protected mode, not vm86 - if the trap/interrupt gate selector in IDT for int 1 isn't a "ring 3" selector.

FrankRizzo
December 23rd, 2004, 14:24
Just for the record, I was talking about old DOS days, I didn't consider the current "All protected mode all the time" scenario. My bad!