text: // Copyright (C) 2003, Matt Conover (mconover@gmail.com)
  #include "cpu.h"
  #include <assert.h>
  
  // NOTE: this assumes default scenarios (i.e., we assume CS/DS/ES/SS and flat
  // and all have a base of 0 and limit of 0xffffffff, we don't try to verify
  // that in the GDT)
  //
  // TODO: use inline assembly to get selector for segment
  // Segment = x86 segment register (SEG_ES = 0, SEG_CS = 1, ...)
  BYTE *GetAbsoluteAddressFromSegment(BYTE Segment, DWORD Offset)
  {
  	switch (Segment)
  	{
  		// Windows uses a flat address space (except FS for x86 and GS for x64)
  		case 0: // SEG_ES
  		case 1: // SEG_CS
  		case 2: // SEG_SS
  		case 3: // SEG_DS
  			return (BYTE *)(DWORD_PTR)Offset;
  		case 4: // SEG_FS
  		case 5: // SEG_GS
  			return (BYTE *)(DWORD_PTR)Offset;
  			// Note: we're really supposed to do this, but get_teb is not implemented
  			// in this bastardized version of the disassembler.
  			// return (BYTE *)get_teb() + Offset;
  		default:
  			assert(0);
  			return (BYTE *)(DWORD_PTR)Offset;
  	}
  }
  
  // This is an GDT/LDT selector (pGDT+Selector)
  BYTE *GetAbsoluteAddressFromSelector(WORD Selector, DWORD Offset)
  {
  	DESCRIPTOR_ENTRY Entry;
  	GATE_ENTRY *Gate;
  	ULONG_PTR Base;
  	
  	assert(Selector < 0x10000);
  	if (!GetThreadSelectorEntry(GetCurrentThread(), Selector, (LDT_ENTRY *)&Entry)) return NULL;
  	if (!Entry.Present) return NULL;
  	if (Entry.System)
  	{
  		Base = 0;
  #ifdef _WIN64
  		Base = (ULONG_PTR)Entry.HighOffset64;
  		Base <<= 32;
  #endif
  		Base |= (size_t)Entry.BaseHi << 24;
  		Base |= (size_t)Entry.BaseMid << 16;
  		Base |= Entry.BaseLow;
  	}
  	else
  	{
  		switch (Entry.Type)
  		{
  			case 1: // 16-bit TSS (available)
  			case 2: // LDT
  			case 3: // 16-bit TSS (busy)
  			case 9: // 32-bit TSS (available)
  			case 11: // 32-bit TSS (busy)
  				Base = 0;
  #ifdef _WIN64
  				Base = (ULONG_PTR)Entry.HighOffset64;
  				Base <<= 32;
  #endif
  				Base |= (size_t)Entry.BaseHi << 24;
  				Base |= (size_t)Entry.BaseMid << 16;
  				Base |= Entry.BaseLow;
  				break;
  
  			case 4: // 16-bit call gate
  			case 5: // task gate
  			case 6: // 16-bit interrupt gate
  			case 7: // 16-bit task gate
  			case 12: // 32-bit call gate
  			case 14: // 32-bit interrupt gate
  			case 15: // 32-bit trap gate
  				Gate = (GATE_ENTRY *)&Entry;
  #ifdef _WIN64
  				Base = (ULONG_PTR)Gate->HighOffset64;
  				Base <<= 32;
  				Base |= (Gate->HighOffset << 16) | Gate->LowOffset;
  #else
  				Base = (Gate->HighOffset << 16) | Gate->LowOffset;
  #endif
  				assert(!Offset); Offset = 0;
  				break;
  			default:
  				assert(0);
  				return NULL;
  		}
  	}
  	return (BYTE *)Base + Offset;
  }
  
  