home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / GDT.ZIP / GDT.C < prev    next >
C/C++ Source or Header  |  1989-01-08  |  30KB  |  922 lines

  1. /* gdt.c -- walks through Global Descriptor Table */
  2. /* (c) Andrew Schulman December 1988 */
  3. /* revised 17-December-1988 */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <setjmp.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #define INCL_DOS
  11. #define INCL_DOSDEVICES
  12. #define INCL_DOSSIGNALS
  13. #include "os2.h"
  14. #include "devhlp.h"
  15.  
  16. typedef char far *FP;
  17.  
  18. #define FP_SEG(p)       HIUSHORT(p)
  19. #define FP_OFF(p)       LOUSHORT(p)
  20. #define MK_FP(seg,off)  ((FP)(((ULONG)(seg) << 16) | (off)))
  21.  
  22. #define RING_3_ALIAS(seg0)  ((seg0) + 3)
  23.  
  24. #define REC_TO_SEG(r)       ((r) << 3)
  25. #define SEG_TO_REC(s)       ((s) >> 3)
  26. #define LDT_REC_TO_SEG(s)   (RING_3_ALIAS(REC_TO_SEG(s)))
  27. /* replace above with: */
  28. typedef struct {
  29.     USHORT rpl : 2;
  30.     USHORT table : 1;
  31.     USHORT index : 15;
  32.     } SEG;
  33. /* replace most uses of USHORT with SEG */
  34. /* perhaps use enums also!! */
  35. /* most of program should consist of data structures */
  36.     
  37. /* again, use SEG type instead of macro ! */
  38. #define IGNORE_RPL(seg)     ((seg) >> 2)
  39.  
  40. /* program should be redone, dispatching on type of seg.  for each seg
  41. type, should be a describe() function and a show() function */
  42.  
  43. #define NULLPTR         ((FP) 0)
  44. #define REG             /*register*/
  45.  
  46. /* types of gates */
  47. #define TSS                     1
  48. #define LDT                     2
  49. #define BUSY_TSS                3
  50. #define CALL_GATE               4
  51. #define TASK_GATE               5
  52. #define INTERRUPT_GATE          6
  53. #define TRAP_GATE               7
  54.  
  55. #pragma pack(1)
  56.  
  57. /* contents of 6-byte structure filled in by SGDT instruction */
  58. typedef struct {
  59.     USHORT limit;
  60.     USHORT base_lo;
  61.     BYTE base_hi;
  62.     BYTE reserved;
  63.     } GDT;
  64.     
  65. typedef GDT IDT;    /* IDTR is same as GDTR */
  66.  
  67. /* "nonstandard extension: bitfield other than int" */  
  68. typedef union {
  69.     BYTE a;
  70.     struct {
  71.         BYTE type : 4;
  72.         BYTE segment : 1;
  73.         BYTE dpl : 2;
  74.         BYTE present : 1;
  75.         } b;
  76.     struct {
  77.         BYTE accessed : 1;
  78.         BYTE read_write : 1;
  79.         BYTE conform_expand : 1;
  80.         BYTE code_data : 1;
  81.         BYTE segment : 1;
  82.         BYTE dpl : 2;
  83.         BYTE present : 1;
  84.         } c;
  85.     } LAR;
  86.     
  87. #define LAR_FM_USHORT(u)        (*((LAR *) &(u)))
  88.     
  89. typedef struct {
  90.     USHORT limit;
  91.     USHORT base_lo;
  92.     BYTE base_hi;
  93.     LAR lar;
  94.     USHORT reserved;
  95.     } DESCRIPTOR;
  96.     
  97. #define ISGATE(seglar)  ((seglar).b.segment == 0)
  98. #define ISCODE(seglar)  ((seglar).c.code_data == 1)
  99. #define ISREAD(seglar)  (ISCODE(seglar) && ((seglar).c.read_write == 1))
  100. #define ISWRITE(seglar) (! ISCODE(seglar) && ((seglar).c.read_write == 1))
  101.  
  102. #define GATE_TYPE(seglar)   ((seglar).b.type)
  103.  
  104. #define ISBIMODAL(seg, phys)    ((phys) == 0x10 * (seg))
  105.  
  106. extern void far gdt(GDT far *gdt);
  107. extern void far idt(IDT far *idt);
  108. extern USHORT far ldt(void);
  109. extern USHORT far lsl(USHORT seg);
  110. extern USHORT far lar(USHORT seg);
  111. extern BOOL far verr(USHORT seg);
  112. extern BOOL far verw(USHORT seg);
  113. /* extern void Debugger(void); */
  114.  
  115. int fail(char *msg);
  116. void walk_dt(DESCRIPTOR far *desc, void (*f)());
  117. void walk(FP base, USHORT start, USHORT stop);
  118. void walk_ldt(FP base, USHORT start, USHORT stop);
  119. void walk_idt(void);
  120. void describe(FP base, USHORT rec, BOOL show_empties, USHORT care_lar,
  121.     BOOL is_ldt);
  122. void show_seg(USHORT rec);
  123. void peek(BYTE hi, USHORT lo, USHORT limit);
  124. void unassemble_uvirt(FP base, USHORT seg, USHORT off);
  125. void unassemble_phys(BYTE hi, USHORT lo, USHORT limit, USHORT off);
  126. void dump(BYTE hi, USHORT lo, FP fp, USHORT size);
  127. void search(FP base, USHORT lar);
  128. char *name(USHORT type);
  129. char *get_doscall_name(USHORT seg);
  130. USHORT hatoi(char *);
  131. void help(void);
  132. void init(void);
  133. void init_doscalls(void);
  134. void far pascal break_handler(USHORT sig_num, USHORT sig_arg);
  135. void breakpoint(void);
  136.  
  137. FP PhysToUVirt(USHORT hi, USHORT lo, USHORT limit, BYTE type);
  138. BOOL ReleaseUVirt(FP fp);
  139.  
  140. static char *PHYSTOUVIRT_FAIL = "PhysTOUVirt fails!";
  141. static char *RELEASEUVIRT_FAIL = "ReleaseUVirt fails!";
  142. static char *SOMETHING_WRONG = "Something wrong!  Is this 386 OS/2?";
  143. static char *DESCRIPTOR_MASK =
  144.     "[seg %04X] %02X%04X <limit %05u> <lar %02X> [%s]\n";
  145. static char *env_str = "GDTCODESEG";
  146. static char *my_ldt = "** MY LOCAL DESCRIPTOR TABLE **\n";
  147. static char *gdt_at_msg = "GDT at %02X%04X <limit %05u> <%u entries>\n";
  148.  
  149. static char *GATE_NAMES[] = {
  150.     "Invalid gate", "TSS gate", "LDT", "Busy TSS gate", "Call gate",
  151.     "Task gate", "Interrupt gate", "Trap gate", "Reserved gate",
  152.     "Reserved gate", "Reserved gate", "Reserved gate", "Reserved gate",
  153.     "Reserved gate", "Reserved gate", "Reserved gate" };
  154.  
  155. static GDT g;
  156. static DESCRIPTOR far *gdt_ptr;
  157. static USHORT devhlp;
  158. static USHORT entries;
  159. static jmp_buf toplevel;
  160. static FP uvirt_p = NULLPTR;
  161. static USHORT radix = 16;
  162.  
  163. static char *gdt_exe;
  164.  
  165. int main(int argc, char *argv[])
  166. {
  167.     char buf[128], *p = buf;
  168.     USHORT action = 0;
  169.  
  170.     /* second copy of GDT.EXE, runs under CodeView */
  171.     if (! strcmp("CVP", getenv("GDTEXE")))
  172.     {
  173.         USHORT seg = atoi(getenv(env_str));
  174.         if (! seg)
  175.             printf("Error:  SET GDTEXE= and retry\n");
  176.         DosGetSeg(seg);
  177.         breakpoint();
  178.         DosFreeSeg(seg);
  179.         return 0;
  180.     }
  181.     
  182.     gdt_exe = argv[0];
  183.     
  184.     gdt(&g);
  185.     
  186.     entries = g.limit / sizeof(DESCRIPTOR);
  187.     printf(gdt_at_msg, g.base_hi, g.base_lo, g.limit, entries);
  188.     if (g.reserved != 0)
  189.         puts(SOMETHING_WRONG);
  190.     
  191.     /* open up DEVHLP device */
  192.     if (DosOpen("DEVHLPXX", &devhlp, &action, 0, 0, 1, 0x40, 0))
  193.         return fail("Can't find DEVHLP.SYS");
  194.  
  195.     gdt_ptr =
  196.         (DESCRIPTOR far *) PhysToUVirt(g.base_hi, g.base_lo, g.limit,
  197.             UVirt_ReadWrite);
  198.     if (! gdt_ptr)
  199.         return fail(PHYSTOUVIRT_FAIL);
  200.     
  201.     /* must be a 386 version of OS/2!! */
  202.     if (FP_OFF(gdt_ptr) != 0)
  203.         return fail(SOMETHING_WRONG);
  204.  
  205.     init();
  206.     init_doscalls();
  207.  
  208.     puts("Type H for help");
  209.     
  210.     if (setjmp(toplevel))
  211.         printf("\n[back to toplevel]\n");
  212.         
  213.     for (;;)
  214.     {
  215.         printf("$ ");
  216.         gets(buf);
  217.  
  218.         switch (toupper(*p))
  219.         {
  220.             case '!':
  221.                 system(p+2); break;
  222.             case '?':
  223.                 show_seg(SEG_TO_REC(hatoi(p+2))); break;
  224.             case '.':
  225.                 describe(gdt_ptr, SEG_TO_REC(hatoi(p+2)), TRUE, -1, FALSE);
  226.                 break;
  227.             case 'H':
  228.                 help(); break;
  229.             case 'I':
  230.                 walk_idt(); break;
  231.             case 'L':
  232.                 {
  233.                     /* walk through seg as if an LDT */
  234.                     USHORT rec = SEG_TO_REC(hatoi(p+2));
  235.                     DESCRIPTOR far *desc = gdt_ptr + rec;
  236.                     if ((desc->limit + 1) % 8)
  237.                         printf("Definitely not an LDT\n");
  238.                     else
  239.                     {
  240.                         if (REC_TO_SEG(rec) == ldt())
  241.                             printf(my_ldt);
  242.                         walk_dt(desc, walk_ldt);
  243.                     }
  244.                     break;
  245.                 }
  246.             case 'P':
  247.                 {
  248.                     USHORT hi = hatoi(strtok(p+2," "));
  249.                     USHORT lo = hatoi(strtok(0," "));
  250.                     USHORT limit = hatoi(strtok(0," "));
  251.                     peek(hi,lo,limit);
  252.                     break;
  253.                 }
  254.             case 'R':
  255.                 radix = atoi(p+2); 
  256.                 if (radix != 10 || radix != 16)
  257.                     radix = 16;
  258.                 break;
  259.             case 'S':
  260.                 search(gdt_ptr, hatoi(p+2)); break;
  261.             case 'U':
  262.                 {
  263.                     /* unassemble:  similar to peek */
  264.                     USHORT seg = hatoi(strtok(p+2,": "));
  265.                     USHORT off = hatoi(strtok(0," "));
  266.                     unassemble_uvirt(gdt_ptr,seg,off);
  267.                     break;
  268.                 }
  269.             case 'W':
  270.                 printf(gdt_at_msg, g.base_hi, g.base_lo, g.limit, entries);
  271.                 if (strlen(p) > 3)
  272.                 {
  273.                     USHORT start = SEG_TO_REC(hatoi(strtok(p+2," ")));
  274.                     USHORT stop = SEG_TO_REC(hatoi(strtok(0, " ")));
  275.                     walk(gdt_ptr, start, stop);
  276.                 }
  277.                 else
  278.                     walk(gdt_ptr, 0, entries);
  279.                 break;
  280.             case 'X':
  281.             case 'Q':               
  282.                 return (ReleaseUVirt(gdt_ptr)) ? 0 : fail(RELEASEUVIRT_FAIL);
  283.                 break;
  284.         }
  285.     }
  286. }
  287.  
  288. /* turn physical address into virtual address */
  289. FP PhysToUVirt(USHORT hi, USHORT lo, USHORT limit, BYTE type)
  290. {
  291.     REGS regs;
  292.     USHORT ret;
  293.     regs.ax = hi;
  294.     regs.bx = lo;
  295.     regs.cx = limit;
  296.     regs.di = 0;
  297.     regs.dx = MAKEUSHORT(DevHlp_PhysToUVirt, type);
  298.     ret = DosDevIOCtl(®s, ®s, 0x60, 128, devhlp);
  299.     return (ret || regs.flags.carry) ? NULLPTR :
  300.         MK_FP(regs.es, regs.bx);
  301. }
  302.     
  303. /* dispose of the virtual address */
  304. BOOL ReleaseUVirt(FP fp)
  305. {
  306.     REGS regs;
  307.     USHORT ret;
  308.     regs.ax = FP_SEG(fp);
  309.     regs.bx = 0;
  310.     regs.cx = 0;
  311.     regs.di = 0;
  312.     regs.dx = MAKEUSHORT(DevHlp_PhysToUVirt, 2);    /* free */
  313.     ret = DosDevIOCtl(®s, ®s, 0x60, 128, devhlp);
  314.     return (! (ret || regs.flags.carry));
  315. }
  316.  
  317. int fail(char *msg)
  318. {
  319.     puts(msg);
  320.     return 1;
  321. }
  322.  
  323. void describe(FP base, USHORT rec, BOOL show_empties, USHORT care_lar,
  324.     BOOL is_ldt)
  325. {
  326.     DESCRIPTOR far *p = ((DESCRIPTOR far *) base) + rec;
  327.     if (rec && ! show_empties && (! p->limit || ! p->lar.a))
  328.         return;
  329.     if (care_lar != -1 && (care_lar != p->lar.a))
  330.         return;
  331.     if (ISGATE(p->lar))
  332.     {
  333.         switch (GATE_TYPE(p->lar))
  334.         {
  335.             case CALL_GATE:
  336.             {
  337.                 DESCRIPTOR far *p2;
  338.                 char *name;
  339.                 /* temp here -- should be separate function for each seg type:
  340.                 create dispatch type and dispatch on type! */
  341.                 /* actually, need two tables: one for describe_ functions, the
  342.                     other for show_ functions */
  343.                 /* Morse, 286, p.163 */
  344.                 printf("<Call gate %04X:0000> ", REC_TO_SEG(rec));
  345.                 /* need another union -- for call gate, byte is word count,
  346.                     _not_ base_hi; next word is destination _selector_, _not_
  347.                     base_lo; next word is destination offset, not limit! */
  348.                 printf("<code %04X:%04X> ", p->base_lo, p->limit);
  349.  
  350.                 p2 = ((DESCRIPTOR far *) base) + SEG_TO_REC(p->base_lo);
  351.                 printf("<phys %02X%04X> ",
  352.                     p2->base_hi, p2->base_lo + p->limit);
  353.  
  354.                 name = get_doscall_name(REC_TO_SEG(rec));
  355.                 /* see if its a special name, not DOSxxxxx */
  356.                 if (name && *name =='*')
  357.                     printf("%s ", name+1);
  358.                 else if (name)
  359.                     printf("DOS%s ", name);
  360.                 else
  361.                     printf("??? ");
  362.  
  363.                 printf("(%u wds)\n", p->base_hi); /* words expects as args */
  364.             }
  365.                 break;
  366.             case TRAP_GATE:
  367.             case INTERRUPT_GATE:
  368.                 printf("[seg %04X] %04X:%04X <lar %02X> [%s]\n",
  369.                     (is_ldt) ? LDT_REC_TO_SEG(rec) : REC_TO_SEG(rec),
  370.                     p->base_lo, p->limit,
  371.                     p->lar.a, name(p->lar.a));
  372.                 break;
  373.             default:
  374.                 goto deflt;
  375.         }
  376.     }
  377.     else 
  378.     {
  379. deflt:  
  380.         printf(DESCRIPTOR_MASK,
  381.             (is_ldt) ? LDT_REC_TO_SEG(rec) : REC_TO_SEG(rec),
  382.             p->base_hi, p->base_lo,
  383.             p->limit,
  384.             p->lar.a,
  385.             name(p->lar.a)
  386.             );
  387.     }
  388. }
  389.  
  390. /* step through a Descriptor Table */
  391. void walk(FP base, USHORT start, USHORT stop)
  392. {
  393.     REG USHORT i;
  394.     for (i=start; i<entries && i<=stop; i++)
  395.         describe(base, i, FALSE, -1, FALSE);
  396. }
  397.  
  398. /* step through a Local Descriptor Table */
  399. void walk_ldt(FP base, USHORT start, USHORT stop)
  400. {
  401.     REG USHORT i;
  402.     for (i=start; i<entries && i<=stop; i++)
  403.         describe(base, i, FALSE, -1, TRUE);
  404. }
  405.  
  406. /* step through a Descriptor Table */
  407. void search(FP base, USHORT lar)
  408. {
  409.     REG USHORT i;
  410.     for (i=0; i<entries; i++)
  411.         describe(base, i, FALSE, lar, FALSE);
  412. }
  413.  
  414. void peek(BYTE hi, USHORT lo, USHORT limit)
  415. {
  416.     FP fp = PhysToUVirt(hi, lo, limit, UVirt_ReadWrite);
  417.     uvirt_p = fp;
  418.     if (fp)
  419.         dump(hi, lo, fp, limit);
  420.     if (! ReleaseUVirt(fp))
  421.         puts(RELEASEUVIRT_FAIL);
  422.     uvirt_p = NULLPTR; 
  423. }
  424.  
  425. void unassemble_uvirt(FP base, USHORT seg, USHORT off)
  426. {
  427.     DESCRIPTOR far *p = ((DESCRIPTOR far *) base) + SEG_TO_REC(seg);
  428.     unassemble_phys(p->base_hi, p->base_lo, p->limit, off);
  429. }
  430.  
  431. void unassemble_phys(BYTE hi, USHORT lo, USHORT limit, USHORT off)
  432. {
  433.     char cmd[128];
  434.     char env[128];
  435.     FP fp;
  436.     USHORT sel;
  437.     
  438.     if (! (fp = PhysToUVirt(hi, lo, limit, UVirt_Exec)))
  439.         return;
  440.  
  441.     DosAllocSeg(limit, &sel, SEG_GETTABLE);
  442.     movedata(FP_SEG(fp),FP_OFF(fp),sel,0,limit);
  443.     
  444.     uvirt_p = fp;
  445.     
  446.     /* get CodeView to do our disassembling for us -- run in 
  447.         sequential mode (/T), with startup commands (/C).  
  448.         NOTE!  CVP U does not require exec seg, but seg must
  449.         be mapped into debugee's address space! Our second copy
  450.         of gdt.exe has to get it, then we have to set breakpoint
  451.         ourselves, then CVP runs some more commands we've put
  452.         on the command line: set radix to 16, set cs, unassemble */
  453.  
  454.     putenv("GDTEXE=CVP");
  455.     sprintf(env, "%s=%u", env_str, sel);
  456.     putenv(env);
  457.  
  458.     sprintf(cmd, "CVP /T /C\"n16;bp %x;g;r cs %x;u %x\" %s",
  459.         (void near *) breakpoint, sel, off, gdt_exe);
  460.     printf("EXEC: %s\n", cmd);
  461.     system(cmd);
  462.     
  463.     sprintf(env,"%s=",env_str); putenv(env);
  464.     putenv("GDTEXE=");
  465.  
  466.     DosFreeSeg(sel);
  467.     if (! ReleaseUVirt(fp))
  468.         puts(RELEASEUVIRT_FAIL);
  469.     uvirt_p = NULLPTR; 
  470. }
  471.  
  472. void show_seg(USHORT rec)
  473. {
  474.     DESCRIPTOR far *desc = gdt_ptr + rec;
  475.     FP p = PhysToUVirt(desc->base_hi, desc->base_lo, desc->limit,
  476.         UVirt_ReadWrite);
  477.     uvirt_p = p;
  478.     if (p)
  479.     {
  480.         printf(DESCRIPTOR_MASK, REC_TO_SEG(rec),
  481.             desc->base_hi, desc->base_lo, desc->limit, desc->lar.a,
  482.                 name(desc->lar.a));
  483.         
  484.         if (ISGATE(desc->lar))
  485.         {
  486.             /* have to do something special for Call gate!:  limit is
  487.             actually offset */
  488.  
  489.             switch (GATE_TYPE(desc->lar))
  490.             {
  491.                 case LDT:
  492.                     /* why is only one LDT showing up???? */
  493.                     if (REC_TO_SEG(rec) == ldt())
  494.                         printf(my_ldt);
  495.                     walk_ldt(p, 0, desc->limit / sizeof(DESCRIPTOR));
  496.                     break;
  497.                 default:
  498.                     dump(desc->base_hi, desc->base_lo, p, desc->limit);
  499.             }
  500.         }
  501.         else
  502.         {
  503.             dump(desc->base_hi, desc->base_lo, p, desc->limit);
  504.         }
  505.         
  506.         if (! ReleaseUVirt(p))
  507.             puts(RELEASEUVIRT_FAIL);
  508.         uvirt_p = NULLPTR;
  509.     }
  510.     else
  511.         puts(PHYSTOUVIRT_FAIL);
  512. }
  513.  
  514. #define WIDTH           16
  515. #define WIDTH_SHIFT     4
  516.  
  517. void dump(BYTE hi, USHORT lo, FP fp, USHORT size)
  518. {
  519.     BYTE far *p;
  520.     USHORT blocks = size / WIDTH;
  521.     USHORT slop = size % WIDTH;
  522.     REG USHORT i;
  523.     REG USHORT j;
  524.     
  525.     for (i=0; i<blocks; i++, fp += WIDTH)
  526.     {
  527.         printf("%02X%04X  ", hi, lo + (i << WIDTH_SHIFT));
  528.         for (j=0, p=fp; j<WIDTH; j++, p++)
  529.             printf("%02X ", *p);
  530.         putchar(' '); putchar(' '); putchar(' ');
  531.         for (j=0, p=fp; j<WIDTH; j++, p++)
  532.             putchar(isalpha(*p) ? *p : '.');
  533.         putchar('\n');
  534.     }
  535.     if (slop)
  536.     {
  537.         printf("%02X%04X  ", hi, lo + (i << WIDTH_SHIFT));
  538.         for (j=0, p=fp; j<WIDTH; j++, p++)
  539.             if (j<slop) printf("%02X ", *p);
  540.             else printf("   ");
  541.         putchar(' '); putchar(' '); putchar(' ');
  542.         for (j=0, p=fp; j<slop; j++, p++)
  543.             putchar(isalpha(*p) ? *p : '.');
  544.         putchar('\n');
  545.     }
  546. }
  547.  
  548. char *name(LAR lar)
  549. {
  550.     if (ISGATE(lar))
  551.         return GATE_NAMES[GATE_TYPE(lar)];
  552.     else if (ISCODE(lar))
  553.         return (ISREAD(lar)) ? "Readable code" : "Execute-only code";
  554.     else
  555.         return (ISWRITE(lar)) ? "Writable data" : "Read-only data";
  556. }
  557.  
  558. void far pascal break_handler(USHORT sig_num, USHORT sig_arg)
  559. {
  560.     /* have to acknowledge the signal first */
  561.     ULONG prevaddr;
  562.     USHORT prevact;
  563.     DosSetSigHandler(0L, &prevaddr, &prevact, 4, 1);        /* ack */
  564.  
  565.     if (uvirt_p) 
  566.     {
  567.         ReleaseUVirt(uvirt_p);
  568.         uvirt_p = NULLPTR;
  569.     }
  570.  
  571.     longjmp(toplevel, -1);
  572. }
  573.  
  574. void init(void)
  575. {
  576.     USHORT handtype, devattr;
  577.     
  578.     /* make sure stdin is KBD and stdout is VIO */
  579.     DosQHandType(0, &handtype, &devattr);
  580.     if (handtype == 1)
  581.         DosQHandType(1, &handtype, &devattr);
  582.     if (handtype == 1)
  583.     {
  584.         ULONG prevaddr;
  585.         USHORT prevact;
  586.         DosSetSigHandler(break_handler, &prevaddr, &prevact, 2, 1);  /* ^C */
  587.         DosSetSigHandler(0L, &prevaddr, &prevact, 1, 3); /* ignore TERM */
  588.         DosSetSigHandler(0L, &prevaddr, &prevact, 1, 4); /* ignore ^break */
  589.     }
  590. }
  591.  
  592. static char *helpmsg[] = {
  593. "GDT.EXE walks through the protected-mode Global Descriptor Table",
  594. "used by OS/2.  It uses the SGDT instruction to get the 24-bit",
  595. "physical base address of the GDT, and the PhysToUVirt DevHlp,",
  596. "made available by DEVHLP.SYS, to turn the physical address into",
  597. "a virtual selector:offset address that can be used by a normal",
  598. "Ring 3 app like GDT.EXE.",
  599. "Commands:",
  600. "\tW [start] [stop] -- walk Global Descriptor Table",
  601. "\tL <seg> -- walk seg as if an LDT \(maybe it is\)",
  602. "\tI -- walk Interrupt Descriptor Table",
  603. "\tQ or X -- exit back to OS/2",
  604. "\tS <lar> -- search for segments with designated access rights",
  605. "\tU <seg:off> -- run CVP to unassemble code",
  606. "\tP <hi> <lo> <limit> -- peek at arbitrary address",
  607. "\t. <seg> -- displays one segment description from the GDT",
  608. "\t? <seg> -- hexdump of segment referenced in GDT",
  609. "\t! <cmdstr> -- runs an external program or OS/2 command",
  610. "Examples:",
  611. "\tw\t\t\t; display the entire GDT",
  612. "\tw 90 100\t\t; focus on portion of GDT",
  613. "\ts F1\t\t\t; find all segments with LAR 0xF1",
  614. "\t. 60\t\t\t; display info on segment 0x60",
  615. "\t? 60\t\t\t; hexdump of segment 0x60",
  616. "\tu b0:adfc\t\t\; unassemble code at 00B0:ADFC",
  617. ""
  618.     } ;
  619.  
  620. void help(void)
  621. {
  622.     char **p = helpmsg;
  623.     while (**p)
  624.     {
  625.         puts(*p);
  626.         p++;
  627.     }
  628. }
  629.  
  630. USHORT hatoi(char *s)
  631. {
  632.     USHORT i = 0, t;
  633.     
  634.     if (radix == 10) return atoi(s);
  635.  
  636.     while (*s == ' ' || *s == '\t')
  637.         s++;
  638.     while (1)
  639.     {
  640.         char c = *s;
  641.         if      (c >= '0' && c <= '9') t = 48;
  642.         else if (c >= 'A' && c <= 'F') t = 55;
  643.         else if (c >= 'a' && c <= 'f') t = 87;
  644.         else break;
  645.         i = (i << 4) + (c - t);
  646.         s++;
  647.     }
  648.     return i;
  649. }
  650.  
  651. /**********************************************************************/
  652. #define NUM_DOSCALLS    111
  653.     
  654. extern USHORT far pascal DOSPTRACE();
  655. extern USHORT far pascal DOSSGSWITCH();
  656. extern USHORT far pascal DOSSGSWITCHME();
  657. extern USHORT far pascal DOSSYSTRACE();
  658.  
  659. typedef struct {
  660.     char *name;
  661.     ULONG procaddr;     /* USHORT (far pascal *procaddr)(); */
  662.     } DOSCALLS;
  663.     
  664. static DOSCALLS dosfuncs[NUM_DOSCALLS] = {
  665.     "ALLOCHUGE",        (ULONG) DosAllocHuge,
  666.     "ALLOCSEG",         (ULONG) DosAllocSeg,
  667.     "ALLOCSHRSEG",      (ULONG) DosAllocShrSeg,
  668.     "BEEP",             (ULONG) DosBeep,
  669.     "BUFRESET",         (ULONG) DosBufReset,
  670.     "CHDIR",            (ULONG) DosChdir,
  671.     "CHGFILEPTR",       (ULONG) DosChgFilePtr,
  672.     "CLIACCESS",        (ULONG) DosCLIAccess,
  673.     "CLOSE",            (ULONG) DosClose,
  674.     "CLOSESEM",         (ULONG) DosCloseSem,
  675.     "CREATECSALIAS",    (ULONG) DosCreateCSAlias,
  676.     "CREATESEM",        (ULONG) DosCreateSem,
  677.     "CREATETHREAD",     (ULONG) DosCreateThread,
  678.     "CWAIT",            (ULONG) DosCWait,
  679.     "DELETE",           (ULONG) DosDelete,
  680.     "DEVCONFIG",        (ULONG) DosDevConfig,
  681.     "DEVIOCTL",         (ULONG) DosDevIOCtl,
  682.     "DUPHANDLE",        (ULONG) DosDupHandle,
  683.     "ENTERCRITSEC",     (ULONG) DosEnterCritSec,
  684.     "ERRCLASS",         (ULONG) DosErrClass,
  685.     "ERROR",            (ULONG) DosError,
  686.     "EXECPGM",          (ULONG) DosExecPgm,
  687.     "EXIT",             (ULONG) DosExit,
  688.     "EXITCRITSEC",      (ULONG) DosExitCritSec,
  689.     "EXITLIST",         (ULONG) DosExitList,
  690.     "FILELOCKS",        (ULONG) DosFileLocks,
  691.     "FINDCLOSE",        (ULONG) DosFindClose,
  692.     "FINDFIRST",        (ULONG) DosFindFirst,
  693.     "FINDNEXT",         (ULONG) DosFindNext,
  694.     "FLAGPROCESS",      (ULONG) DosFlagProcess,
  695.     "FREEMODULE",       (ULONG) DosFreeModule,
  696.     "FREESEG",          (ULONG) DosFreeSeg,
  697.     "GETCP",            (ULONG) DosGetCp,
  698.     "GETDATETIME",      (ULONG) DosGetDateTime,
  699.     "GETENV",           (ULONG) DosGetEnv,
  700.     "GETHUGESHIFT",     (ULONG) DosGetHugeShift,
  701.     "GETINFOSEG",       (ULONG) DosGetInfoSeg,
  702.     "GETMACHINEMODE",   (ULONG) DosGetMachineMode,
  703.     "GETMODHANDLE",     (ULONG) DosGetModHandle,
  704.     "GETMODNAME",       (ULONG) DosGetModName,
  705.     "GETPID",           (ULONG) DosGetPid,
  706.     "GETPROCADDR",      (ULONG) DosGetProcAddr,
  707.     "GETPRTY",          (ULONG) DosGetPrty,
  708.     "GETSEG",           (ULONG) DosGetSeg,
  709.     "GETSHRSEG",        (ULONG) DosGetShrSeg,
  710.     "GETVERSION",       (ULONG) DosGetVersion,
  711.     "GIVESEG",          (ULONG) DosGiveSeg,
  712.     "HOLDSIGNAL",       (ULONG) DosHoldSignal,
  713.     "KILLPROCESS",      (ULONG) DosKillProcess,
  714.     "LOADMODULE",       (ULONG) DosLoadModule,
  715.     "LOCKSEG",          (ULONG) DosLockSeg,
  716.     "MAKEPIPE",         (ULONG) DosMakePipe,
  717.     "MEMAVAIL",         (ULONG) DosMemAvail,
  718.     "MKDIR",            (ULONG) DosMkdir,
  719.     "MOVE",             (ULONG) DosMove,
  720.     "MUXSEMWAIT",       (ULONG) DosMuxSemWait,
  721.     "NEWSIZE",          (ULONG) DosNewSize,
  722.     "OPEN",             (ULONG) DosOpen,
  723.     "OPENSEM",          (ULONG) DosOpenSem,
  724.     "PHYSICALDISK",     (ULONG) DosPhysicalDisk,
  725.     "PORTACCESS",       (ULONG) DosPortAccess,
  726.     "PTRACE",           (ULONG) DOSPTRACE,
  727.     "QCURDIR",          (ULONG) DosQCurDir,
  728.     "QCURDISK",         (ULONG) DosQCurDisk,
  729.     "QFHANDSTATE",      (ULONG) DosQFHandState,
  730.     "QFILEINFO",        (ULONG) DosQFileInfo,
  731.     "QFILEMODE",        (ULONG) DosQFileMode,
  732.     "QFSINFO",          (ULONG) DosQFSInfo,
  733.     "QHANDTYPE",        (ULONG) DosQHandType,
  734.     "QVERIFY",          (ULONG) DosQVerify,
  735.     "READ",             (ULONG) DosRead,
  736.     "READASYNC",        (ULONG) DosReadAsync,
  737.     "REALLOCHUGE",      (ULONG) DosReallocHuge,
  738.     "REALLOCSEG",       (ULONG) DosReallocSeg,
  739.     "RESUMETHREAD",     (ULONG) DosResumeThread,
  740.     "RMDIR",            (ULONG) DosRmdir,
  741.     "SCANENV",          (ULONG) DosScanEnv,
  742.     "SEARCHPATH",       (ULONG) DosSearchPath,
  743.     "SELECTDISK",       (ULONG) DosSelectDisk,
  744.     "SEMCLEAR",         (ULONG) DosSemClear,
  745.     "SEMREQUEST",       (ULONG) DosSemRequest,
  746.     "SEMSET",           (ULONG) DosSemSet,
  747.     "SEMSETWAIT",       (ULONG) DosSemSetWait,
  748.     "SEMWAIT",          (ULONG) DosSemWait,
  749.     "SENDSIGNAL",       (ULONG) DosSendSignal,
  750.     "SETCP",            (ULONG) DosSetCp,
  751.     "SETDATETIME",      (ULONG) DosSetDateTime,
  752.     "SETFHANDSTATE",    (ULONG) DosSetFHandState,
  753.     "SETFILEINFO",      (ULONG) DosSetFileInfo,
  754.     "SETFILEMODE",      (ULONG) DosSetFileMode,
  755.     "SETFSINFO",        (ULONG) DosSetFSInfo,
  756.     "SETMAXFH",         (ULONG) DosSetMaxFH,
  757.     "SETPRTY",          (ULONG) DosSetPrty,
  758.     "SETSIGHANDLER",    (ULONG) DosSetSigHandler,
  759.     "SETVEC",           (ULONG) DosSetVec,
  760.     "SETVERIFY",        (ULONG) DosSetVerify,
  761.     "SGSWITCH",         (ULONG) DOSSGSWITCH,
  762.     "SGSWITCHME",       (ULONG) DOSSGSWITCHME,
  763.     "SLEEP",            (ULONG) DosSleep,
  764.     "SUBALLOC",         (ULONG) DosSubAlloc,
  765.     "SUBFREE",          (ULONG) DosSubFree,
  766.     "SUBSET",           (ULONG) DosSubSet,
  767.     "SUSPENDTHREAD",    (ULONG) DosSuspendThread,
  768.     "SYSTEMSERVICE",    (ULONG) DosSystemService,
  769.     "SYSTRACE",         (ULONG) DOSSYSTRACE,
  770.     "TIMERASYNC",       (ULONG) DosTimerAsync,
  771.     "TIMERSTART",       (ULONG) DosTimerStart,
  772.     "TIMERSTOP",        (ULONG) DosTimerStop,
  773.     "UNLOCKSEG",        (ULONG) DosUnlockSeg,
  774.     "WRITE",            (ULONG) DosWrite,
  775.     "WRITEASYNC",       (ULONG) DosWriteAsync,
  776.     } ;
  777.  
  778. #define NUM_NEWCALLS    51
  779.  
  780. /* table stores ordinal numbers, until replaced by procaddr */
  781. /* add asterisks so they show up clearly */
  782. static DOSCALLS newcalls[NUM_NEWCALLS] = {
  783.     "CALLBACK *",           157L,
  784.     "FSRAMSEMCLEAR *",      162L,
  785.     "FSRAMSEMREQUEST *",    161L,
  786.     "GETSTDA *",            119L,  /* 3 wds */
  787.     "GLOBALSEG *",          132L,
  788.     "HUGEINCR *",           136L,
  789.     "HUGESHIFT *",          135L,
  790.     "ICANONICALIZE *",      100L,      /* 7 wds */
  791.     "ICREATETHREAD *",      1L,        /* 4 wds */
  792.     "IEXECPGM *",           4L,        /* 12 wds */
  793.     "IRAMSEMWAKE *",        125L,  /* 3 wds */
  794.     "IREAD *",              79L,       /* 6 wds */
  795.     "ISEMREQUEST *",        18L,   /* 4 wds */
  796.     "ISEMWAIT *",           21L,       /* 4 wds */
  797.     "ISETCP *",             131L,  /* 2 wds */
  798.     "ISYSSEMCLEAR *",       17L,       /* 2 wds */
  799.     "ISYSSEMSET *",         19L,   /* 2 wds */
  800.     "IWRITE *",             87L,   /* 6 wds */
  801.     "LIBINIT *",            96L,     /* 2 wds */
  802.     "PROFILE *",            133L,  /* 9 wds */
  803.     "QAPPTYPE *",           163L,
  804.     "QPROCSTATUS *",        184L,
  805.     "QSYSINFO *",           166L,    /* 4 wds */
  806.     "QTRACEINFO *",         93L,
  807.     "R2STACKREALLOC *",     160L,    /* 1 wds */
  808.     "READPHYS *",           103L,
  809.     "SETFGND *",            101L,  /* 2 wds */
  810.     "SETPROCCP *",          155L,      /* 5 wds */
  811.     "SGSWITCHPROC *",       124L,
  812.     "SIZESEG *",            126L,    /* 3 wds */
  813.     "SWAPTASKINIT *",       102L,
  814.  
  815.     /* names that don't have DOS in front of them */
  816.     "*GETADDR *",    111L,
  817.     "*GETHEADERS *", 108L,
  818.     "*GETSELADDR *", 110L,
  819.     "*STRUCHECK *", 106L,
  820.     "*STRURESUPDATE *", 107L,
  821.     "*UNUSEDA *",    98L,
  822.     "*UNUSEDB *",    99L,
  823.     "*UNUSEDC *",    126L,
  824.     "*UNUSEDD *",    128L,
  825.     "*UNUSEDE *",    104L,
  826.     "*UNUSEDF *",    105L,
  827.     "*UNUSEDG *",    95L,
  828.     "*DBGETKVAR *", 109L,
  829.     "*DBGETOWNER *", 117L,
  830.     "*DBMEMFREE *", 116L,
  831.     "*DBMEMLOCK *", 112L,
  832.     "*DBMEMREALLOC *", 15L,
  833.     "*DBMEMUNLOCK *", 113L,
  834.     "*DBPHYSINFO *", 118L,
  835.     "*DBSEGALLOC *", 114L,
  836.     } ;
  837.  
  838. int cmp_doscalls(DOSCALLS *dc1, DOSCALLS *dc2)
  839. {
  840.     return  (dc1->procaddr == dc2->procaddr) ? 0 :
  841.             (dc1->procaddr < dc2->procaddr) ? -1 : 1;
  842. }
  843.  
  844. int srch_doscall(USHORT *seg, DOSCALLS *dc)
  845. {
  846.     USHORT ndx1 = IGNORE_RPL(*seg);
  847.     USHORT ndx2 = IGNORE_RPL(FP_SEG(dc->procaddr));
  848.     return (ndx1 == ndx2) ? 0 : (ndx1 < ndx2) ? -1 : 1;
  849. }
  850.  
  851. #define FAILBUFSIZE 128
  852.  
  853. void init_doscalls(void)
  854. {
  855.     /* try to install new functions */
  856.     char failbuffer[FAILBUFSIZE];
  857.     ULONG procaddr;
  858.     USHORT doscalls;
  859.     REG DOSCALLS *p;
  860.     REG USHORT i;
  861.     
  862.     DosLoadModule(failbuffer, FAILBUFSIZE, "DOSCALLS", &doscalls);
  863.     
  864.     /* sort dosfuncs by address */
  865.     qsort(dosfuncs, NUM_DOSCALLS, sizeof(DOSCALLS), cmp_doscalls);
  866.     
  867.     /* before loop, newcalls[i].procaddr contains DOSCALLS.ord# */
  868.     for (i=0, p=newcalls; i<NUM_NEWCALLS; i++, p++)
  869.         if (! DosGetProcAddr(doscalls, p->procaddr, &procaddr))
  870.         {
  871.             LAR ar;
  872.             USHORT u = lar(FP_SEG(procaddr));
  873.             ar = LAR_FM_USHORT(u);
  874.             if (ISGATE(ar) && GATE_TYPE(ar) == CALL_GATE)
  875.                 p->procaddr = procaddr;
  876.         }
  877.         
  878.     /* sort newcalls by address */
  879.     qsort(newcalls, NUM_NEWCALLS, sizeof(DOSCALLS), cmp_doscalls);
  880. }
  881.  
  882. char *get_doscall_name(USHORT seg)
  883. {
  884.     DOSCALLS *p;
  885.  
  886.     return
  887.         (p = bsearch(&seg, dosfuncs, NUM_DOSCALLS, sizeof(DOSCALLS),
  888.             srch_doscall)) ? p->name :
  889.         (p = bsearch(&seg, newcalls, NUM_NEWCALLS, sizeof(DOSCALLS),
  890.             srch_doscall)) ? p->name :
  891.         /*otherwise*/ (char *) 0;
  892. }
  893.  
  894. /* target for CodeView breakpoint */
  895. void breakpoint(void) 
  896. {
  897.     /* this code intentionally left blank */
  898. }
  899.  
  900. void walk_idt(void)
  901. {
  902.     IDT i;
  903.     idt(&i);
  904.     walk_dt(&i, walk);
  905. }
  906.  
  907. /* walk a descriptor table */
  908. /* or, change dump() params so it fits in same scheme */
  909. void walk_dt(DESCRIPTOR far *desc, void (*f)())
  910. {
  911.     FP p;
  912.     
  913.     p = PhysToUVirt(desc->base_hi, desc->base_lo, desc->limit,
  914.         UVirt_ReadWrite);
  915.     uvirt_p = p;
  916.     if (p)
  917.         (*f)(p, 0, desc->limit / sizeof(DESCRIPTOR));
  918.     if (! ReleaseUVirt(p))
  919.         puts(RELEASEUVIRT_FAIL);
  920.     uvirt_p = NULLPTR;
  921. }
  922.