home *** CD-ROM | disk | FTP | other *** search
/ ftp.robelle3000.ai 2014 / 2014.06.ftp.robelle3000.ai.tar / ftp.robelle3000.ai / papers / nmdebug.txt < prev    next >
Text File  |  1994-04-28  |  36KB  |  902 lines

  1.  
  2.  
  3.  
  4.                     The MPE/iX System Debugger
  5.  
  6.             By David J. Greer, Robelle Consulting Ltd.
  7.  
  8.  
  9.            Copyright Robelle Consulting Ltd.  1991,1994
  10.  
  11.  
  12.       Permission is granted to reprint this document (but not
  13.        for profit), provided that copyright notice is given.
  14.  
  15.  
  16.  
  17.  MPE/iX comes with a powerful debugger.  For those of us who have
  18.  struggled with Debug/V, there are many great features to look
  19.  forward to.  But, like all new software, there is a learning
  20.  curve in understanding the new MPE/iX debugger.  Attempting to
  21.  find the dozen or so most useful features in the three-inch stack
  22.  of paper called the System Debugger Reference Manual is
  23.  impossible, unless you have three spare months.  In this article,
  24.  I intend to summarize the features I've found most useful.
  25.  
  26.  I am indebted to Stan Sieler of Allegro Consultants who taught me
  27.  much of what is presented in this article.  To obtain the maximum
  28.  benefit from this article, you should try all of the examples
  29.  that are presented.  Having both a CM- and an NM-program
  30.  available that calls the FWRITE intrinsic will make following the
  31.  examples that much easier.  If you are going to be a big user of
  32.  Debug/iX, then you really have to have the reference manual.
  33.  Order part #32650-90013, System Debug Reference Manual.
  34.  
  35.  
  36.  Native-Mode or Compatibility-Mode
  37.  
  38.  HP was very kind to write not only a nice debugger for
  39.  native-mode programs, but include features for debugging
  40.  compatibility-mode programs too.  When I first attempted to debug
  41.  a CM-program, I got so confused that I returned to my classic HP
  42.  3000 where at least I knew all the command names.  The next
  43.  section will show Debug/iX commands for our old favorite Debug/V
  44.  commands.
  45.  
  46.  
  47.  Debug/V Versus Debug/iX
  48.  
  49.  Just like Debug/V, you can invoke Debug/iX by including the
  50.  keyword "Debug" on the :Run Command for your program.  Debug/iX
  51.  responds with its "CM" prompt:
  52.  
  53.       :run testprog;debug
  54.  
  55.       CM DEBUG Intrinsic: PROG %6.3542
  56.       cmdebug >
  57.  
  58.  If you have a Pmap (or Robelle's Qmap), you can set a breakpoint
  59.  just as you would in Debug/V -- using segment.offset:
  60.  
  61.       cmdebug >B 0.45
  62.  
  63.  Anyone who has struggled with Pmaps knows how convenient it would
  64.  be if the system debugger took advantage of the FPMAP information
  65.  stored in program files.  With this information it should be
  66.  possible to set a breakpoint by procedure name.  Debug/iX lets
  67.  you either set a symbolic breakpoint at the first logical
  68.  instruction in your procedure or at the more useful entry-point:
  69.  
  70.       cmdebug >B open'input'file       {first instruction}
  71.       cmdebug >B ?open'input'file      {? implies entry point}
  72.       cmdebug >B open'input'file+255   {octal offset from first}
  73.       cmdebug >c                       {Continue = Resume}
  74.  
  75.  
  76.  Breakpoints
  77.  
  78.  In the last ten years, I have probably lost over a month of time
  79.  from one horrible default in Debug/V.  In Debug/V, the Break
  80.  Command would only break the first time it encountered the
  81.  breakpoint, unless you added ":@" to the Break Command.  In
  82.  Debug/iX the default is to always break.  Occasionally, you only
  83.  want the breakpoint to be invoked once.  Use ",-1" after the
  84.  break location to have the breakpoint removed after one
  85.  occurrence:
  86.  
  87.       nmdebug >b ?open'input'file,-1 {break once}
  88.  
  89.  
  90.  Clearing Breakpoints
  91.  
  92.  In Debug/V, the Clear Command disables breakpoints that have been
  93.  set with the Break Command.  In Debug/iX, use the BD (Breakpoint
  94.  Delete) Command to remove breakpoints:
  95.  
  96.       nmdebug >bd       {You will be asked for which one}
  97.       nmdebug >bd @     {Delete all breakpoints}
  98.  
  99.  
  100.  Setting a "Return" Breakpoint
  101.  
  102.  One of the most useful breakpoints is the one immediately after a
  103.  procedure call.  Suppose that your program calls the procedure
  104.  extract_ready.  You want to know the result of extract_ready, so
  105.  you would like a breakpoint in the calling code immediately after
  106.  the call to extract_ready.  You do the following:
  107.  
  108.       cmdebug >b ?extract_ready
  109.       cmdebug >c
  110.       .
  111.       .
  112.       .                        {break at extract_ready}
  113.       cmdebug >lev 1;b p,-1    {-1 means only break once}
  114.       cmdebug >c               {continue execution}
  115.  
  116.  The "lev 1" goes back to the previous logical level in the
  117.  calling sequence (use "tr,d" to see a complete traceback).  The
  118.  "b p" sets a breakpoint at the compatibility-mode program
  119.  counter.  The "lev 1" places the program counter at the
  120.  instruction after the one that called the current procedure.  The
  121.  ",-1" tells Debug/iX to execute the breakpoint once and then
  122.  throw it away.  Note that it's safe to use this breakpoint
  123.  anywhere in the extract_ready procedure -- not just at the
  124.  beginning.
  125.  
  126.  What if we are in native-mode code (e.g., FWRITE)?  Our return
  127.  breakpoint won't work, since we called FWRITE from compatibility-
  128.  mode.  To set a return breakpoint in this case, first switch into
  129.  cmdebug:
  130.  
  131.       cmdebug >b ?FWRITE
  132.       cmdebug >c
  133.       .
  134.       .
  135.       .                        {break at NM FWRITE}
  136.       nmdebug >cm              {switch into CM}
  137.       cmdebug >lev 1;b p,-1    {set return breakpoint}
  138.       cmdebug >c               {continue execution}
  139.  
  140.  
  141.  Abort Command -- Getting Out of Debug
  142.  
  143.  You can terminate your program with the Abort Command.  Use this
  144.  any time that Debug/iX is prompting for commands.  The Debug/iX
  145.  Abort Command is similar to the Debug/V E@ Command.
  146.  
  147.  
  148.  Displaying Values
  149.  
  150.  When I first used Debug/iX, I became totally confused about how
  151.  to display the usual DB-, Q-, and S-relative values.  It turns
  152.  out to be very simple.  In Debug/V the Display Command takes the
  153.  register as a parameter.  In Debug/iX there are separate command
  154.  names for displaying values relative to each register.  Here are
  155.  the Debug/V and Debug/iX Display Commands:
  156.  
  157.       Debug/V     Debug/iX
  158.         D DB        DDB
  159.         D S         DS
  160.         D Q         DQ
  161.  
  162.  The Debug/iX Display Command has a count as its second parameter
  163.  (just like Debug/V), but the display attribute is different.
  164.  Here is the comparison:
  165.  
  166.       Debug/V      Debug/iX         Description
  167.       ,I           ,# or D          Decimal
  168.       ,O           ,% or O          Octal {default in CM}
  169.       ,H           ,$ or H          Hexadecimal {default in NM}
  170.       ,A           ,S               Ascii/String
  171.  
  172.  Instead of S, you can also use A for displaying string values.
  173.  The A-option is closer to the A-option of Debug/V, but we find
  174.  the S-option more useful.
  175.  
  176.  By default, the S-option displays all characters you request and
  177.  only displays the virtual address of the string once.  If you
  178.  want to see as many characters per line as possible, with each
  179.  new line starting with the virtual address of the characters
  180.  displayed, use this command:
  181.  
  182.       cmdebug >dq 104,200,s,e      {"e" shows addresses}
  183.  
  184.  
  185.  Symbolic Machine Code
  186.  
  187.  Our list above doesn't show you how to display the actual
  188.  run-time machine instructions (commonly called decompiling).
  189.  That's because Debug/iX has many excellent features to
  190.  symbolically display code.  While you can use the DC (Display
  191.  Code) Command to show symbolic code, we have found a better
  192.  method -- windows.
  193.  
  194.  
  195.  Symbolic Traceback
  196.  
  197.  The Debug/V Trace Command was almost useless.  You had to
  198.  manually work through the segment numbers and offsets to figure
  199.  out the true procedure names.  The Debug/iX Trace Command
  200.  produces a proper symbolic traceback of procedure names.
  201.  
  202.  You can also use the traceback to observe switches from
  203.  native-mode to compatibility-mode.  For example, if you have SM
  204.  capability you can set a breakpoint in any system SL or system XL
  205.  routine.  KSAM files come in two flavors: CM and NM.  If you
  206.  access a CM KSAM file from a NM program, MPE/iX calls the CM
  207.  FWRITE intrinsic.  You can easily prove this to yourself by
  208.  setting a breakpoint in the CM FWRITE intrinsic:
  209.  
  210.       :run testprog;debug        {NM program to read CM KSAM file}
  211.       nmdebug >cmdebug           {switch to CM}
  212.       cmdebug >b ?FWRITE         {question-mark for entry point}
  213.       cmdebug >c                 {continue execution}
  214.       .
  215.       .
  216.       .                          {note the ",d" on the TR Command}
  217.       cmdebug >tr,d              {traceback showing switches}
  218.  
  219.  
  220.  
  221.  
  222.                     Compatibility-Mode Windows
  223.  
  224.  
  225.  The WON Command is the real power of Debug/iX.  WON is short for
  226.  Windows On.  When you turn windows on, the top portion of the
  227.  screen is reserved for a symbolic display of the currently
  228.  executing code, another portion displays register and/or stack
  229.  values, and the bottom of the screen is used to enter commands.
  230.  This is a very powerful feature.
  231.  
  232.  
  233.  CM Window Example
  234.  
  235.  The following is an example compatibility-mode window.  We first
  236.  set a breakpoint, continue to that breakpoint, and finally we
  237.  turn windows on.
  238.  
  239.       cmdebug >b ?input'command     {break at the entry point}
  240.       cmdebug >c                    {continue execution}
  241.       .
  242.       .
  243.       .
  244.       cmdebug >won                  {turn windows on}
  245.  
  246.  The top three lines of the display show the register information:
  247.  
  248.  R % Regs   DB=001200  DBDST=001632  X=000002 STATUS=(mITroC CCG 007)   PIN=051
  249.  SDST=001627  DL=177450     Q=023620     S=023620      CMPC=PROG 000006.006711
  250.   CIR=035004  MAPFLAG=0     MAPDST=000000
  251.  FcmP %    PROG 6.6711         (?) SETUP             CSTX 7            Level 0
  252.  006707:          INPUT'COMMAND+%437       031031  2.  PCAL ?ERRX
  253.  006710:          INPUT'COMMAND+%440       032000  4.  SXIT  0
  254.  006711:     [1]> ?INPUT'COMMAND           035004  :.  ADDS  4
  255.  006712:          INPUT'COMMAND+%442       171700  ..  LRA   S-0
  256.  006713:          INPUT'COMMAND+%443       051401  S.  STOR  Q+1
  257.  006714:          INPUT'COMMAND+%444       035023  :.  ADDS  %23
  258.  006715:          INPUT'COMMAND+%445       041401  C.  LOAD  Q+1
  259.  Q %  (DB  mode)                    QDST=001627                       Level 0
  260.  023610:  000000   047420   061006   000006   177600   D000002    D00364
  261.  023620:Q>D000014 <S
  262.  023630:
  263.  S %  (DB  mode)                    SDST=001627                       Level 0
  264.  023610:  000000   047420   061006   000006   177600   D000002    D00364
  265.  023620:Q>D000014 <S
  266.  Commands
  267.  
  268.  %47 (%103) cmdebug >
  269.  
  270.  
  271.  For most of us, only the DL=, Q=, S=, and X= values are
  272.  interesting.  If the DBDST and the SDST (the DB- and S- data
  273.  segments) are different, you are in split-stack mode.  Line four
  274.  shows that we are currently at location 6.6711 in the program.
  275.  The PROG would change if the breakpoint was inside an SL.  Next
  276.  we see seven instructions.  The "[1]" means breakpoint number 1.
  277.  The ">" symbol next to "?INPUT'COMMAND" shows the next
  278.  instruction to be executed.  The bottom of the display shows the
  279.  values around the Q- and S- registers.  In our example, the Q and
  280.  S registers are the same so the Q- and S-displays are identical.
  281.  Finally, you are prompted for more Debug/iX commands.
  282.  
  283.  
  284.  Single-Stepping
  285.  
  286.  One other command adds a lot of power to windows:  S --
  287.  single-stepping.  The S Command executes the next instruction,
  288.  then returns control to Debug/iX.  After the execution, register
  289.  and stack values are updated and any changed values are
  290.  highlighted.  Because the compatibility-mode window shows the top
  291.  few words of the stack, you can often get an instant picture of
  292.  what is going on.  Here is the first window after executing one
  293.  single-step:
  294.  
  295.       cmdebug >s              {single-step}
  296.  
  297.  R % Regs   DB=001200  DBDST=001632  X=000002 STATUS=(mITroC CCG 007)   PIN=1
  298.  SDST=001632  DL=177450     Q=023620     S=023624      CMPC=PROG 000006
  299.   CIR=171700  MAPFLAG=0     MAPDST=000000
  300.  cmP %    PROG 6.6712         (?) SETUP             CSTX 7            Level 0
  301.  006707:          INPUT'COMMAND+%437       031031  2.  PCAL ?ERRX
  302.  006710:          INPUT'COMMAND+%440       032000  4.  SXIT  0
  303.  006711:     [1]  ?INPUT'COMMAND           035004  :.  ADDS  4
  304.  006712:        > INPUT'COMMAND+%442       171700  ..  LRA   S-0
  305.  006713:          INPUT'COMMAND+%443       051401  S.  STOR  Q+1
  306.  006714:          INPUT'COMMAND+%444       035023  :.  ADDS  %23
  307.  006715:          INPUT'COMMAND+%445       041401  C.  LOAD  Q+1
  308.  Q %  (DB  mode)                    QDST=001632                       Level 0
  309.  023610:  000000   047420   061006   000006   177600   000002   00364
  310.  023620:Q>000014   000002   006712   062007   d
  311.  023630:
  312.  S %  (DB  mode)                    SDST=001632                       Level 0
  313.  023610:  000000   047420   061006   000006   177600   000002   00364
  314.  023620:Q>000014   000002   006712   062007<S
  315.  Commands
  316.  
  317.  %47 (%103) cmdebug >
  318.  
  319.  
  320.  The ">" symbol has moved forward by one instruction.  The
  321.  register values have been updated and the top of stack has
  322.  changed because we added four to the S-register.
  323.  
  324.  
  325.  Set CRON
  326.  
  327.  This sounds like the title of a futuristic movie, but when
  328.  combined with single-stepping it can be very powerful.  Once you
  329.  start using the S (Single-Step) Command, you'll find yourself
  330.  typing it a lot, especially when debugging NM programs where you
  331.  have a lot more instructions per source code statement.
  332.  Fortunately, the Debug/iX designers already thought of this.
  333.  When you Set CRON, hitting Return tells Debug/iX "execute the
  334.  last command that I typed".  This is most useful when your last
  335.  command was S, but it applies to any command:
  336.  
  337.       cmdebug >set cron        {Return = last-command}
  338.       cmdebug >s               {single-step}
  339.       cmdebug >                {another single-step!}
  340.       cmdebug >                {and one more}
  341.       cmdebug >                {and so on}
  342.  
  343.  
  344.  Multiple Steps
  345.  
  346.  While single-stepping is useful, it can be very slow.  You can
  347.  step through a program faster using multiple instructions for
  348.  every step.  The following example shows how to step through
  349.  every seven executed instructions.  Note:  you must have a space
  350.  after the Step Command and before the number of instructions to
  351.  execute (e.g., "S7" is invalid):
  352.  
  353.       cmdebug >set cron        {Return = last-command}
  354.       cmdebug >s 7             {execute seven instructions}
  355.       cmdebug >                {another seven!}
  356.       cmdebug >                {and seven more}
  357.       cmdebug >                {and so on}
  358.  
  359.  
  360.  
  361.  
  362.  
  363.                        Native-Mode Debugging
  364.  
  365.  
  366.  Much of what has been discussed applies to native-mode.  There
  367.  are a few minor differences:
  368.  
  369.  1. You don't need to specify Fpmap (or any other magic parameter)
  370.     on the :Link Command.  Procedure name and location information
  371.     is automatically included in all NM program files.
  372.  
  373.  2. Since the first instruction of a procedure and its entry point
  374.     are the same, you never need to use a question mark.  If you
  375.     happen to type a question mark, Debug/iX may not print an
  376.     error.  In this case, you will have set a breakpoint in a stub
  377.     procedure.  Since you almost never want to do this, it's
  378.     important to remember not to type the question mark before the
  379.     procedure name.
  380.  
  381.  3. In most programming languages, any separators (e.g.,
  382.     apostrophes) used in procedure names will now become
  383.     underbars.
  384.  
  385.  Here is our previous breakpoint example in native-mode:
  386.  
  387.       nmdebug >b open_input_file    {break at procedure entry}
  388.  
  389.  
  390.  Case Sensitivity
  391.  
  392.  It is easy to see that portions of MPE/iX were affected by UNIX
  393.  and the C programming language.  In UNIX and C, case is
  394.  significant (i.e., upper-case and lower-case are not the same).
  395.  When setting breakpoints in native-mode code, it is important to
  396.  remember this.  Most MPE/iX routine names are in upper-case.  The
  397.  most well-known exceptions are all of the IMAGE and VPLUS
  398.  intrinsics which are in lower-case.  The following example
  399.  results in a Debug/iX error:
  400.  
  401.       nmdebug >b fwrite          {not found; lower-case}
  402.  
  403.  
  404.  Switching Modes
  405.  
  406.  Sometimes you want to switch between CM-debug and NM-debug.  For
  407.  example, the NM-FWRITE intrinsic calls the CM-FWRITE intrinsic
  408.  for certain types of files (e.g., circular).  These commands
  409.  would set breakpoints in both the CM- and NM-FWRITE intrinsics:
  410.  
  411.       nmdebug >b FWRITE         {NM-FWRITE breakpoint}
  412.       nmdebug >cm               {switch into cmdebug}
  413.       cmdebug >b ?FWRITE        {CM-FWRITE breakpoint}
  414.       cmdebug >nm               {switch back into nmdebug}
  415.       nmdebug >c                {continue execution}
  416.  
  417.  
  418.  
  419.                         Native-Mode Windows
  420.  
  421.  
  422.  The WON (Windows On) Command is just as powerful in native-mode
  423.  as in compatibility-mode.  The display is different -- instead of
  424.  the old familiar DB, S, and Q registers, there is a strange group
  425.  of 32 "general-purpose" registers.  The code looks a lot
  426.  different too -- those famous RISC instructions instead of our
  427.  old faithful Classic 3000 ones.
  428.  
  429.  
  430.  NM Window Example
  431.  
  432.  We will show an example native-mode window, by setting a
  433.  breakpoint for the FWRITE intrinsic:
  434.  
  435.       nmdebug >b FWRITE            {requires SM capability}
  436.       nmdebug >c                   {continue execution}}
  437.       .
  438.       .
  439.       .
  440.       nmdebug >won                 {turn windows on}
  441.  
  442.  GR$   ipsw=0006fe0f=jthlnxbCVmrQPDI  priv=0  pc=0000000a.004a5fc0  pin=0000007a
  443.  r0  00000000 40100e20 004aee30 00000001 r4  c0000000 0000ffff 4033292a 00000000
  444.  r8  00000001 00000009 00000004 4034a880 r12 00000000 00000000 00000000 00000000
  445.  r16 00000000 00000000 00000000 c0000000 r20 c0000000 00000001 85240000 00000314
  446.  r24 40332604 000000d0 00000001 c0202008 r28 00000001 ffffffff 4034afd8 004aee30
  447.  nmP$  SYS   a.4a5fb8  NL.PUB.SYS/FSPACE+$5a4                        Level   0,0
  448.  004a5fb8:         FSPACE+$5a4            e840c000  BV       0(2)
  449.  004a5fbc:         FSPACE+$5a8            4fc33d31  LDWM     -360(0,30),3
  450.  004a5fc0:    [1]> FWRITE                 6bc23fd9  STW      2,-20(0,30)
  451.  004a5fc4:         FWRITE+$4              6fc30340  STWM     3,416(0,30)
  452.  004a5fc8:         FWRITE+$8              6bc43cc9  STW      4,-412(0,30)
  453.  004a5fcc:         FWRITE+$c              6bc53cd1  STW      5,-408(0,30)
  454.  004a5fd0:         FWRITE+$10             6bc63cd9  STW      6,-404(0,30)
  455.  Commands
  456.  
  457.  $7 ($1d) nmdebug >
  458.  
  459.  
  460.  The first line contains general information about the process
  461.  (e.g., the pin number).  The pc= is the program counter (notice
  462.  it's a full 64-bit address in space.offset format).  Lines two
  463.  through four of the display show all 32 general-purpose
  464.  registers.  The fifth line shows where the first instruction in
  465.  the window is located (in NL.Pub.Sys @ FSPACE+$5a4).  The
  466.  native-mode instructions are shown, along with the breakpoint
  467.  number "[1]" and the next instruction to be executed is marked
  468.  with the ">".
  469.  
  470.  There are two commands that can be a big benefit in examining the
  471.  code "around" a breakpoint: PB (Program Back) and PF (Program
  472.  Forward).
  473.  
  474.  
  475.  Paging
  476.  
  477.  Debug/iX windows have to display all their information in the
  478.  twenty-four lines on a standard terminal screen.  By default, the
  479.  size of the symbolic instruction list is seven instructions.
  480.  Especially when you are single-stepping through instructions, it
  481.  is very useful to see the previous seven instructions or the next
  482.  seven.  The PB (Program Back) Command displays the previous seven
  483.  instructions and the PF (Program Forward) Command shows the next
  484.  seven.  While seven instructions is the default, there are
  485.  commands to change the size of the program window.  If you have
  486.  changed the size, Program Back and Program Forward adjust
  487.  themselves to the new window size.
  488.  
  489.       nmdebug >pf             {program forward}
  490.       nmdebug >pb             {program back}
  491.  
  492.  
  493.  PL Command
  494.  
  495.  If you want to change the number of program instructions on the
  496.  screen, use the PL Command (Program List).  The PL Command
  497.  assumes that the number of lines you want is in the current base.
  498.  Therefore, PL 10 means 16 instructions in NM Debug and 8
  499.  instructions in CM Debug.  To get around the problem, we always
  500.  specify the number of instructions in decimal:
  501.  
  502.       nmdebug >pl #10     {show "ten" instructions}
  503.  
  504.  
  505.  
  506.  
  507.                  Native-Mode Procedure Parameters
  508.  
  509.  
  510.  Long-time users of Debug/V know how to anticipate where procedure
  511.  parameters will be located.  For example, if we had a procedure
  512.  with this declaration:
  513.  
  514.       integer procedure convint(buf,len);  !result = Q-6
  515.          value   len;
  516.          integer len;                      !len    = Q-4
  517.          byte array buf;                   !@buf   = Q-5
  518.  
  519.  In CM-debug, we would look at the parameters as follows:
  520.  
  521.       cmdebug >dq -6           {result of Convint procedure}
  522.       cmdebug >dq -4           {length of buffer}
  523.       cmdebug >dq -5           {address of buffer}
  524.       Q-%5     % 000104        {must use this value below}
  525.       cmdebug >ddb 104/2,10,s  {print actual buffer contents}
  526.  
  527.  Notice that we had to divide the value at Q-5 (i.e., %104) by
  528.  two, since the buffer was passed as a byte address.  In
  529.  native-mode, this irritation disappears (except for those using
  530.  SPLash! to emulate Classic byte addressing).
  531.  
  532.  
  533.  Native-Mode Calling Conventions
  534.  
  535.  With the power to set breakpoints symbolically, by just knowing
  536.  the name of a procedure, there is even more incentive to be able
  537.  to guess the location of procedure parameters.  NM procedures are
  538.  allocated registers for the first four parameters, but they are
  539.  allocated left-to-right -- the opposite of CM procedures.  The
  540.  first parameter is assigned to Register-26, the second to
  541.  Register-25, the third to Register-24, the fourth to Register-23,
  542.  and any remaining parameters are stored on the NM stack.  The
  543.  return value is in Register-28 (and Register-29 for 64-bit
  544.  values).  For native-mode, you would think of the declaration for
  545.  Convint as:
  546.  
  547.       integer procedure convint(buf,len); !result = R28
  548.          value   len;
  549.          integer len;                     !len    = R25
  550.          byte array buf;                  !@buf   = R26
  551.  
  552.  If you have windows on, the 32 general-purpose registers are
  553.  always displayed.  The only problem area is the buffer parameter:
  554.  
  555.       nmdebug >b convint       {note lower-case}
  556.       nmdebug >won             {windows on}
  557.       nmdebug >c               {continue execution}
  558.       .
  559.       .
  560.       .                        {debug breaks @ convint}
  561.       nmdebug >=r25            {display the length}
  562.       nmdebug >dv r26,10,s     {display virtual uses the contents}
  563.                                {of register 26 as an address}
  564.  
  565.  
  566.  Variables
  567.  
  568.  Debug/iX contains a programming language.  We won't try and cover
  569.  all of the features of this language, but variables are so
  570.  powerful that they are worth knowing about.  In our example with
  571.  the Convint procedure, suppose that the buffer you are passing to
  572.  Convint is a global variable.  Setting the breakpoint at Convint
  573.  gives you a convenient method to find and save the address of
  574.  your buffer so that you can use it at any breakpoint.
  575.  
  576.       nmdebug >var buf_var=r26  {save address of buffer}
  577.       nmdebug >dv buf_var,10,s  {display buffer contents}
  578.       nmdebug >c                {continue execution}
  579.       .
  580.       .
  581.       .                         {sometime much later ...}
  582.       nmdebug >dv buf_var,10,s  {display the buffer contents}
  583.  
  584.  The final Display Virtual Command displays the contents of the
  585.  buffer using the address that we saved.  When the breakpoint
  586.  takes place, we may have no convenient way of finding the program
  587.  variable that has the address of our buffer.  Because we have
  588.  saved the address in the Debug/iX variable "buf_var", we display
  589.  the buffer contents without knowing where the address is stored.
  590.  
  591.  
  592.  Virtual Addresses
  593.  
  594.  So far, we have assumed that all addresses are 32-bits.  In
  595.  MPE/iX, addresses are actually 64-bits.  Debug/iX shows these
  596.  addresses as space.offset.  If you are working with mapped files,
  597.  you will find that the full 64-bit address suddenly becomes
  598.  important.  The following example opens a file with mapped
  599.  access, saves the virtual address of the file into a variable,
  600.  and then displays the actual contents of the file.
  601.  
  602.       nmdebug >map "file1.suprtest" {open an mpe file mapped}
  603.       nmdebug >var fileaddr = mapva("file1.suprtest")
  604.       nmdebug >=fileaddr            {display the virtual address}
  605.  
  606.  Debug/iX has a built-in calculator that accepts any Debug/iX
  607.  expression.  You invoke the calculator with an equal sign "=".
  608.  Debug/iX evaluates the calculator expression and prints the
  609.  result.  The calculator will display the full 64-bit address of
  610.  "file1.suprtest" as space.offset.
  611.  
  612.  You can display the actual contents of the file:
  613.  
  614.       nmdebug >dv fileaddr,20,s    {first 20-bytes of file}
  615.  
  616.  Warning:  Due to a very serious bug in MPE/iX, never, never,
  617.  never do this on the file Catalog.Pub.Sys.  If you open
  618.  Catalog.Pub.Sys with mapped access, you will cause a system
  619.  failure.
  620.  
  621.  The map command displays the virtual address of a file in
  622.  space.offset format.  You can use the DV (Display Virtual)
  623.  Command to display the file contents or you can use our method.
  624.  We prefer using a variable and mapva function, since typing in a
  625.  full 64-bit address correctly is quite difficult.
  626.  
  627.  
  628.  Cseq.Pub.Nuggets
  629.  
  630.  While it is easy to predict the layout of parameters in our
  631.  simple example, things can get more complicated in MPE/iX.  For
  632.  example, addresses can be passed as 64-bit quantities instead of
  633.  the default 32-bit values.  The best way I've found to determine
  634.  parameter location is to use the Cseq (calling sequence} utility
  635.  in the Nuggets collection (available from Software Research
  636.  Northwest 206-463-3030).  Here is the Cseq output for the FWRITE
  637.  intrinsic:
  638.  
  639.  Procedure FWRITE (
  640.           Parm  1:          int16   ;   {R26, bits =   16}
  641.           Parm  2: anyvar   record  ;   {(skip 25) R23, R24}
  642.                                         {bits = 65536}
  643.                                         {Address type = LongAddr}
  644.           Parm  3:          int16   ;   {SP-$0032, bits =   16}
  645.           Parm  4:          UInt16  )   {SP-$0036, bits =   16}
  646.        uncheckable_anyvar
  647.  
  648.  Note that the buffer parameter is a "LongAddr" that is passed in
  649.  both R23 and R24 (the first is the space and the second is the
  650.  offset).  Fortunately, it is still easy to see the contents of
  651.  the buffer.  If we were at a breakpoint at the start of FWRITE,
  652.  we would display the buffer with:
  653.  
  654.       nmdebug >dv r23.r24,20,s     {display buffer contents}
  655.  
  656.  
  657.  Integers:  16-bit versus 32-bit
  658.  
  659.  Cmdebug displays integers in octal as 16-bit quantities.  Nmdebug
  660.  displays integers in hex as 32-bit quantities.  In our FWRITE
  661.  example, it is easy to see the value of the length parameter.
  662.  
  663.       nmdebug >dv sp-32,1      {display the length}
  664.       $ 00005f00
  665.  
  666.  We used the DV (Display Virtual) Command to display the stack
  667.  contents.  The ",1" is not necessary - it's the default, but we
  668.  have shown it to make the following examples a little clearer.
  669.  The "dv sp-32" displays the value at sp-32 as a 32-bit quantity,
  670.  but we know that the actual value of FWRITE's length parameter is
  671.  a 16-bit quantity.  You can display two 16-bit integers using the
  672.  following:
  673.  
  674.       nmdebug >dv sp-32,1,,,2  {display two 16-bit integers}
  675.       $ 0000 5f00
  676.       nmdebug >dv sp-32,1,#,,2 {display two integers in decimal}
  677.       #      0  24320
  678.  
  679.  Display Virtual always rounds down to a virtual address that is a
  680.  multiple of four and then displays one or more 32 bit words.
  681.  
  682.  
  683.  
  684.                         Miscellaneous Tips
  685.  
  686.  
  687.  
  688.  Setting a "Return" Breakpoint
  689.  
  690.  We showed how to set a return breakpoint in compatibility-mode.
  691.  You use a similar method to set a return breakpoint in
  692.  native-mode code:
  693.  
  694.       nmdebug >b extract_ready
  695.       nmdebug >c
  696.       .
  697.       .
  698.       .                       {break at extract_ready}
  699.       nmdebug >lev 1;b pc,-1  {-1 means only break once}
  700.       nmdebug >c              {continue execution}
  701.  
  702.  The only difference between a CM return breakpoint, and an NM
  703.  one, is the name of the program counter.  In native-mode it's
  704.  called "pc".  This sets a return breakpoint immediately after the
  705.  code that called extract_ready.  Note that it's safe to use this
  706.  breakpoint anywhere in the extract_ready procedure -- not just at
  707.  the beginning.
  708.  
  709.  
  710.  Debugging Batch Programs
  711.  
  712.  In Debug/V, there was no practical way to debug a program running
  713.  in batch.  In Debug/iX, you can debug a batch program on the
  714.  console, although it's a bit messy to set up.  You have to do
  715.  these steps:
  716.  
  717.  1. Obtain the pin number of the program you want to debug.
  718.     You'll need to use a program like Shot.Pub.Nuggets.  You can
  719.     use the Showproc Command, if you have MPE/iX version 2.1 or
  720.     later versions.
  721.  
  722.  2. Go to the console and insure that there will be no output on
  723.     the console.  The easiest way to do this is to initiate a
  724.     :Restore on the console.  This assumes that your tape drive is
  725.     not configured for auto-reply.  Do not reply to the tape
  726.     request.
  727.  
  728.          {On the console ...}
  729.          :hello user.acct
  730.          :restore
  731.  
  732.  3. On another terminal, log on with SM capability and enter
  733.     debug.  For example,
  734.  
  735.         :hello manager.sys
  736.         :debug
  737.  
  738.  4. Once you are inside Debug, you must set an environment
  739.     variable and force a breakpoint in the batch program.  Our
  740.     example assumes that the batch program will call the FWRITE
  741.     intrinsic:
  742.  
  743.          nmdebug >env job_debug true   {set special variable}
  744.          nmdebug >b FWRITE:pin#        {don't forget the pin#}
  745.  
  746.  You don't actually type "b FWRITE:pin#" when setting the
  747.  breakpoint.  You substitute the actual pin# that you obtained in
  748.  step 1 (e.g., "b FWRITE:103").
  749.  
  750.  When the batch program encounters the breakpoint, Debug/iX is
  751.  invoked and all Debug/iX input/output is done via the console.
  752.  On the console you can type any of the usual Debug/iX commands.
  753.  When you finish your debugging session, you'll need to remember
  754.  to abort the :Restore that you initiated.  You must also return
  755.  to the Manager.Sys session and disable job debugging:
  756.  
  757.       cmdebug >env job_debug false
  758.  
  759.  
  760.  Macros
  761.  
  762.  Debug/iX contains a small programming language that lets you
  763.  create your own macros.  Debug/iX has no command to skip over
  764.  procedure calls, although almost all PC-based debuggers have this
  765.  feature.  When single-stepping through a program, you rarely want
  766.  to single-step through external procedures (e.g., the Print
  767.  intrinsic).  Use the j macro to jump over the next native-mode BL
  768.  instruction.  Macros use braces for the body of the macro (i.e.,
  769.  as begin/end), so don't interpret the braces as comments.  Here
  770.  is how to declare the macro:
  771.  
  772.       nmdebug >mac j {b pc+$8,-1; c}
  773.  
  774.  Macros are declared with the Mac Command.  The first parameter to
  775.  the Mac Command is the macro name (in this case it's j).  The
  776.  body of the macro follows and is surrounded with braces.  Macros
  777.  can take several lines.  The j macro sets a breakpoint at the
  778.  next native-mode instruction after a branch-and-link "pc+$8".
  779.  The breakpoint is only executed once ",-1".  Multiple commands
  780.  are separated by semi-colons ";".  The last step of the macro is
  781.  to execute the Continue Command "c".  Note that the j macro is
  782.  only useful around branch-and-link instructions which is why we
  783.  jump eight bytes ahead of the program counter instead of four.
  784.  You execute the macro as if it were a built-in Debug/iX command:
  785.  
  786.       nmdebug >j
  787.  
  788.  
  789.  Vfilepages Macro
  790.  
  791.  When doing any performance measurements with disc files, you need
  792.  to know what portion of the file is in memory.  This macro takes
  793.  advantage of many features of Debug/iX.  The macro displays the
  794.  number of pages of a file that are currently present in virtual
  795.  memory.
  796.  
  797.       /*  Macro:   Vfilepages
  798.       /*
  799.       /*  Purpose: Display the number of pages (and corresponding
  800.       /*           sectors) of a file that are actually in memory.
  801.       /*
  802.       /*  Warning: Never use this macro on catalog.pub.sys.
  803.       /*
  804.  
  805.       mac vfilepages (filename:str) {
  806.          map !filename;
  807.          w !filename " contains ";
  808.          w vainfo(mapva(!filename),"pages_in_mem"):"D";
  809.          w " pages in memory = ";
  810.          w vainfo(mapva(!filename),"pages_in_mem")*#16:"D";
  811.          w " sectors";
  812.          wl;
  813.          unmap(mapindex(!filename));
  814.          }
  815.  
  816.  Lines starting with "/*" are treated as comments.  The "filename"
  817.  is a parameter to the macro and it's of string type.  To
  818.  understand the rest of the macro requires looking up the
  819.  description of the Map, Mapva, W, WL, and Unmap Commands and an
  820.  understanding of the Vainfo and Mapindex Function.  We'll leave
  821.  that up to you.  To invoke this macro, you would do the following
  822.  (note the quotes around the filename):
  823.  
  824.       vfilepages "file50.suprtest"
  825.       file50.suprtest contains 8 pages in memory = 128 sectors
  826.  
  827.  Warning:  Because this macro uses the Debug/iX Map Command, do
  828.  not use it on the file catalog.pub.sys.  If you do, you will
  829.  cause a system failure.
  830.  
  831.  
  832.  DBUGINIT File
  833.  
  834.  Once you start writing macros, you will want to have them
  835.  automatically loaded when you enter Debug/iX.  Debug/iX always
  836.  executes a use-file called DBUGINIT.  Debug/iX first looks for
  837.  this file in the same group and account as the program, then it
  838.  looks in the logon group and account.  Rather than fill our
  839.  DBUGINIT file with macros, we fill it with Use Commands for
  840.  different files that contain useful macros: You can use :file
  841.  commands for the DBUGINIT file, but you must use a fully
  842.  qualified filename.  For example:
  843.  
  844.       :hello david.dev,david
  845.       :print dbuginit.macro.dev
  846.       use splash.macro.splash
  847.       use macros.macro.dev
  848.       :file dbuginit.david.dev=debuginit.macro.dev
  849.       :run testprog;debug     {Debug/iX will use debuginit.macro}
  850.  
  851.  
  852.  :Setdump Command
  853.  
  854.  Classic MPE contains a :Setdump Command, but I believe most of us
  855.  ignored it because the traceback it printed was not symbolic.  If
  856.  you enable :setdump in MPE/iX, you not only get an excellent
  857.  symbolic traceback, but in native-mode you are placed into
  858.  Debug/iX (certain exceptions apply to privileged-mode programs).
  859.  
  860.  
  861.  MPE Commands
  862.  
  863.  You can enter almost any MPE command by preceding it with a
  864.  colon.  This includes UDCs and the :Run Command.  Often in the
  865.  middle of a debugging session, you need to examine your source
  866.  code.  An easier way to do this is to run your editor from within
  867.  Debug/iX.  One word of caution -- Debug/iX, like many HP
  868.  products, fails to see if a son process has terminated or
  869.  suspended.
  870.  
  871.  We also find it useful to invoke Cseq.Pub.Nuggets when we are
  872.  debugging a program.  This lets us determine the location of the
  873.  parameters for any MPE intrinsic:
  874.  
  875.       nmdebug >:cseq.pub.nuggets    {obtain parameter addresses}
  876.  
  877.  
  878.  Running Qedit from Debug/iX
  879.  
  880.  If you invoke Qedit from Debug/iX, be sure to run it with Parm=32
  881.  (this tells Qedit not to suspend on exit).  The most likely
  882.  reason to invoke Qedit from Debug/iX is to examine your source
  883.  code.  If you do not /Shut your file before running your program,
  884.  you will get "Error:  Busy file" when you try to open your file
  885.  inside Qedit (inside Debug/iX).  To get around the problem, you
  886.  can either /List your source code or /Text a copy.
  887.  
  888.  
  889.  Conclusion
  890.  
  891.  If you are going to make heavy use of Debug/iX, I strongly
  892.  recommend getting the System Debug Reference Manual.  While it's
  893.  not helpful for learning Debug/iX, it's invaluable in looking up
  894.  specific commands and their syntax.  That part number again is
  895.  #32650-90013.
  896.  
  897.  When I first set out to write this article, I thought that it
  898.  would only take me a few paragraphs to convey what I'd learned
  899.  about Debug/iX.  If you've got this far, you realize that I
  900.  underestimated the amount of material -- not surprising given the
  901.  rich feature set of Debug/iX.
  902.