Novell is now a part of Micro Focus

The NetWare Internal Debugger

Articles and Tips: tip

Kevin Burnett
Senior Research Engineer
Novell AppNotes

01 Jul 2003

At BrainShare 2003, I had the opportunity of sitting at the AppNotes program table and talking with some of our loyal readers. Several of you requested that we touch upon the NetWare Internal Debugger--its commands and all. So, for this month, I will quench your thirst and delve into one of the more obscure mysteries of the NetWare Operating System.

Using the NetWare Internal Debugger

The NetWare Internal Debugger is an assembly language debugger that is always present within the NetWare 3.x, 4.x, 5.x, and 6.x OSes. For those of you developers that develop LAN or Disk Drivers or do extensive NLM development, you know only too well what the Internal Debugger is.

This is a command-line debugger that does not display source code. However, you can use the WATCOM utility WDISASM with the "/s /l" options to create a list file containing C source interspersed throughout the assembly code. This is very helpful for debugging in 386 assembly. To use the internal debugger, you should have some knowledge of 80386 assembly language and stack-based parameter passing.

The internal debugger was designed specifically to debug NLMs. It includes a set of supplementary commands that are customized for NLMs, such as the .A (display abend or break reason) and .P (display all process names and addresses) commands. These are not part of a typical debugger.

The internal debugger allows resident debugging, in which the debugger and the test application run on the same server. In addition, the internal debugger provides a way to debug multiple NLMs concurrently.

One word of caution--the NetWare Internal Debugger is not for the feint of heart. You need a solid understanding in Assembly and Machine language to effectively utilize the Internal Debugger.

Entering the Debugger

