home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.robelle3000.ai 2014
/
2014.06.ftp.robelle3000.ai.tar
/
ftp.robelle3000.ai
/
papers
/
nmdebug.pro
< prev
next >
Wrap
Text File
|
1994-04-28
|
47KB
|
1,327 lines
.comment File: NMDEBUG
.comment
.comment Purpose: The MPE/iX System Debugger Paper
.comment
.comment To print this document, do the following:
.comment
.comment :run printdoc.pub.robelle;info="NMDEBUG"
.comment
.com {ifout starts here}
.comment Choose the output device parameters for this document
.if outfinal
. if outrecord
. out(las 30 c1 r+ s7).com Robelle bound version, attached
. else
. out(las 30 c1 r- s7).com Robelle bound version
. endif
.elseif outhelpcomp
. out(lpt q+ w80).com helpcomp;parm=1
.elseif outa4
. if outlpt
. if outrecord
. out(lpt s7 r+).com A4 paper, $Stdlist/LP/disc, attached
. else
. out(lpt s7 r-).com A4 paper, $Stdlist/LP/disc
. endif
. elseif outlaser
. if outrecord
. if outdouble
. out(las 30 s8 r+ d+).com A4 paper, LaserJet, attached, duplex
. else
. out(las 30 s8 r+).com A4 paper, LaserJet, attached
. endif
. else
. if outdouble
. out(las 30 s8 r- d+).com A4 paper, LaserJet, duplex
. else
. out(las 30 s8 r-).com A4 paper, LaserJet
. endif
. endif
. else.com No other outxxx jcws specified
. out(lpt s7 r-).com generic: A4 paper, $Stdlist/LP/disc
. endif
.elseif outtext
. if outrecord
. out(lpt s0 u- r+)
. else
. out(lpt s0 u-)
. endif
.else
. if outlpt
. if outrecord
. out(lpt s3 r+).com Letter, $Stdlist/LP/disc, attached
. else
. out(lpt s3 r-).com Letter, $Stdlist/LP/disc
. endif
. elseif outlaser
. if outrecord
. if outdouble
. out(las 30 s7 r+ d+).com Letter, LaserJet, attached, duplex
. else
. out(las 30 s7 r+).com Letter, LaserJet, attached
. endif
. else
. if outdouble
. out(las 30 s7 r- d+).com Letter, LaserJet, duplex
. else
. out(las 30 s7 r-).com Letter, LaserJet
. endif
. endif
. else.com No outxxx jcws specified
. out(lpt s3 r-).com Letter, generic: $Stdlist/LP/disc
. endif
.endif
.comment
.comment Choose the fonts for this document
.if outfinal
. include final.qlibdata.green
.else
. include f92286f.qlibdata.robelle
.endif
.comment
.comment Choose the margins for this document
.comment
.if outhelpcomp
. mar(r78)
.elseif outa4
. mar(r62)
.else
. mar(r65)
.endif
.comment
.comment Choose the forms for this document
.comment
.comment Form 1 is for the body of the manual
.comment Form 2 is for unnumbered pages (end of section)
.comment Form 3 is for the table of contents (roman numerals)
.comment
.if outtext
. form(k1 [L8000] )
. form(k2 [L8000] )
. form(k3 [L8000] )
.elseif outa4
. form(k1 [ T #23 S:40 // l64 / #33 "-" pn:1 "-" /]
+ [ S #23 T:40 // l64 / #33 "-" pn:1 "-" /])
. form(k2 [ // l64 / #33 pr:3 /]).com Roman numerals
. form(k3 [ // l63 // ])
.else
. form(k1 [ T #26 S:40 // l55 / #33 "-" pn:1 "-" /]
+ [ S #26 T:40 // l55 / #33 "-" pn:1 "-" /])
. form(k2 [ // l55 / #33 pr:3 /]).com Roman numerals
. form(k3 [ // l54 // ])
.endif
.comment
.comment Option settings:
.comment
.comment For text output we want a ragged right edge.
.comment
.if outtext
. opt(j4 p+ b+ r-)
.else
. opt(j4 p+ b+).com Okay to insert four blanks between words
.comment when justifying, two spaces after period,
.comment suppress blank lines at top of page
.endif
.comment
.comment Other formatting parameters:
.par(f` p5 s1 u3) .com Automatic .skip 1.page 5.undent 3
.inp(u~ b@ h\ e& t# f|).com Underline,Blank,Hyphen,Escape,Tab,Font
.if not outtext
.page.count 1 .com Start page numbering over again.
.form 3
.jump 7
.opt(l- r- f-)
`|3The MPE/iX System Debugger|
|1By David J.@Greer|
`|1Abstract|
.opt
MPE/iX comes with a powerful debugger. For those of us who
have struggled with Debug/V, there are many great features
to look forward to. But, like all new software, there is a
learning curve in understanding the new MPE/iX debugger.
Attempting to find the dozen or so most useful features in
the three-inch stack of paper called the System Debugger
Reference Manual is impossible, unless you have three spare months.
In this article, I intend
to summarize the features I've found most useful.
.skip 10
.opt(l- r- f-)
.font 1
Robelle Consulting Ltd.
Unit 201, 15399-102A Ave.
Surrey, B.C. Canada V3R 7K1
Phone: (604) 582-1700
Fax: (604) 582-1799
Email: david_greer&@robelle.com
.font 0
Copyright Robelle Consulting Ltd. 1991,1994
Permission is granted to reprint this document (but ~not~
for profit), provided that copyright notice is given.
.opt.com Stop centering
.endif.com { not outtext }
.com The next FORM is for Contents/Preface:
.form 1
.contents(i+3)
.page.count 1
.jump 1
.opt(l- r- f-)
`|3The MPE/iX System Debugger|
|1By David J.@Greer, Robelle Consulting Ltd.|
.if outtext
Copyright Robelle Consulting Ltd. 1991,1994
Permission is granted to reprint this document (but ~not~
for profit), provided that copyright notice is given.
.endif
.opt
.ent `Introduction
MPE/iX comes with a powerful debugger. For those of us who
have struggled with Debug/V, there are many great features
to look forward to. But, like all new software, there is a
learning curve in understanding the new MPE/iX debugger.
Attempting to find the dozen or so most useful features in
the three-inch stack of paper called the System Debugger
Reference Manual is impossible, unless you have three spare months.
In this article, I intend
to summarize the features I've found most useful.
I am indebted to Stan Sieler of Allegro Consultants who taught
me much of what is presented in this article. To obtain the
maximum benefit from this article, you should try all of the
examples that are presented. Having both a CM- and an NM-program
available that calls the FWRITE intrinsic will make following the
examples that much easier.
If you are going to be a big user of Debug/iX, then you really
have to have the reference manual. Order part 羊-90013,
System Debug Reference Manual.
.tit |1MPE/iX Debugger|
.sub |1Native-Mode|
`|1Native-Mode or Compatibility-Mode|
.ent Native-Mode or Compatibility-Mode
HP was very kind to write not only a nice debugger for
native-mode programs, but include features for
debugging compatibility-mode programs too. When I first
attempted to debug a CM-program, I got so confused that I
returned to my classic HP 3000 where at least I knew all the
command names. The next section will show Debug/iX commands
for our old favorite Debug/V commands.
.sub |1Debug/V Versus Debug/iX|
`|1Debug/V Versus Debug/iX|
.ent Debug/V Versus Debug/iX
Just like Debug/V, you can invoke Debug/iX by including the
keyword "Debug" on the :Run Command for your program. Debug/iX
responds with its "CM" prompt:
.font 5
:run testprog;debug
CM DEBUG Intrinsic: PROG %6.3542
cmdebug >
.font 0
If you have a Pmap (or Robelle's Qmap), you can set a breakpoint
just as you would in Debug/V -- using |2segment.offset|:
#6|5cmdebug >B 0.45|
Anyone who has struggled with Pmaps knows how convenient it would
be if the system debugger took advantage of the FPMAP information
stored in program files. With this information it should be
possible to set a breakpoint by |1procedure name|. Debug/iX
lets you either set a symbolic breakpoint at the first logical
instruction in your procedure or at the more useful entry-point:
.page 4
.font 5
cmdebug >B open'input'file |0{first instruction}|
cmdebug >B ?open'input'file |0{? implies entry point}|
cmdebug >B open'input'file+255 |0{octal offset from first}|
cmdebug >c |0{Continue = Resume}|
.font 0
.sub |1Breakpoints|
`|1Breakpoints|
.ent Breakpoints
In the last ten years, I have probably lost over a month of time
from one horrible default in Debug/V. In Debug/V, the Break
Command would only break the first time it encountered the
breakpoint, unless you added ":&@" to the Break Command.
In Debug/iX the default is to always break. Occasionally, you
only want the breakpoint to be invoked once. Use ",-1" after
the break location to have the breakpoint removed after one
occurrence:
|5#6nmdebug >b ?open'input'file,-1 |0{break once}|
.sub |1Clearing Breakpoints|
`|1Clearing Breakpoints|
.ent Clearing Breakpoints
In Debug/V, the Clear Command disables breakpoints that have been set
with the Break Command. In Debug/iX, use the BD (Breakpoint Delete)
Command to remove breakpoints:
.font 5
nmdebug >bd |0{You will be asked for which one}|
nmdebug >bd &@ |0{Delete all breakpoints}|
.font 0
.sub |1Return Breakpoint|
`|1Setting a "Return" Breakpoint|
.ent Setting a "Return" Breakpoint
One of the most useful breakpoints is the one immediately after
a procedure call. Suppose that your program calls the procedure
|5extract_ready|. You want to know the result of |5extract_ready|, so
you would like a breakpoint in the calling code immediately after
the call to |5extract_ready|. You do the following:
.font 5
cmdebug >b ?extract_ready
cmdebug >c
.
.
. |0{break at |5extract_ready|}|
cmdebug >lev 1;b p,-1 |0{-1 means only break once}|
cmdebug >c |0{continue execution}|
.font 0
The "lev 1" goes back to the previous logical level in the
calling sequence (use "tr,d" to see a complete traceback). The "b p"
sets a breakpoint at the compatibility-mode program counter.
The "lev 1" places the program counter at the instruction
|2after| the one that called the current procedure. The ",-1" tells
Debug/iX to execute the breakpoint once and then throw it away.
Note that it's safe to use this breakpoint anywhere in the
|5extract_ready| procedure -- not just at the beginning.
What if we are in native-mode code (e.g., FWRITE)? Our return
breakpoint won't work, since we called FWRITE from
compatibility-\mode. To set a return breakpoint in this case,
first switch into cmdebug:
.font 5
cmdebug >b ?FWRITE
cmdebug >c
.
.
. |0{break at NM FWRITE}|
nmdebug >cm |0{switch into CM}|
cmdebug >lev 1;b p,-1 |0{set return breakpoint}|
cmdebug >c |0{continue execution}|
.font 0
.sub |1Abort Command|
`|1Abort Command -- Getting Out of Debug|
.ent Abort Command
You can terminate your program with the Abort Command. Use this
any time that Debug/iX is prompting for commands.
The Debug/iX Abort Command is similar to the Debug/V E&@ Command.
.sub |1Displaying Values|
`|1Displaying Values|
.ent Displaying Values
When I first used Debug/iX, I became totally confused about how
to display the usual DB-, Q-, and S-relative values. It turns
out to be very simple.
In
Debug/V the Display Command takes the register as a
parameter.
In Debug/iX there are separate command
names for displaying values relative to each register.
Here are the Debug/V and Debug/iX Display Commands:
.font 5
~Debug/V~ ~Debug/iX~
D DB DDB
D S DS
D Q DQ
.font 0
The Debug/iX Display Command has a count as its second parameter (just
like Debug/V), but the display attribute is different.
Here is the comparison:
.font 5
~Debug/V~ ~Debug/iX~ ~Description~
,I , or D Decimal
,O ,% or O Octal |0{default in CM}|
,H ,$ or H Hexadecimal |0{default in NM}|
,A ,S Ascii/String
.font 0
Instead of S, you can also use A for displaying string values.
The A-option is closer to the A-option of Debug/V, but we find
the S-option more useful.
By default, the S-option displays all
characters you request and only displays the virtual address of
the string once. If you want to see as many characters per line
as possible, with each new line starting with the virtual address
of the characters displayed, use this command:
#6|5cmdebug >dq 104,200,s,e |0{"e" shows addresses}|
.sub |1Symbolic Machine Code|
`|1Symbolic Machine Code|
.ent Symbolic Machine Code
Our list above doesn't show you how to display the actual
run-time machine instructions (commonly called decompiling).
That's because Debug/iX has many excellent features to
symbolically display code. While you can use the DC (Display
Code) Command to show symbolic code, we have found a better method
-- windows.
.sub |1Symbolic Traceback|
`|1Symbolic Traceback|
.ent Symbolic Traceback
The Debug/V Trace Command was almost useless. You had
to manually work through the segment numbers and offsets to
figure out the true procedure names. The Debug/iX
Trace Command produces a proper symbolic traceback of
procedure names.
You can also use the traceback to observe switches from
native-mode to compatibility-mode. For example, if you have
SM capability you can set a breakpoint in any system SL or
system XL routine. KSAM files come in two flavors:
CM and NM. If you access a
CM KSAM file from a NM program, MPE/iX
calls the CM FWRITE intrinsic. You can easily prove this to
yourself by setting a breakpoint in the CM FWRITE intrinsic:
.font 5
:run testprog;debug |0{NM program to read CM KSAM file}|
nmdebug >cmdebug |0{switch to CM}|
cmdebug >b ?FWRITE |0{question-mark for entry point}|
cmdebug >c |0{continue execution}|
.
.
. |0{note the ",d" on the TR Command}|
cmdebug >tr,d |0{traceback showing switches}|
.font 0
.page.jump 1
.sub |1WON Command|
.opt(f-l-r-)
`|3Compatibility-Mode Windows|
.opt
.ent `Compatibility-Mode Windows
The WON Command is the real power of Debug/iX.
WON is short for Windows On. When you turn windows on, the top
portion of the screen is reserved for a symbolic display of the
currently executing code, another
portion displays register and/or
stack values, and the bottom of the screen is used to enter
commands. This is a very powerful feature.
.sub |1CM Window Example|
`|1CM Window Example|
.ent CM Window Example
The following is an example compatibility-mode window. We first
set a breakpoint, continue to that breakpoint, and finally we
turn windows on.
.page 6
.font 5
cmdebug >b ?input'command |0{break at the entry point}|
cmdebug >c |0{continue execution}|
.
.
.
cmdebug >won |0{turn windows on}|
.font 0
.com Outlined Shape at column 7. 51 columns wide and 23 rows high.
.break.page 25.com Does .INP use * ??
The top three lines of the display show the register information:
.skip 1
.if outtext or outlpt then
. mar(r100).opt(f-)
R % Regs DB=001200 DBDST=001632 X=000002 STATUS=(mITroC CCG 007) PIN=051
SDST=001627 DL=177450 Q=023620 S=023620 CMPC=PROG 000006.006711
CIR=035004 MAPFLAG=0 MAPDST=000000
FcmP % PROG 6.6711 (?) SETUP CSTX 7 Level 0
006707: INPUT'COMMAND+%437 031031 2. PCAL ?ERRX
006710: INPUT'COMMAND+%440 032000 4. SXIT 0
006711: [1]> ?INPUT'COMMAND 035004 :. ADDS 4
006712: INPUT'COMMAND+%442 171700 .. LRA S-0
006713: INPUT'COMMAND+%443 051401 S. STOR Q+1
006714: INPUT'COMMAND+%444 035023 :. ADDS %23
006715: INPUT'COMMAND+%445 041401 C. LOAD Q+1
Q % (DB mode) QDST=001627 Level 0
023610: 000000 047420 061006 000006 177600 D000002@ D00364
023620:Q>D000014@<S
023630:
S % (DB mode) SDST=001627 Level 0
023610: 000000 047420 061006 000006 177600 D000002@ D00364
023620:Q>D000014@<S
Commands
%47 (%103) cmdebug >
.else
. box(c+8 w50 r-0+ h22+)
. font 6.mar(l+8 r108).opt(f-)
R % Regs DB=001200 DBDST=001632 X=000002 STATUS=(mITroC CCG 007) PIN=051 <-&|
SDST=001627 DL=177450 Q=023620 S=023620 CMPC=PROG 000006.006711 &| R Window
CIR=035004 MAPFLAG=0 MAPDST=000000 <-&|
FcmP % PROG 6.6711 (?) SETUP CSTX 7 Level 0 <-&|
006707: INPUT'COMMAND+%437 031031 2. PCAL ?ERRX &|
006710: INPUT'COMMAND+%440 032000 4. SXIT 0 &| CmP
006711: [1]> ?INPUT'COMMAND 035004 :. ADDS 4 &| Window
006712: INPUT'COMMAND+%442 171700 .. LRA S-0 &|
006713: INPUT'COMMAND+%443 051401 S. STOR Q+1 &|
006714: INPUT'COMMAND+%444 035023 :. ADDS %23 &|
006715: INPUT'COMMAND+%445 041401 C. LOAD Q+1 <-&|
Q % (DB mode) QDST=001627 Level 0 <-&|
023610: 000000 047420 061006 000006 177600 D000002@ D00364 &| Q
023620:Q>D000014@<S &| Window
023630: <-&|
S % (DB mode) SDST=001627 Level 0 <-&|
023610: 000000 047420 061006 000006 177600 D000002@ D00364 &| S
023620:Q>D000014@<S <-&| Window
Commands <-&|
&| Command
%47 (%103) cmdebug > <-&| Window
.endif
.font 0.opt.mar
For most of us, only the DL=, Q=, S=, and X= values are interesting.
If the DBDST and the SDST (the DB- and S- data segments) are
different, you are in split-stack mode.
Line four shows that
we are currently at location 6.6711 in the
program. The PROG would change if the breakpoint was inside an SL.
Next we see seven instructions. The "[1]" means breakpoint
number 1. The ">" symbol next to "?INPUT'COMMAND" shows the
next instruction to be executed. The bottom of the display shows
the values around the Q- and S- registers.
In our example, the Q and S registers are the same so the Q- and
S-displays are identical.
Finally, you are prompted for more
Debug/iX commands.
.sub |1Single-Stepping|
`|1Single-Stepping|
.ent Single-Stepping
One other command adds a lot of power to windows: S --
single-stepping. The S Command executes the next instruction, then
returns control to Debug/iX. After the execution, register and
stack values are updated and any changed values are highlighted.
Because the compatibility-mode window shows the top few words of
the stack, you can often get an instant picture of what is going
on.
Here is the first window after executing one single-step:
.font 5.page 25
cmdebug >s |0{single-step}|
.com Outlined Shape at column 7. 51 columns wide and 23 rows high.
.break.page 23.com Does .INP use * ??
.if outtext or outlpt then
. mar(r100).opt(f-)
.else
. box(c+8 w50 r-0+ h22+)
. font 6.mar(l+8 r108).opt(f-)
.endif
R % Regs DB=001200 DBDST=001632 X=000002 STATUS=(mITroC CCG 007) PIN=1
SDST=001632 DL=177450 Q=023620 S=023624 CMPC=PROG 000006
CIR=171700 MAPFLAG=0 MAPDST=000000
cmP % PROG 6.6712 (?) SETUP CSTX 7 Level 0
006707: INPUT'COMMAND+%437 031031 2. PCAL ?ERRX
006710: INPUT'COMMAND+%440 032000 4. SXIT 0
006711: [1] ?INPUT'COMMAND 035004 :. ADDS 4
006712: > INPUT'COMMAND+%442 171700 .. LRA S-0
006713: INPUT'COMMAND+%443 051401 S. STOR Q+1
006714: INPUT'COMMAND+%444 035023 :. ADDS %23
006715: INPUT'COMMAND+%445 041401 C. LOAD Q+1
Q % (DB mode) QDST=001632 Level 0
023610: 000000 047420 061006 000006 177600 000002 00364
023620:Q>000014 000002 006712 062007 &d
023630:
S % (DB mode) SDST=001632 Level 0
023610: 000000 047420 061006 000006 177600 000002 00364
023620:Q>000014 000002 006712 062007<S
Commands
%47 (%103) cmdebug >
.font 0.mar.opt
The ">" symbol has moved forward by one instruction. The register
values have been updated and the top of stack has changed because
we added four to the S-register.
.sub |1Set CRON|
`|1Set CRON|
.ent Set CRON
This sounds like the title of a futuristic movie, but when
combined with single-stepping it can be very powerful. Once you
start using the S (Single-Step) Command, you'll find yourself
typing it a lot, especially when debugging NM programs where you
have a lot more instructions per source code statement.
Fortunately, the Debug/iX designers already thought of this. When
you Set CRON, hitting Return tells Debug/iX "execute the last
command that I typed". This is most useful when your last
command was S, but it applies to |1any| command:
.font 5
cmdebug >set cron |0{Return = last-command}|
cmdebug >s |0{single-step}|
cmdebug > |0{another single-step!|}
cmdebug > |0{and one more}|
cmdebug > |0{and so on}|
.font 0
.sub |1Multiple Steps|
`|1Multiple Steps|
.ent Multiple Steps
While single-stepping is useful, it can be very slow. You can
step through a program faster using multiple instructions for
every step. The following example shows how to step through
every seven executed instructions.
Note: you must have a space after the Step Command and
before the number of instructions to execute (e.g., "S7" is
invalid):
.font 5
cmdebug >set cron |0{Return = last-command}|
cmdebug >s 7 |0{execute seven instructions|}
cmdebug > |0{another seven!|}
cmdebug > |0{and seven more}|
cmdebug > |0{and so on}|
.font 0
.page.jump 1
.sub |1Native-Mode Debugging|
.opt(l- r- f-)
`|3Native-Mode Debugging|
.opt
.ent `Native-Mode Debugging
Much of what has been discussed applies to native-mode. There
are a few minor differences:
.mar(l+3)
`1.#4You don't need to specify Fpmap (or any other magic
parameter) on the :Link Command. Procedure name and location
information is automatically included in all NM program files.
`2.#4Since the first
instruction of a procedure and its entry point are the same, you
never need to use a question mark.
If you happen to type a question mark, Debug/iX may not print an
error. In this case, you will have set a breakpoint in a stub
procedure. Since you almost never want to do this, it's important
to remember not to type the question mark before the procedure name.
`3.#4In most programming languages, any separators
(e.g., apostrophes) used in
procedure names will now become underbars.
.mar
Here is our previous breakpoint example in native-mode:
#6|5nmdebug >b open_input_file |0{break at procedure entry}
.sub |1Case Sensitivity|
`|1Case Sensitivity|
.ent Case Sensitivity
It is easy to see that portions of MPE/iX were affected by UNIX
and the C programming language. In UNIX and C, case is
significant (i.e., upper-case and lower-case are not the same).
When setting breakpoints in native-mode code, it
is important to remember this. Most MPE/iX routine names are in
upper-case. The most well-known exceptions are all of the IMAGE
and VPLUS intrinsics which are in lower-case. The following
example results in a Debug/iX error:
#6|5nmdebug >b fwrite |0{not found; lower-case}|
`|1Switching Modes|
.ent Switching Modes
.sub |1Switching Modes|
Sometimes you want to switch between CM-debug and NM-debug. For
example, the NM-FWRITE intrinsic calls the CM-FWRITE intrinsic
for certain types of files (e.g., circular). These commands
would set breakpoints in both the CM- and NM-FWRITE intrinsics:
.font 5
nmdebug >b FWRITE |0{NM-FWRITE breakpoint}|
nmdebug >cm |0{switch into cmdebug}|
cmdebug >b ?FWRITE |0{CM-FWRITE breakpoint}|
cmdebug >nm |0{switch back into nmdebug}|
nmdebug >c |0{continue execution}|
.font 0
.page.jump 1
.sub |1Native-Mode Windows|
.opt(f-l-r-)
`|3Native-Mode Windows|
.opt
.ent `Native-Mode Windows
The WON (Windows On) Command is just as powerful in native-mode
as in compatibility-mode. The display is different -- instead of
the old familiar DB, S, and Q registers, there is a strange group of
32 "general-purpose" registers. The code looks a lot different
too -- those famous RISC instructions instead of our old faithful
Classic 3000 ones.
.sub |1NM Window Example|
`|1NM Window Example|
.ent NM Window Example
We will show an example native-mode window, by setting a breakpoint
for the FWRITE intrinsic:
.font 5.page 15
nmdebug >b FWRITE |0{requires SM capability}|
nmdebug >c |0{continue execution}}|
.
.
.
nmdebug >won |0{turn windows on}|
.com Outlined Shape at column 7. 51 columns wide and 18 rows high.
.break.page 25.com Does .INP use * ??
.if outtext or outlpt then
. mar(r100).opt(f-)
GR$ ipsw=0006fe0f=jthlnxbCVmrQPDI priv=0 pc=0000000a.004a5fc0 pin=0000007a
r0 00000000 40100e20 004aee30 00000001 r4 c0000000 0000ffff 4033292a 00000000
r8 00000001 00000009 00000004 4034a880 r12 00000000 00000000 00000000 00000000
r16 00000000 00000000 00000000 c0000000 r20 c0000000 00000001 85240000 00000314
r24 40332604 000000d0 00000001 c0202008 r28 00000001 ffffffff 4034afd8 004aee30
nmP$ SYS a.4a5fb8 NL.PUB.SYS/FSPACE+$5a4 Level 0,0
004a5fb8: FSPACE+$5a4 e840c000 BV 0(2)
004a5fbc: FSPACE+$5a8 4fc33d31 LDWM -360(0,30),3
004a5fc0: [1]> FWRITE 6bc23fd9 STW 2,-20(0,30)
004a5fc4: FWRITE+$4 6fc30340 STWM 3,416(0,30)
004a5fc8: FWRITE+$8 6bc43cc9 STW 4,-412(0,30)
004a5fcc: FWRITE+$c 6bc53cd1 STW 5,-408(0,30)
004a5fd0: FWRITE+$10 6bc63cd9 STW 6,-404(0,30)
Commands
$7 ($1d) nmdebug >
.else
. box(c+8 w50 r-0+ h17+)
. font 6.mar(l+8 r108).opt(f-)
GR$ ipsw=0006fe0f=jthlnxbCVmrQPDI priv=0 pc=0000000a.004a5fc0 pin=0000007a <-&|
r0 00000000 40100e20 004aee30 00000001 r4 c0000000 0000ffff 4033292a 00000000 &| R
r8 00000001 00000009 00000004 4034a880 r12 00000000 00000000 00000000 00000000 &| Window
r16 00000000 00000000 00000000 c0000000 r20 c0000000 00000001 85240000 00000314 &|
r24 40332604 000000d0 00000001 c0202008 r28 00000001 ffffffff 4034afd8 004aee30 <-&|
nmP$ SYS a.4a5fb8 NL.PUB.SYS/FSPACE+$5a4 Level 0,0 <-&|
004a5fb8: FSPACE+$5a4 e840c000 BV 0(2) &|
004a5fbc: FSPACE+$5a8 4fc33d31 LDWM -360(0,30),3 &| NmP
004a5fc0: [1]> FWRITE 6bc23fd9 STW 2,-20(0,30) &| Window
004a5fc4: FWRITE+$4 6fc30340 STWM 3,416(0,30) &|
004a5fc8: FWRITE+$8 6bc43cc9 STW 4,-412(0,30) &|
004a5fcc: FWRITE+$c 6bc53cd1 STW 5,-408(0,30) &|
004a5fd0: FWRITE+$10 6bc63cd9 STW 6,-404(0,30) <-&|
Commands <-&| Command
&| Window
$7 ($1d) nmdebug > <-&|
.endif
.font 0.mar.opt
The first line contains general information about the process
(e.g., the pin number).
The pc= is the program counter (notice it's a full 64-bit address in
|2space.offset| format).
Lines two through four of the display show
all 32 general-purpose registers.
The fifth line shows where the first instruction in the window
is located (in
NL.\Pub.\Sys &@ FSPACE+$5a4).
The native-mode instructions are shown, along with the breakpoint
number "[1]" and the next instruction to be executed is marked with the
">".
There are two commands that
can be a big benefit in examining the code "around" a breakpoint:
PB (Program Back) and PF (Program Forward).
.sub |1Paging|
`|1Paging|
.ent Paging
Debug/iX windows have to display all their information in the
twenty-four lines on a standard terminal screen. By default, the
size of the symbolic instruction list is seven
instructions. Especially when you are single-stepping through
instructions, it is very useful to see the previous seven
instructions or the next seven. The PB (Program Back) Command displays
the previous seven instructions and the PF (Program Forward) Command
shows the next seven. While seven instructions is the default,
there are commands to change the size of the program window.
If you have changed the size, Program Back and Program Forward adjust
themselves to the new window size.
.font 5
nmdebug >pf |0{program forward}|
nmdebug >pb |0{program back}|
.font 0
.sub |1PL Command|
`|1PL Command|
.ent PL Command
If you want to change the number of program instructions on the
screen, use the PL Command (Program List). The PL Command assumes
that the number of lines you want is in the current base.
Therefore, PL 10 means 16 instructions in NM Debug and 8 instructions
in CM Debug. To get around the problem, we always specify the
number of instructions in decimal:
#6|5nmdebug >pl |0{show "ten" instructions}|
.page.jump 1
.sub |1Procedure Parameters|
.opt(f-l-r-)
`|3Native-Mode Procedure Parameters|
.opt
.ent Native-Mode Procedure Parameters
.com <djg> Longer introduction here?
Long-time users of Debug/V know how to anticipate where
procedure parameters will be located. For example, if
we had a procedure with this declaration:
.font 5.page 5
integer procedure convint(buf,len); !result = Q-6
value len;
integer len; !len = Q-4
byte array buf; !&@buf = Q-5
.font 0
In CM-debug, we would look at the parameters as follows:
.font 5.page 5
cmdebug >dq -6 |0{result of Convint procedure}|
cmdebug >dq -4 |0{length of buffer}|
cmdebug >dq -5 |0{address of buffer}|
Q-%5 % 000104 |0{must use this value below}|
cmdebug >ddb 104/2,10,s |0{print actual buffer contents}|
.font 0
Notice that we had to divide the value at Q-5 (i.e., %104)
by two, since the
buffer was passed as a byte address. In native-mode, this irritation
disappears (except for those using SPLash! to emulate Classic
byte addressing).
.sub |1Calling Conventions|
`|1Native-Mode Calling Conventions|
.ent NM Calling Conventions
With the power to set breakpoints symbolically, by just knowing
the name of a procedure, there is even more incentive to be able
to guess the location of procedure parameters. NM procedures are
allocated registers for the first four parameters, but they are
allocated left-to-right -- the opposite of CM procedures. The
first parameter is assigned to Register-26, the second to
Register-25, the third to Register-24, the fourth to Register-23,
and any remaining parameters are stored on the NM stack.
The return value is in Register-28 (and Register-29 for 64-bit
values).
For native-mode, you would think of the declaration for Convint as:
.font 5.page 5
integer procedure convint(buf,len); !result = R28
value len;
integer len; !len = R25
byte array buf; !&@buf = R26
.font 0
If you have windows on, the 32 general-purpose registers are
always displayed. The only problem area is the buffer parameter:
.font 5.page 8
nmdebug >b convint |0{note lower-case}|
nmdebug >won |0{windows on}|
nmdebug >c |0{continue execution}|
.
.
. |0{debug breaks &@ convint}|
nmdebug >=r25 |0{display the length}|
nmdebug >dv r26,10,s |0{display virtual uses the contents}|
|0{of register 26 as an address}|
.font 0
.sub |1Variables|
`|1Variables|
.ent Variables
Debug/iX contains a programming language. We won't try and
cover all of the features of this language, but variables are so
powerful that they are worth knowing about.
In our example with the Convint procedure,
suppose that the
buffer you are passing to Convint is a global variable. Setting the
breakpoint at Convint gives you a convenient method to find and
save the address of your buffer so that you can use it at any
breakpoint.
.font 5.page 8
nmdebug >var buf_var=r26 |0{save address of buffer}|
nmdebug >dv buf_var,10,s |0{display buffer contents}|
nmdebug >c |0{continue execution}|
.
.
. |0{sometime much later ...}|
nmdebug >dv buf_var,10,s |0{display the buffer contents}|
.font 0
The final Display Virtual Command displays the contents of the buffer
using the address that we saved. When the breakpoint takes place,
we may have no convenient way of finding the
program variable that has the
address of our buffer. Because we have saved the
address in the Debug/iX variable "buf_var",
we display the buffer contents without knowing where the
address is stored.
.sub |1Virtual Addresses|
`|1Virtual Addresses|
.ent Virtual Addresses
So far, we have assumed that all addresses are 32-bits. In MPE/iX,
addresses are actually 64-bits. Debug/iX shows these addresses
as |2space.offset|. If you are working with mapped files, you
will find that the full 64-bit address suddenly becomes important.
The following example opens a file with mapped access, saves the
virtual address of the file into a variable, and then displays the
actual contents of the file.
.font 5.page 5
nmdebug >map "file1.suprtest" |0{open an mpe file mapped}|
nmdebug >var fileaddr = mapva("file1.suprtest")
nmdebug >=fileaddr |0{display the virtual address}|
.font 0
Debug/iX has a built-in calculator that accepts any
Debug/iX expression.
You invoke the calculator with an equal sign "=". Debug/iX
evaluates the calculator expression and prints the result.
The calculator will display the full 64-bit address of
"file1.suprtest" as
|2space.offset|.
You can display the actual contents of the file:
#6|5nmdebug >dv fileaddr,20,s |0{first 20-bytes of file}|
.font 1
Warning: Due to a very serious bug in MPE/iX, never, never, never
do this on the file Catalog.\Pub.\Sys. If you open Catalog.\Pub.\Sys
with mapped access, you will cause a system failure.
.font 0
The map command displays the virtual address of a file in
|2space.offset| format. You can use the DV (Display Virtual)
Command to display the file contents or you can use our
method. We prefer using a variable and mapva function, since typing
in a full 64-bit address correctly is quite difficult.
.sub |1Cseq.Pub.Nuggets|
`|1Cseq.Pub.Nuggets|
.ent Cseq
While it is easy to predict the layout of parameters in our
simple example, things can get more complicated in MPE/iX. For
example, addresses can be passed as 64-bit quantities instead of
the default 32-bit values. The best way I've found to determine
parameter location is to use the Cseq (~c~alling ~seq~uence}
utility in the Nuggets collection (available from Software
Research Northwest 206-463-3030). Here is the Cseq output for
the FWRITE intrinsic:
.font 5.page 8.mar(r+5)
Procedure FWRITE (
Parm 1: int16 ; |0{R26, #bits = 16}|
Parm 2: anyvar record ; |0{(skip 25) R23, R24}|
|0{#bits = 65536}|
|0{Address type = LongAddr}|
Parm 3: int16 ; |0{SP-$0032, #bits = 16}|
Parm 4: UInt16 ) |0{SP-$0036, #bits = 16}|
uncheckable_anyvar
.font 0.mar
Note that the buffer parameter is a "LongAddr" that is passed in
both R23 and R24 (the first is the space and the second is the
offset). Fortunately, it is still easy to see the contents of the
buffer. If we were at a breakpoint at the start of FWRITE, we
would display the buffer with:
.font 5
nmdebug >dv r23.r24,20,s |0{display buffer contents}|
.font 0
.sub |1Integers: 16-bit versus 32-bit|
`|1Integers: 16-bit versus 32-bit|
.ent Integers
Cmdebug displays integers in octal as 16-bit quantities. Nmdebug
displays integers in hex as 32-bit quantities. In our FWRITE
example, it is easy to see the value of the length parameter.
.font 5
nmdebug >dv sp-32,1 |0{display the length}|
$ 00005f00
.font 0
We used the DV (Display Virtual) Command to display the stack
contents. The ",1" is not necessary - it's the default, but we
have shown it to make the following examples a little clearer.
The "dv sp-32" displays the value at sp-32 as a 32-bit quantity,
but we know that the actual value of FWRITE's length parameter is
a 16-bit quantity. You can display two 16-bit integers using the
following:
.font 5
nmdebug >dv sp-32,1,,,2 |0{display two 16-bit integers}|
$ 0000 5f00
nmdebug >dv sp-32,1,,,2 |0{display two integers in decimal}|
0 24320
.font 0
Display Virtual always rounds down to a virtual address that is
a multiple of four and then displays one or more 32 bit words.
.page.jump 1
.sub Miscellaneous Tips
.opt(f-l-r-)
`|3Miscellaneous Tips|
.opt
.ent `Miscellaneous Tips
.sub |1Return Breakpoint|
`|1Setting a "Return" Breakpoint|
.ent Setting a "Return" Breakpoint
We showed how to set a return breakpoint in compatibility-\mode.
You use a similar method to set a return breakpoint in native-mode
code:
.font 5
nmdebug >b extract_ready
nmdebug >c
.
.
. |0{break at |5extract_ready|}|
nmdebug >lev 1;b pc,-1 |0{-1 means only break once}|
nmdebug >c |0{continue execution}|
.font 0
The only difference between a CM return breakpoint, and an NM one, is
the name of the program counter. In native-mode it's called "pc".
This sets a return breakpoint immediately after the
code that called |5extract_ready|. Note that it's safe to use this
breakpoint anywhere in the |5extract_ready| procedure -- not just
at the beginning.
.sub |Debugging Batch Programs|
`|1Debugging Batch Programs|
.ent Debugging Batch Programs
In Debug/V, there was no practical way to debug a program running
in batch. In Debug/iX, you can debug a batch program on the
console, although it's a bit messy to set up. You have to do these
steps:
.mar(l+3)
`1.#4Obtain the pin number of the program you want to debug. You'll
need to use a program like Shot.\Pub.\Nuggets.
You can use the Showproc Command, if you have MPE/iX version 2.1 or
later versions.
`2.#4Go to the console and insure that there will be no output
on the console. The easiest way to do this is to initiate a
:Restore on the console. This assumes that your tape drive is
not configured for auto-reply. Do not reply to the tape
request.
.font 5
{On the console ...}
:hello user.acct
:restore
.font 0
`3.#4On another terminal,
log on with SM capability and enter debug. For example,
.font 5
:hello manager.sys
:debug
.font 0
`4.#4Once you are inside Debug, you must set an environment
variable and force a breakpoint in the batch program. Our
example assumes that the batch program will call the FWRITE
intrinsic:
.font 5
nmdebug >env job_debug true |0{set special variable}|
nmdebug >b FWRITE:|2pin| |0{don't forget the pin}|
.font 0
.mar
You don't actually type "b FWRITE:pin" when setting the
breakpoint. You substitute the actual pin that you obtained in
step 1 (e.g., "b FWRITE:|2103|").
When the batch program encounters the breakpoint, Debug/iX is
invoked and all Debug/iX input/output is done via the console. On
the console you can type any of the usual Debug/iX commands.
When you finish your debugging session, you'll need to remember to
abort the :Restore that you initiated.
You must also return to the Manager.Sys session and disable job
debugging:
.font 5
cmdebug >env job_debug false
.font 0
.sub |1Macros|
`|1Macros|
.ent Macros
Debug/iX contains a small programming language that lets you create
your own macros.
Debug/iX has no command to skip over procedure calls,
although almost all
PC-based debuggers have this feature. When single-stepping
through a program, you rarely want to single-step through external
procedures (e.g., the Print intrinsic). Use the |2j| macro to
jump over the next native-mode BL instruction.
Macros use braces for the body of the macro (i.e., as begin/end),
so don't interpret
the braces as comments.
Here is how to
declare the macro:
#6|5nmdebug >mac j {b pc+$8,-1; c}
Macros are declared with the Mac Command.
The first parameter to the Mac Command is the macro name (in this
case it's |2j|). The body of the macro follows and is surrounded
with braces.
Macros can take several lines. The |2j| macro sets a breakpoint
at the next native-mode instruction after a branch-and-link
"pc+$8". The breakpoint is
only executed once ",-1".
Multiple commands are separated by semi-colons ";". The last
step of the macro is to execute the Continue Command "c".
Note that the |2j| macro is only useful around branch-and-link
instructions which is
why we jump eight bytes ahead of the program
counter instead of four.
You execute the macro as if it were a built-in Debug/iX command:
#6|5nmdebug >j|
`|1Vfilepages Macro|
.ent Vfilepages Macro
When doing any performance measurements with disc files, you
need to know what portion of the file is in memory. This macro
takes advantage of many features of Debug/iX.
The macro displays the number of pages of a file that are
currently present in virtual memory.
.font 5.page 5
/* Macro: Vfilepages
/*
/* Purpose: Display the number of pages (and corresponding
/* sectors) of a file that are actually in memory.
/*
/* Warning: Never use this macro on catalog.pub.sys.
/*
mac vfilepages (filename:str) {
map !filename;
w !filename " contains ";
w vainfo(mapva(!filename),"pages_in_mem"):"D";
w " pages in memory = ";
w vainfo(mapva(!filename),"pages_in_mem")*:"D";
w " sectors";
wl;
unmap(mapindex(!filename));
}
.font 0
Lines starting with "/*" are treated as comments. The "filename"
is a parameter to the macro and it's of string type. To understand
the rest of the macro requires looking up the description of the
Map, Mapva, W, WL, and Unmap
Commands and an understanding of the Vainfo and Mapindex
Function. We'll leave that up to you. To invoke this macro, you would
do the following (note the quotes around the filename):
.font 5
vfilepages "file50.suprtest"
file50.suprtest contains 8 pages in memory = 128 sectors
.font 0
.font 1
Warning: Because this macro uses the Debug/iX Map Command, do
not use it on the file catalog.pub.sys. If you do, you will cause
a system failure.
.font 0
`|1DBUGINIT File|
.ent DEBUGINIT File
Once you start writing macros, you will want to have them
automatically loaded when you enter Debug/iX. Debug/iX always
executes a use-file called DBUGINIT. Debug/iX first looks
for this file in
the same group and account as the program, then it looks in the
logon group and account. Rather than fill our DBUGINIT file with
macros, we fill it with Use Commands for different files that
contain useful macros:
You can use :file commands for the DBUGINIT file,
but you must use a fully qualified filename. For example:
.font 5.mar(r+5)
:hello david.dev,david
:print dbuginit.macro.dev
use splash.macro.splash
use macros.macro.dev
:file dbuginit.~david~.dev=debuginit.macro.dev
:run testprog;debug |0{Debug/iX will use debuginit.macro}|
.font 0.mar
.sub |1:Setdump Command|
`|1:Setdump Command|
.ent :Setdump Command
Classic MPE contains a :Setdump Command, but I believe most of us
ignored it because the traceback it printed was not symbolic. If
you enable :setdump in MPE/iX, you not only get an excellent
symbolic traceback, but in native-mode you are placed into
Debug/iX (certain
exceptions apply to privileged-\mode programs).
.sub |1MPE Commands|
`|1MPE Commands|
.ent MPE Commands
You can enter almost any MPE command by preceding it with a colon. This
includes UDCs and the :Run Command. Often in the middle of a
debugging session, you need to examine your source code. An
easier way to do this is to run your editor from within Debug/iX.
One word of caution -- Debug/iX, like many HP products, fails to
see if a son process has terminated or suspended.
We also find it useful to invoke Cseq.\Pub.\Nuggets when we are
debugging a program. This lets us determine the location of the
parameters for any MPE intrinsic:
.font 5.mar(r+3)
nmdebug >:cseq.pub.nuggets |0{obtain parameter addresses}|
.font 0.mar
.sub |1Running Qedit|
`|1Running Qedit from Debug/iX|
.ent Running Qedit from Debug/iX
If you invoke Qedit from Debug/iX, be sure to run it with Parm=32
(this tells Qedit not to suspend on exit). The most likely reason
to invoke Qedit from Debug/iX is to examine your source code. If
you do not /Shut your file before running your program, you will
get "Error: Busy file" when you try to open your file inside Qedit
(inside Debug/iX). To get around the problem, you can either
/List your source code or /Text a copy.
.sub |1Conclusion|
`|1Conclusion|
.ent Conclusion
If you are going to make heavy use of Debug/iX, I strongly recommend
getting the System Debug Reference Manual. While it's not helpful for
learning Debug/iX, it's invaluable in looking up specific commands
and their syntax. That part number again is 羊-90013.
When I first set out to write this article, I thought that it
would only take me a few paragraphs to convey what I'd learned
about Debug/iX. If you've got this far, you realize that I
underestimated the amount of material -- not surprising given the
rich feature set of Debug/iX.
.com {toc starts here}
.if outtext
. page
.else
. con
. form 3
. tit
. page
. if outdouble or outfinal
. align
. endif
. count 3
. com The next FORM is for Contents/Preface:
. form 2
. jump 6
. if not outfinal
. jump 5
. endif
. opt(l- r- f-).font 3
The MPE/iX System Debugger
. skip 4
Contents
. opt.font 0
. tit |1Contents|
. con (p+ f. m14 c55 l0 r0)
. tit
. form 3
. if outdouble or outfinal
. align
. endif
.endif { else of if outtext }
.check(c1 f0 i1 j0 m1 o1 p1)
.com {toc ends here}