home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 036 / emxfix02.zip / emx / src / os2 / ptrace.c < prev    next >
C/C++ Source or Header  |  1994-12-08  |  18KB  |  682 lines

  1. /* ptrace.c -- Implement ptrace()
  2.    Copyright (c) 1994 by Eberhard Mattes
  3.  
  4. This file is part of emx.
  5.  
  6. emx is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emx is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emx; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. As special exception, emx.dll can be distributed without source code
  21. unless it has been changed.  If you modify emx.dll, this exception
  22. no longer applies and you must remove this paragraph from all source
  23. files for emx.dll.  */
  24.  
  25.  
  26. #define INCL_DOSPROCESS
  27. #define INCL_DOSSESMGR
  28. #define INCL_DOSEXCEPTIONS
  29. #define INCL_DOSERRORS
  30. #include <os2emx.h>
  31. #include "clib.h"
  32. #include <sys/signal.h>
  33. #include <sys/ptrace.h>
  34. #include <sys/user.h>
  35. #include "reg.h"
  36. #include <sys/errno.h>
  37. #include "emxdll.h"
  38.  
  39. #define USEROFF(F) offsetof (struct user, F)
  40.  
  41. struct reg_table
  42. {
  43.   ULONG addr;
  44.   void *debug;
  45.   BYTE len;
  46. };
  47.  
  48. struct co_regs
  49. {
  50.   USHORT cw;
  51.   USHORT unused1;
  52.   USHORT sw;
  53.   USHORT unused2;
  54.   USHORT tw;
  55.   USHORT unused3;
  56.   ULONG fip;
  57.   USHORT fcs;
  58.   USHORT fop;
  59.   ULONG foo;
  60.   USHORT fos;
  61.   USHORT unused4;
  62.   BYTE fst[8][10];
  63. };
  64.  
  65. static BYTE float_regs;
  66. static uDB_t dbgbuf;
  67. static ULONG child_syscall;
  68. static ULONG child_layout;
  69. static ULONG child_session;
  70. static ULONG run_tid;
  71. static BYTE auto_switch;
  72. static ULONG run_pid;
  73. static struct co_regs dbgco;
  74. static BYTE brk_flag;
  75. static BYTE more;
  76. static BYTE second;
  77.  
  78. /* Table for converting user struct offsets into pointers to fields of
  79.    dbgbuf.  It also contains the lengths of the fields. */
  80.  
  81. static struct reg_table const ptrace_regs[] =
  82. {
  83.   {USEROFF (u_regs[R_GS]),   &dbgbuf.GS,     2},
  84.   {USEROFF (u_regs[R_FS]),   &dbgbuf.FS,     2},
  85.   {USEROFF (u_regs[R_ES]),   &dbgbuf.ES,     2},
  86.   {USEROFF (u_regs[R_DS]),   &dbgbuf.DS,     2},
  87.   {USEROFF (u_regs[R_EDI]),  &dbgbuf.EDI,    4},
  88.   {USEROFF (u_regs[R_ESI]),  &dbgbuf.ESI,    4},
  89.   {USEROFF (u_regs[R_EBP]),  &dbgbuf.EBP,    4},
  90.   {USEROFF (u_regs[R_ESP]),  &dbgbuf.ESP,    4},
  91.   {USEROFF (u_regs[R_EBX]),  &dbgbuf.EBX,    4},
  92.   {USEROFF (u_regs[R_EDX]),  &dbgbuf.EDX,    4},
  93.   {USEROFF (u_regs[R_ECX]),  &dbgbuf.ECX,    4},
  94.   {USEROFF (u_regs[R_EAX]),  &dbgbuf.EAX,    4},
  95.   {USEROFF (u_regs[R_EIP]),  &dbgbuf.EIP,    4},
  96.   {USEROFF (u_regs[R_CS]),   &dbgbuf.CS,     2},
  97.   {USEROFF (u_regs[R_EFL]),  &dbgbuf.EFlags, 4},
  98.   {USEROFF (u_regs[R_UESP]), &dbgbuf.ESP,    4},
  99.   {USEROFF (u_regs[R_SS]),   &dbgbuf.SS,     2}
  100. };
  101.  
  102.  
  103. static const struct reg_table *user_addr (ULONG addr)
  104. {
  105.   int i;
  106.  
  107.   for (i = 0; i < sizeof (ptrace_regs) / sizeof (ptrace_regs[0]); ++i)
  108.     if (ptrace_regs[i].addr == addr)
  109.       return (&ptrace_regs[i]);
  110.   return (NULL);
  111. }
  112.  
  113.  
  114. ULONG debug (void)
  115. {
  116.   ULONG rc;
  117.  
  118.   rc = DosDebug (&dbgbuf);
  119.   return (rc == 0 ? 0 : set_error (rc));
  120. }
  121.  
  122.  
  123. ULONG debug_read_byte (ULONG addr, BYTE *dst)
  124. {
  125.   ULONG rc;
  126.  
  127.   dbgbuf.Cmd  = DBG_C_ReadMem;
  128.   dbgbuf.Addr = addr;
  129.   rc = debug ();
  130.   if (rc != 0) return (rc);
  131.   *dst = (BYTE)dbgbuf.Value;
  132.   return (0);
  133. }
  134.  
  135.  
  136. ULONG debug_read_word (ULONG addr, ULONG *dst)
  137. {
  138.   ULONG rc, w;
  139.  
  140.   dbgbuf.Cmd  = DBG_C_ReadMem;
  141.   dbgbuf.Addr = addr;
  142.   rc = debug ();
  143.   if (rc != 0) return (rc);
  144.   w = dbgbuf.Value & 0xffff;
  145.   dbgbuf.Cmd  = DBG_C_ReadMem;
  146.   dbgbuf.Addr = addr + 2;
  147.   rc = debug ();
  148.   if (rc != 0) return (rc);
  149.   w |= (dbgbuf.Value & 0xffff) << 16;
  150.   *dst = w;
  151.   return (0);
  152. }
  153.  
  154.  
  155. void do_auto_switch (void)
  156. {
  157.   DosSelectSession (child_session);
  158.   auto_switch = FALSE;
  159. }
  160.  
  161.  
  162. static int debug_poke16 (ULONG addr, ULONG value)
  163. {
  164.   ULONG rc;
  165.  
  166.   dbgbuf.Cmd   = DBG_C_WriteMem;
  167.   dbgbuf.Addr  = addr;
  168.   dbgbuf.Value = value;
  169.   rc = debug ();
  170.   if (rc == 0 && dbgbuf.Cmd != DBG_N_Success)
  171.     rc = EIO;
  172.   return (rc);
  173. }
  174.  
  175.  
  176. /* Read the registers.  TID is the thread ID (0 means the active
  177.   thread).  Return errno. */
  178.  
  179. static ULONG read_reg (ULONG tid)
  180. {
  181.   ULONG rc;
  182.  
  183.   dbgbuf.Cmd = DBG_C_ReadReg;
  184.   dbgbuf.Tid = tid;
  185.   rc = debug ();
  186.   if (rc == 0 && dbgbuf.Cmd != DBG_N_Success)
  187.     rc = EIO;
  188.   return (rc);
  189. }
  190.  
  191.  
  192. /* Write the registers.  TID is the thread ID (which must be
  193.    non-zero).  Return errno. */
  194.  
  195. static ULONG write_reg (ULONG tid)
  196. {
  197.   ULONG rc;
  198.  
  199.   dbgbuf.Cmd = DBG_C_WriteReg;
  200.   dbgbuf.Tid = tid;
  201.   rc = debug ();
  202.   if (rc == 0 && dbgbuf.Cmd != DBG_N_Success)
  203.     rc = EIO;
  204.   return (rc);
  205. }
  206.  
  207.  
  208. /* Set a watchpoint.  Return errno. */
  209.  
  210. static ULONG set_watch (ULONG addr, ULONG len, ULONG type)
  211. {
  212.   ULONG rc;
  213.  
  214.   dbgbuf.Cmd   = DBG_C_SetWatch;
  215.   dbgbuf.Addr  = addr;
  216.   dbgbuf.Len   = len;
  217.   dbgbuf.Index = 0;             /* Reserved */
  218.   dbgbuf.Value = type | DBG_W_Local;
  219.   dbgbuf.Pid   = run_pid;
  220.   rc = debug ();
  221.   return (rc);
  222. }
  223.  
  224.  
  225. static ULONG terminate (void)
  226. {
  227.   ULONG rc;
  228.  
  229.   dbgbuf.Cmd = DBG_C_Term;
  230.   rc = debug ();
  231.   return (rc);
  232. }
  233.  
  234.  
  235. static ULONG get_fpstate (void)
  236. {
  237.   ULONG rc;
  238.  
  239.   dbgbuf.Cmd    = DBG_C_ReadCoRegs;
  240.   dbgbuf.Tid    = 0;            /* Thread: active thread */
  241.   dbgbuf.Value  = DBG_CO_387;   /* Coprocessor type */
  242.   dbgbuf.Buffer = (ULONG)&dbgco;
  243.   dbgbuf.Len    = sizeof (dbgco);
  244.   dbgbuf.Index  = 0;            /* Reserved */
  245.   rc = debug ();
  246.   if (rc == 0 && dbgbuf.Cmd != DBG_N_Success)
  247.     rc = EIO;
  248.   return (rc);
  249. }
  250.  
  251.  
  252. /* Return true if EIP points to a CALL instruction.  Moreover, true is
  253.    returned if an error occurs (to be on the safe side for
  254.    automatically switching to the child session). */
  255.  
  256. static int callp (void)
  257. {
  258.   ULONG eip, rc;
  259.   BYTE b;
  260.  
  261.   if (read_reg (0) != 0)
  262.     return (TRUE);
  263.   eip = dbgbuf.EIP;
  264.   do
  265.     {
  266.       rc = debug_read_byte (eip++, &b);
  267.       if (rc != 0) return (TRUE);
  268.     } while ((b & 0xe7) == 0x26 /* Segment override prefix */
  269.              || b == 0x64       /* FS prefix */
  270.              || b == 0x65       /* GS prefix */
  271.              || b == 0x66       /* Operand size prefix */
  272.              || b == 0x67);     /* Address size prefix */
  273.   if (b == 0xe8 || b == 0x9a)   /* CALL near label, CALL far label*/
  274.     return (TRUE);
  275.   if (b == 0xff)
  276.     {
  277.       rc = debug_read_byte (eip++, &b);
  278.       if (rc != 0) return (TRUE);
  279.       /* Note: This was off by one bit in child.asm! */
  280.       if ((b & 0x38) == 0x10)   /* CALL near reg/mem */
  281.         return (TRUE);
  282.       if ((b & 0x38) == 0x18)   /* CALL far reg/mem */
  283.         return (TRUE);
  284.     }
  285.   return (FALSE);
  286. }
  287.  
  288.  
  289. #define N_STOP                  (-1)
  290. #define N_CONTINUE_STOP         (-2)
  291. #define N_CONTINUE_SEARCH       (-3)
  292. #define N_RESUME                (-4)
  293.  
  294.  
  295. static int n_exception (void)
  296. {
  297.   int rc;
  298.   ULONG report, info, w;
  299.  
  300.   switch (dbgbuf.Value)
  301.     {
  302.     case DBG_X_PRE_FIRST_CHANCE: /* pre first chance */
  303.     case DBG_X_STACK_INVALID:   /* invalid stack */
  304.       /* The exception number is in dbgbuf.Buffer. */
  305.       if (dbgbuf.Buffer == XCPT_BREAKPOINT)
  306.         {
  307.           brk_flag = TRUE; more = FALSE;
  308.           debug_set_wait (run_pid, 0x7f | (SIGTRAP << 8), FALSE);
  309.           return (N_CONTINUE_STOP);
  310.         }
  311.       else if (dbgbuf.Buffer == XCPT_SINGLE_STEP)
  312.         {
  313.           more = FALSE;
  314.           debug_set_wait (run_pid, 0x7f | (SIGTRAP << 8), FALSE);
  315.           return (N_CONTINUE_STOP);
  316.         }
  317.       break;
  318.  
  319.     case DBG_X_FIRST_CHANCE:    /* first chance */
  320.       report = dbgbuf.Buffer;   /* Address of report buffer */
  321.       rc = debug_read_word (report, &w);
  322.       if (rc == 0)
  323.         switch (w)
  324.           {
  325.           case XCPT_GUARD_PAGE_VIOLATION:
  326.           case XCPT_PROCESS_TERMINATE:
  327.             second = TRUE;
  328.             return (N_CONTINUE_SEARCH);
  329.  
  330.           case XCPT_SIGNAL:
  331.             more = FALSE;
  332.             info = offsetof (EXCEPTIONREPORTRECORD, ExceptionInfo) + 0;
  333.             rc = debug_read_word (report + info, &w);
  334.             if (rc == 0)
  335.               switch (w)
  336.                 {
  337.                 case XCPT_SIGNAL_INTR:
  338.                   debug_set_wait (run_pid, 0x7f | (SIGINT << 8), FALSE);
  339.                   return (N_CONTINUE_STOP);
  340.  
  341.                 case XCPT_SIGNAL_BREAK:
  342.                   debug_set_wait (run_pid, 0x7f | (SIGBREAK << 8), FALSE);
  343.                   return (N_CONTINUE_STOP);
  344.  
  345.                 case XCPT_SIGNAL_KILLPROC:
  346.                   debug_set_wait (run_pid, 0x7f | (SIGTERM << 8), FALSE);
  347.                   return (N_CONTINUE_STOP);
  348.                 }
  349.             break;
  350.           }
  351.       break;
  352.  
  353.     case DBG_X_LAST_CHANCE:     /* last chance */
  354.  
  355.       /* dbgbuf.Buffer does not point to the exception report record
  356.          (documentation error or implementation error). */
  357.  
  358.       if (second)
  359.         {
  360.           second = FALSE;
  361.           return (N_CONTINUE_SEARCH);
  362.         }
  363.       break;
  364.     }
  365.  
  366.   more = FALSE;
  367.   debug_set_wait (run_pid, 0x7f | (SIGSEGV << 8), FALSE);
  368.   return (N_CONTINUE_STOP);
  369. }
  370.  
  371.  
  372. /* Handle the current notification and return N_STOP, N_CONTINUE_STOP,
  373.    N_CONTINUE_SEARCH, N_RESUME, or errno (non-negative). */
  374.  
  375. static int notification (void)
  376. {
  377.   int rc;
  378.  
  379.   switch (dbgbuf.Cmd)
  380.     {
  381.     case DBG_N_Success:
  382.  
  383.       /* The request was completed successfully.  Run or step again
  384.          unless `more' has been set to FALSE. */
  385.  
  386.       if (more)
  387.         return (N_RESUME);
  388.  
  389.       /* Running or stepping the debuggee is completed.  Read the
  390.          registers.  Skip over INT3 if a breakpoint was hit. */
  391.  
  392.       rc = read_reg (0);
  393.       if (rc == 0 && brk_flag)
  394.         {
  395.           /* Skip the INT3 instruction for compatibility with emx.exe
  396.              and GDB. */
  397.  
  398.           dbgbuf.EIP += 1;      /* Skip INT3 */
  399.           rc = write_reg (dbgbuf.Tid);
  400.         }
  401.       return (rc);              /* ptrace() successful (usually) */
  402.  
  403.     case DBG_N_Error:
  404.  
  405.       /* An error occured. */
  406.  
  407.       oprintf ("DosDebug error: 0x%.8x\r\n", (unsigned)dbgbuf.Value);
  408.       quit (255);
  409.  
  410.     case DBG_N_ProcTerm:
  411.  
  412.       /* Process terminated.  Let wait() return the termination
  413.          code. */
  414.  
  415.       debug_set_wait (run_pid, (dbgbuf.Value & 0xff) << 8, TRUE);
  416.       more = FALSE;
  417.       rc = terminate ();
  418.       return (rc);              /* ptrace() successful (usually) */
  419.  
  420.     case DBG_N_Exception:
  421.  
  422.       /* An exception occured. */
  423.  
  424.       return (n_exception ());
  425.  
  426.     case DBG_N_ModuleLoad:
  427.     case DBG_N_ModuleFree:
  428.     case DBG_N_ThreadTerm:
  429.       return (N_CONTINUE_STOP);
  430.           
  431.     case DBG_N_ThreadCreate:
  432.       run_tid = dbgbuf.Tid;
  433.       return (N_CONTINUE_STOP);
  434.  
  435.     case DBG_N_Watchpoint:
  436.  
  437.       /* Watchpoint hit.  Watchpoints are currently used only for
  438.          skipping over the call to emx_syscall when single-stepping.
  439.          Stop the debuggee and let wait() indicate SIGTRAP. */
  440.  
  441.       more = FALSE;
  442.       debug_set_wait (run_tid, 0x7f | (SIGTRAP << 8), FALSE);
  443.       return (N_STOP);
  444.  
  445.     case DBG_N_NewProc:
  446.     case DBG_N_AliasFree:
  447.     default:
  448.  
  449.       /* These notifications are not expected to occur. */
  450.  
  451.       oprintf ("Unexpected DosDebug notification: 0x%.8x\r\n",
  452.                (unsigned)dbgbuf.Cmd);
  453.       quit (255);
  454.     }
  455. }
  456.  
  457.  
  458. /* Perform a DBG_C_Go or DBG_C_SStep command. */
  459.  
  460. static ULONG run (ULONG cmd)
  461. {
  462.   ULONG rc;
  463.   int next;
  464.  
  465.   if (auto_switch && cmd == DBG_C_Go)
  466.     do_auto_switch ();
  467.   more = TRUE; brk_flag = FALSE; second = FALSE; float_regs = FALSE;
  468.   next = N_RESUME;
  469.   for (;;)
  470.     {
  471.       switch (next)
  472.         {
  473.         case N_RESUME:
  474.           if (auto_switch && cmd == DBG_C_SStep && callp ())
  475.             do_auto_switch ();
  476.           dbgbuf.Cmd = cmd;
  477.           dbgbuf.Pid = run_pid;
  478.           dbgbuf.Tid = 0;       /* All threads */
  479.           rc = debug ();
  480.           if (rc != 0) return (rc);
  481.           break;
  482.  
  483.         case N_STOP:
  484.           dbgbuf.Cmd = DBG_C_Stop;
  485.           dbgbuf.Pid = run_pid;
  486.           rc = debug ();
  487.           if (rc != 0) return (rc);
  488.           break;
  489.  
  490.         case N_CONTINUE_STOP:
  491.         case N_CONTINUE_SEARCH:
  492.           dbgbuf.Value = (next == N_CONTINUE_STOP
  493.                           ? XCPT_CONTINUE_STOP : XCPT_CONTINUE_SEARCH);
  494.           dbgbuf.Cmd   = DBG_C_Continue;
  495.           dbgbuf.Pid   = run_pid;
  496.           dbgbuf.Tid   = 1;
  497.           rc = debug ();
  498.           if (rc != 0) return (rc);
  499.           break;
  500.  
  501.         default:
  502.           /* errno value */
  503.           return ((ULONG)next);
  504.         }
  505.       next = notification ();
  506.     }
  507. }
  508.  
  509.  
  510. int do_ptrace (ULONG request, ULONG pid, ULONG addr, ULONG data, ULONG *errnop)
  511. {
  512.   ULONG rc, w;
  513.   const struct reg_table *rp;
  514.  
  515.   dbgbuf.Pid = run_pid = pid;
  516.   switch (request)
  517.     {
  518.     case PTRACE_EXIT:
  519.       float_regs = FALSE;       /* Floating point status is now invalid */
  520.       rc = terminate ();
  521.       *errnop = rc;
  522.       if (rc != 0) return (-1);
  523.       debug_set_wait (run_pid, 0, TRUE);
  524.       return (0);
  525.  
  526.     case PTRACE_PEEKTEXT:
  527.     case PTRACE_PEEKDATA:
  528.       rc = debug_read_word (addr, &w);
  529.       *errnop = rc;
  530.       if (rc != 0) return (-1);
  531.       return (w);
  532.  
  533.     case PTRACE_POKETEXT:
  534.     case PTRACE_POKEDATA:
  535.       rc = debug_poke16 (addr, (ULONG)data & 0xffff);
  536.       if (rc == 0)
  537.         rc = debug_poke16 (addr +2, (ULONG)data >> 16);
  538.       *errnop = rc;
  539.       return (rc == 0 ? 0 : -1);
  540.  
  541.     case PTRACE_PEEKUSER:
  542.       if (addr == USEROFF (u_ar0))
  543.         w = USEROFF (u_regs) + KERNEL_U_ADDR;
  544.       else if (addr == USEROFF (u_fpvalid))
  545.         {
  546.           if (!float_regs && get_fpstate () == 0)
  547.             float_regs = TRUE;
  548.           w = (float_regs ? 0xff : 0);
  549.         }
  550.       else if (addr == USEROFF (u_fpstate.status))
  551.         w = 0;                  /* ... */
  552.       else if (addr >= USEROFF (u_fpstate.state)
  553.                && addr <= USEROFF (u_fpstate.state) + sizeof (dbgco) - 4)
  554.         {
  555.           if (!float_regs)
  556.             {
  557.               rc = get_fpstate ();
  558.               if (rc != 0)
  559.                 {
  560.                   *errnop = rc;
  561.                   return (-1);
  562.                 }
  563.               float_regs = TRUE;
  564.             }
  565.           memcpy (&w, (char *)&dbgco + addr - USEROFF (u_fpstate.state), 4);
  566.         }
  567.       else if ((rp = user_addr (addr)) != NULL)
  568.         {
  569.           w = 0;
  570.           memcpy (&w, rp->debug, rp->len);
  571.         }
  572.       else
  573.         {
  574.           *errnop = EINVAL;
  575.           return (-1);
  576.         }
  577.       *errnop = 0;
  578.       return (w);
  579.  
  580.     case PTRACE_POKEUSER:
  581.       rp = user_addr (addr);
  582.       if (rp == NULL)
  583.         rc = EIO;
  584.       else
  585.         rc = read_reg (0);
  586.       if (rc == 0)
  587.         {
  588.           memcpy (rp->debug, &data, rp->len);
  589.           rc = write_reg (dbgbuf.Tid);
  590.         }
  591.       *errnop = rc;
  592.       return (rc == 0 ? 0 : -1);
  593.  
  594.     case PTRACE_RESUME:
  595.       rc = run (DBG_C_Go);
  596.       *errnop = rc;
  597.       return (rc == 0 ? 0 : -1);
  598.  
  599.     case PTRACE_STEP:
  600.       if (child_syscall != 0 && child_syscall == dbgbuf.EIP)
  601.         {
  602.           /* Avoid stepping into emx_syscall. */
  603.           rc = set_watch (child_syscall + 5, 1, DBG_W_Execute);
  604.           if (rc == 0)
  605.             rc = run (DBG_C_Go);
  606.         }
  607.       else
  608.         rc = run (DBG_C_SStep);
  609.       *errnop = rc;
  610.       return (rc == 0 ? 0 : -1);
  611.  
  612.     case PTRACE_SESSION:
  613.       if (!debug_same_sess)
  614.         switch (data)
  615.           {
  616.           case 0:               /* Switch to debugger */
  617.             DosSelectSession (0);
  618.             auto_switch = FALSE;
  619.             break;
  620.  
  621.           case 1:               /* Switch to child */
  622.             DosSelectSession (child_session);
  623.             auto_switch = FALSE;
  624.             break;
  625.  
  626.           case 2:               /* Automatic switch to child */
  627.             auto_switch = TRUE;
  628.             break;
  629.  
  630.           default:
  631.             /* Succeed for undefined values. */
  632.             break;
  633.           }
  634.       *errnop = 0;
  635.       return (0);
  636.  
  637.     case PTRACE_TRACEME:
  638.     default:
  639.       *errnop = EINVAL;
  640.       return (-1);
  641.     }
  642. }
  643.  
  644.  
  645. /* Prepare a child process for debugging. */
  646.  
  647. ULONG spawn_debug (ULONG pid, ULONG sid)
  648. {
  649.   ULONG rc, w;
  650.   BYTE b;
  651.  
  652.   run_tid = 0;
  653.   float_regs = FALSE;
  654.   child_syscall = 0;
  655.   child_layout = 0;
  656.   child_session = sid;
  657.   dbgbuf.Pid = pid;
  658.   dbgbuf.Tid = 0;               /* reserved */
  659.   dbgbuf.Cmd = DBG_C_Connect;
  660.   dbgbuf.Value = DBG_L_386;     /* level */
  661.   rc = debug ();
  662.   if (rc != 0) return (rc);
  663.   if (dbgbuf.Cmd != DBG_N_Success)
  664.     return (EINVAL);
  665.   dbgbuf.Cmd = DBG_C_ReadReg;
  666.   dbgbuf.Tid = 0;               /* Active thread */
  667.   rc = debug ();
  668.   if (rc != 0) return (rc);
  669.   if (dbgbuf.Cmd != DBG_N_Success)
  670.     return (EINVAL);
  671.   if (debug_read_byte (ENTRY_POINT+0, &b) == 0 && b == 0x68     /* PUSH n */
  672.       && debug_read_byte (ENTRY_POINT+5, &b) == 0 && b == 0xe8  /* CALL */
  673.       && debug_read_byte (ENTRY_POINT+10, &b) == 0 && b == 0xeb /* JMP */
  674.       && debug_read_byte (ENTRY_POINT+12, &b) == 0 && b == 0xe8 /* CALL */
  675.       && debug_read_word (ENTRY_POINT+1, &w) == 0)
  676.     {
  677.       child_layout = w;
  678.       child_syscall = ENTRY_POINT + 12;
  679.     }
  680.   return (0);
  681. }
  682.