In order to make your NetWare 3.x, 4.x, 5.x, or 6.x server speak debugger-ease, complete the next couple of steps:

  1. Press Shift+Shift+ALT+ESC keys. The keys don't have to be pressed at the same time, but they do need to he held down together with the <ESC> key being the last to go down. This four-key combination is tenderly know as the Novell Four-Finger Salute!

  2. After completing Step 1, this will take you to a pound sign (#) prompt.

    Note: Trying to get into the debugger during a server crisis can help you determine if this is a hard hang or a soft hang. If you are unable to toggle the server console but you can get into the debugger, or if the server is not responding yet you can still toggle between screens at the console, your server is experiencing a soft hang.

Note: On the other hand, if you can't toggle at the console and you can't get into the debugger, the server is experiencing a hard hang. FYI, hard hangs are typically hardware related. Soft hangs are software or utilization related, or are related to a combination of problems.

Internal Debugger Commands

You can recall commands from the NetWare Internal Debugger's command line buffer by pressing the Up-arrow key. After recalling a command from the command-line buffer, you can edit it. The Right- and Left-arrow keys move the cursor. Insert toggles to the overwrite ability. Some of the commands can be repeated by pressing the <Enter> key--these cases are noted in the command descriptions.

Note: If you decide to cancel a command, the Esc key acts like the <Enter> key. You must use the Delete or Backspace key to erase the command line.

There are four types of help commands in the NetWare Internal Debugger. These are:

  • HE-Help on expressions

  • HB-Help on breakpoints

  • H-General Help

  • .H-Help with the supplementary commands

In the Command Summaries table, a pair of square brackets in the Command indicates optional parameters.

Supplementary Commands



Displays the abend or break reason.


Performs a diagnostic core dump to diskette (this can take a great number of diskettes).

.d [address]

If no address is specified, this command displays a page directory map for the current debugger domain. When an address is specified, it displays page entry map for the current debugger domain.


Displays help information about the supplementary commands.

.l offset [offset]

Displays linear address given page map offsets.

.lx address

Displays page offsets and values used for translations.


Displays the names and addresses of the loaded modules.

.p [address]

If no address is specified, this command displays process (thread) names and addresses. If an address is specified, it displays the address as a process (thread) control block. You can use this command to determine what a particular thread is doing. For example, you can examine the values on the stack (which contain return addresses for called functions) to determine what an inactive task is doing (waiting on a semaphore, waiting on keyboard input, and so on). That is, you can construct a "trail" of functions that have been called. This command now displays the semaphore address when listing processes that are waiting on a semaphore.


Displays running process (thread) control block. This command displays information about the running thread in the same format as the .p address command.

.s [address]

If an address is not specified, the command displays all screen names and their addresses. If an address is specified, it displays the specified address as a screen structure. A pointer value obtained by the .s command is used as the address parameter. The command .s address is another way to get information about the current activity of a sleeping thread.

.sem [semaphore address]

If an address is not specified, the command lists all semaphores that have processes waiting on them. If a semaphore address is specified, it displays detailed information about the semaphore.


Toggles the "developer option" to On or Off.


Displays the server version.

Breakpoint Commands



Displays all current breakpoints.

bc number

Clears the specified breakpoint.


Clears all breakpoints.

b = address [( condition )]

Sets an execution breakpoint at the given address. For example: Breakpoint if MyFunction is called and the first parameter on the stack is equal to 0, you would type b = MyFunction [desp+4] == 0

br = address [( condition )]

Sets a read or write breakpoint at the given address. For example: to check if the code (in the range 14500 to 15500) ever reads or writes to memory location 160FE, you would type br = 160FE EIP >= 14500 && eip <= 15500

bw = address [( condition )]

Sets a write breakpoint at address. For example, to check if the code (in the range 14500 to 15500) ever writes to memory location 160FE, you would type bw = 160FE EIP >= 14500 && eip <= 15500

General Debugger Commands


c address

Interactively changes memory.

c address=numbers

Changes memory, starting at an address, to numbers. For example, to change byte values starting at address 10DFAB to FF, FE, 22, you would type: c 10DFAB = FF,FE,22

c address = "text"

This command is currently not supported.

d address [length]

Dumps length bytes of memory starting at the address. If length is not specified, 256 (decimal) bytes are dumped. For example, to dump 16 (decimal) bytes at address 00088F20, you would enter the following command.

d 88F20 10

This command can be repeated by pressing Enter. You can visually scan for a string in the ASCII portion of the dump display by dumping a memory location and then repeatedly pressing Enter to display contiguous blocks of memory.

dl[+ linkOffset ] addr [length]

Traverses a linked list. If length is not specified, 256 (decimal) bytes are dumped. For example, suppose the first node in a linked list starts at 50 and the offset of the address of the next node is at offset 4. To traverse the linked list, displaying 16 (decimal) bytes each time, enter the following command.

dl+4 50 10

To display each successive node in the list, press Enter. The default link offset is 0, which indicates the end of the list. Thus, dl 50 10 uses a link offset of 0. This command can be repeated by pressing Enter. You can dump the first node in a linked list and then dump each successive node by pressing Enter. A NULL link marks the end of the list.

f flag=value

This command changes the specified flag. The value can be 0 or 1. For example, to change the specified flag to the new value (0 or 1), where flag is CF, AF, ZF, SF, IF, TF, PF, DF, or OF, you would type: f CF = 0


Specifies a "Go" instruction, starting from the current EIP.

g [break_addresses]

Specifies a "Go" instruction, starting at the current EIP and ending at the break address or addresses. For example, suppose a code breakpoint has just occurred at the start of a C function. To resume execution until the function returns to its caller, use the following command: g [desp]


Displays general help.


Displays breakpoint help.


Displays expressions help.

i[b,w,d] port

Inputs a byte, word, or double-word from the specified port. The default is a byte. For example, to input the value at port 2F0, you would type: i 2F0

m start [L length] pattern

Memory search is currently not supported.


Lists all symbol names and displays the NLMs that defined them.

n symbolname value

Defines a new symbol name at an address. For example, to give the value 2D46A5 the name x, you would type: n x 2D46A5. Now x can be referenced with other commands, such as: b=x, b=x+5, u x. By default, the value is 10. Symbols can be defined with the n command. When the server starts, you can use the y option to override the default.


Removes a user-defined symbol name.


Removes all user-defined symbol names.

o[b,w,d] port = value

Outputs byte, word, or double-word to the specified port. For example, to output 10h to port 320h, you would type: o 320=10


This command single-steps through the program code; proceeds past calls. (See the s command for stepping into calls.) You can repeat this command by pressing Enter. A common use for this command is to run until you hit a breakpoint and then single-step by entering the p command. You can then press the Enter key repeatedly to continue single-stepping. By holding down Enter, you can quickly single-step through the program code.


Quits to DOS.


Displays the registers and flags.

REG = value

Changes the register to the specified value. The registers are EAX, EBX, ECX, EDX, ESI, EDI, EBP, EIP, and EFL.


Single-steps through the program code; steps into a call. (See the p command for stepping past calls.) You can repeat this command by pressing Enter. You can hit a breakpoint and single-step by entering the s command and then pressing Enter repeatedly to continue single-stepping. By holding down Enter, you can quickly single-step through the program code.


Same as s.

u address [count]

Disassembles count instructions. If you type u by itself and press Enter, the starting address is assumed to be the contents of the EIP register, and 16 (decimal) bytes will be disassembled. For example, to disassemble 16 (decimal) bytes prior to the current instruction, you would type: u eip-10

NOTE: A command such as this might not cause the disassembly to fall on an instruction boundary. This command can be repeated by pressing Enter. You can disassemble starting at any memory location by initially entering the u command and then pressing Enter to continue the contiguous disassembly.


Displays the server's screen(s) for viewing. Each time a key is pressed, the next screen is displayed. See the .s command.


Exchanges processor stack frames.

z expression

Evaluates the expression. For example, to display the value at the address computed by adding EBP to EBX shifted right 16 (decimal) times, you would type: z [ d EBP + (EBX >> 10) ]

? [address]

Displays the nearest symbols to the specified address. If an address is not given, the EIP registry is used. For example, to determine the NLM and function owning the current instruction, you would type the following: ?

Setting Breakpoints

With the NetWare Internal Debugger, you can set execute, write, or read/write breakpoints. There are four breakpoint registers, allowing a maximum of four simultaneous breakpoints. Breakpoints can be permanent or temporary:

  • To set permanent breakpoints, use the b, br, and bw commands. For permanent breakpoints, you can attach a condition that specifies whether or not to take the breakpoint. If the condition is true, a breakpoint is taken. If the condition is false, execution continues without stopping.

  • To set temporary breakpoints, use the g command. For example, a "go" to a specific address is a temporary breakpoint. The p command can also set a temporary breakpoint if the current instruction cannot be single-stepped. If you use all four breakpoints and issue a g [desp] command, the following is displayed:

Go out of breakpoints
  • If you use all four breakpoints and attempt to proceed past a function call using the p command, the following is displayed:

Breakpoint not available for proceed

The assembly repeat instructions (such as REPE), the LOOP instruction, and the CALL instruction also require p to set a temporary breakpoint.

Debugger Examples

First of all, I would like to direct you to a couple of Tom Buckley's excellent articles in past issues of AppNotes. These articles show how to walk the NetWare stack with the NetWare Internal Debugger. Part 1 can be found at

Part 2 of the article can be found at

So what are some things you can do with the Internal Debugger when something goes wrong with your server? The following shows how to use some of the troubleshooting commands offered by the debugger.


V <Enter>

This command takes you to a sequential display of each of the console screens running at the time of the abend or that were available when the debugger was invoked. Press any key to see additional screens until you get back to the pound (#) prompt. Review the screens looking for anything you think could be indicative of the problem

.R <Enter>

Displays the running process.

? <Enter>

Displays the contents of the Extended Instruction Pointer (the process scheduled to run next).


This will produce a module listing. If .R or ? mentions something related to a module you are running, record the date of the module. The problem may simply be an outdated module.

Note: <Enter> means press the Enter key following the command.


The NetWare Internal Debugger is a very powerful debugging tool for the NetWare OS. However, it does require a substantial understanding of Assembly Programming and Machine Language to use it effectively. If you have any NetWare Internal Debugger or debugging questions you would like answered, send them to:
, and we will see if we can provide answers in a future issue.

Note: Portions of Technical Information Document #2920074 were used in creating this Tip & Trick.

* Originally published in Novell AppNotes


The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates