The shell reads lines of input from an input stream, parses and evaluates each line, and writes the result of the evaluation to an output stream. With its default C-expression interpreter, the shell accepts the same expression syntax as a C compiler with only a few variations.
The following sections explain how to start and stop the shell and provide examples illustrating some typical uses of the shell's C interpreter. In the examples, the default shell prompt for interactive input in C is "->". User input is shown in bold face and shell responses are shown in a plain roman face.
% windsh phobos
In the first case, a shell window like that shown in Figure 5-2 appears, ready for your input at the -> prompt. In the second case, WindSh simply executes in the environment where you call it, using the parent shell's window.
Regardless of how you start it, you can terminate a Tornado shell session by executing the exit( ) or the quit( ) command or by typing your host system's end-of-file character (usually CTRL+D). If the shell is not accepting input (for instance, if it loses the connection to the target server) you can use the interrupt key (CTRL+C).
You may run as many different shells attached to the same target as you wish. All functions called from a shell have their output redirected to the WindSh window from which they received input unless you changed the shell defaults using shConfig (see WindSh Environment Variables).
You can also redirect windsh input and output to other UNIX commands, as in the following test (using the shell built-in command i( ) to report on what tasks are running on the target) to look for a target-system task called tPortmapd:
% echo "i" | windsh -q ev386ex@yunque | grep tPortmapd tPortmapd _portmapd 3a4280 100 PEND 2afc4 3a3f28 16 0
Because you can start as many Tornado shell sessions as you like, such combinations of the Tornado shell and the UNIX shell do not interfere with interactive windsh sessions.
Start to type any target symbol name or any existing directory name and then type CTRL+D. The shell automatically completes the command or directory name for you. If there are multiple options, it prints them for you and then reprints your entry. For example, entering an ambiguous request generates the following result:
-> /usr/Tor [CTRL+D] Tornado/ TorClass/ -> /usr/Tor
You can add one or more letters and then type CTRL+D again until the path or symbol is complete.
Once you have typed the complete function name, typing CTRL+D again prints the function synopsis and then reprints the function name ready for your input:
-> _taskIdDefault [CTRL+D] taskIdDefault() - set the default task ID (WindSh) int taskIdDefault ( int tid /* user-supplied task ID; if 0, return default */ ) -> _taskIdDefault
If the routine exists on both host and target, the WindSh synopsis is printed. To print the target synopsis of a function add the meta character @ before the function name.
You can extend the synopsis printing function to include your own routines. To do this, follow these steps:
-> cd $WIND_BASE/target/src/projectX -> make synopsis
Typing any function name, a space, and CTRL+W opens a browser and displays the HTML reference page for the function. Be sure to leave a space after the function name.
-> i [CTRL+W]
-> @i [CTRL+W]
Typing CTRL+W without any function name launches the HTML help tool. If a browser is already running, the reference page is displayed in that browser; otherwise a new browser is started.
The shell prints all integers and characters in both decimal and hexadecimal, and if possible, as a character constant or a symbolic address and offset.
-> 68 value = 68 = 0x44 = 'D'
Almost all C operators can be used for data calculation. Use "(" and ")" to force order of precedence.
-> (14 * 9) / 3 value = 42 = 0x2a = '*'
-> (j + k) * 3 value = ...
WindSh allows you to change the behavior of a particular shell session by setting several environment variables. The Tcl procedure shConfig allows you to display and set how I/O redirection, C++ constructors and destructors, loading, and the load path are defined and handled by the shell.
Because shConfig is a Tcl procedure, use the ? to move from the C interpreter to the Tcl interpreter. (See 5.7.2 Tcl: Calling Under C Control.)
-> ?shConfig SH_GET_TASK_IO = on LD_CALL_XTORS = target LD_SEND_MODULES = on LD_PATH = C:/ProjectX/lib/objR4650gnutest/;C:/ProjectY/lib/objR4560gnuvx -> ?shConfig LD_CALL_XTORS on -> ?shConfig LD_CALL_XTORS LD_CALL_XTORS = on
Some of the commands (or routines) that you can execute from the shell are built into the host shell, rather than running as function calls on the target. These facilities parallel interactive utilities that can be linked into VxWorks itself. By using the host commands, you minimize the impact on both target memory and performance.
The following sections give summaries of the Tornado WindSh commands. For more detailed reference information, see the windsh reference entry (either online, or in C. Tornado Tools Reference).
|
WARNING: Most of the shell commands correspond to similar routines that can be linked into VxWorks for use with the target-resident version of the shell (VxWorks Programmer's Guide: Target Shell). However, the target-resident routines differ in some details. For reference information on a shell command, be sure to consult the windsh entry in C. Tornado Tools Reference or use the HTML help for the command. Although there is usually an entry with the same name in the VxWorks Reference Manual, it describes a related target routine, not the shell command.
|
||||||||||||||||||
Table 5-2 summarizes the WindSh commands that manage VxWorks tasks.
|
|||||||||||||||||||
|
|||||||||||||||||||
Set or report the default (current) task ID (see 5.3.5 The "Current" Task and Address for a discussion of how the current task is established and used).
|
|||||||||||||||||||
|
|||||||||||||||||||
The repeat( ) and period( ) commands spawn tasks whose entry points are _repeatHost and _periodHost. The shell downloads these support routines when you call repeat( ) or period( ). (With remote target servers, that download sometimes fails; for a discussion of when this is possible, and what you can do about it, see 5.6 Object Module Load Path.) These tasks may be controlled like any other tasks on the target; for example, you can suspend or delete them with ts( ) or td( ) respectively.
Table 5-3 summarizes the WindSh commands that report task information.
The i( ) command is commonly used to get a quick report on target activity. (To see this information periodically, use the Tornado browser; see 6. Browser). If nothing seems to be happening, i( ) is often a good place to start investigating. To display summary information about all running tasks:
-> i NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY --------- ----------- -------- --- -------- ------- -------- ------- ----- tExcTask _excTask 3ad290 0 PEND 4df10 3ad0c0 0 0 tLogTask _logTask 3aa918 0 PEND 4df10 3aa748 0 0 tWdbTask 0x41288 3870f0 3 READY 23ff4 386d78 3d0004 0 tNetTask _netTask 3a59c0 50 READY 24200 3a5730 0 0 tFtpdTask _ftpdTask 3a2c18 55 PEND 23b28 3a2938 0 0 value = 0 = 0x0
The w( ) and tw( ) commands allow you to see what object a VxWorks task is pending on. w( ) displays summary information for all tasks, while tw( ) displays object information for a specific task. Note that OBJ_NAME field is used only for objects that have a symbolic name associated with the address of their structure.
-> w NAME ENTRY TID STATUS DELAY OBJ_TYPE OBJ_ID OBJ_NAME ---------- ---------- -------- --------- ----- ---------- -------- -------- tExcTask _excTask 3d9e3c PEND 0 MSG_Q(R) 3d9ff4 N/A tLogTask _logTask 3d7510 PEND 0 MSG_Q(R) 3d76c8 N/A tWdbTask _wdbCmdLoo 36dde4 READY 0 0 tNetTask _netTask 3a43d0 READY 0 0 u0 _smtask1 36cc2c PEND 0 MSG_Q_S(S) 370b61 N/A u1 _smtask3 367c54 PEND 0 MSG_Q_S(S) 370b61 N/A u3 _taskB 362c7c PEND 0 SEM_B 8d378 _mySem2 u6 _smtask1 35dca4 PEND 0 MSG_Q_S(S) 370ae1 N/A u9 _task3B 358ccc PEND 0 MSG_Q(S) 8cf1c _myMsgQ value = 0 = 0x0 -> -> tw u1 NAME ENTRY TID STATUS DELAY OBJ_TYPE OBJ_ID OBJ_NAME ---------- ---------- -------- --------- ----- ---------- -------- -------- u1 _smtask3 367c54 PEND 0 MSG_Q_S(S) 370b61 N/A Message Queue Id : 0x370b61 Task Queueing : SHARED_FIFO Message Byte Len : 100 Messages Max : 0 Messages Queued : 0 Senders Blocked : 2 Send Timeouts : 0 Receive Timeouts : 0 Senders Blocked: TID CPU Number Shared TCB ---------- ---------- ---------- 0x36cc2c 0 0x36e464 0x367c54 0 0x36e47c value = 0 = 0x0 ->
Table 5-4 shows the WindSh commands that display information from the symbol table, from the target system, and from the shell itself.
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
The lkup( ) command takes a regular expression as its argument, and looks up all symbols containing strings that match. In the simplest case, you can specify a substring to see any symbols containing that string. For example, to display a list containing routines and declared variables with names containing the string dsm, do the following:
-> lkup "dsm" _dsmData 0x00049d08 text (vxWorks) _dsmNbytes 0x00049d76 text (vxWorks) _dsmInst 0x00049d28 text (vxWorks) mydsm 0x003c6510 bss (vxWorks)
Case is significant, but position is not (mydsm is shown, but myDsm would not be). To explicitly write a search that would match either mydsm or myDsm, you could write the following:
-> lkup "[dD]sm"
Regular-expression searches of the symbol table can be as simple or elaborate as required. For example, the following simple regular expression displays the names of three internal VxWorks semaphore functions:
-> lkup "sem.Take" _semBTake 0x0002aeec text (vxWorks) _semCTake 0x0002b268 text (vxWorks) _semMTake 0x0002bc48 text (vxWorks) value = 0 = 0x0
Another information command is a symbolic disassembler, l( ). The command syntax is:
l [adr[, n]]
This command lists n disassembled instructions, starting at adr. If n is 0 or not given, the n from a previous l( ) or the default value (10) is used. If adr is 0, l( ) starts from where the previous l( ) stopped, or from where an exception occurred (if there was an exception trap or a breakpoint since the last l( ) command).
The disassembler uses any symbols that are in the symbol table. If an instruction whose address corresponds to a symbol is disassembled (the beginning of a routine, for instance), the symbol is shown as a label in the address field. Symbols are also used in the operand field. The following is an example of disassembled code for an MC680x0 target:
-> l printf _printf
This example shows the printf( ) routine. The routine does a LINK, then pushes the value of std_out onto the stack and calls the routine fioFormatV( ). Notice that symbols defined in C (routine and variable names) are prefixed with an underbar ( _ ) by the compiler.
Perhaps the most frequently used system information command is d( ), which displays a block of memory starting at the address which is passed to it as a parameter. As with any other routine that requires an address, the starting address can be a number, the name of a variable or routine, or the result of an expression.
Several examples of variations on d( ) appear below.
Display starting at address 1000 decimal:
-> d (1000)
-> d 0x1000
Display starting at the address contained in the variable dog:
-> d dog
The above is different from a display starting at the address of dog. For example, if dog is a variable at location 0x1234, and that memory location contains the value 10000, d( ) displays starting at 10000 in the previous example and at 0x1234 in the following:
-> d &dog
Display starting at an offset from the value of dog:
-> d dog + 100
Display starting at the result of a function call:
-> d func (dog)
Display the code of func( ) as a simple hex memory dump:
-> d func
Developers often need to change the state of the target, whether to run a new version of some software module, to patch memory, or simply to single-step a program. Table 5-5 summarizes the WindSh commands of this type.
|
|||||||||||||||||||
|
|||||||||||||||||||
Modify the saved values of boot parameters (see 2.6.4 Description of Boot Parameters).
|
|||||||||||||||||||
If supported by the target-agent configuration, enter system mode. See 5.2.6 Using the Shell for System Mode Debugging.
|
|||||||||||||||||||
|
|||||||||||||||||||
One of the most useful shell features for interactive development is the dynamic linker. With the shell command ld( ), you can download and link new portions of the application. Because the linking is dynamic, you only have to rebuild the particular piece you are working on, not the entire application. Download can be cancelled with CTRL+C or by clicking Cancel in the load progress indicator window. The dynamic linker is discussed further in VxWorks Programmer's Guide: Configuration and Build.
The m( ) command provides an interactive way of manipulating target memory.
The remaining commands in this group are for breakpoints and single-stepping. You can set a breakpoint at any instruction. When that instruction is executed by an eligible task (as specified with the b( ) command), the task that was executing on the target suspends, and a message appears at the shell. At this point, you can examine the task's registers, do a task trace, and so on. The task can then be deleted, continued, or single-stepped.
If a routine called from the shell encounters a breakpoint, it suspends just as any other routine would, but in order to allow you to regain control of the shell, such suspended routines are treated in the shell as though they had returned 0. The suspended routine is nevertheless available for your inspection.
When you use s( ) to single-step a task, the task executes one machine instruction, then suspends again. The shell display shows all the task registers and the next instruction to be executed by the task.
You can use the bh( ) command to set hardware breakpoints at any instruction or data element. Instruction hardware breakpoints can be useful to debug code running in ROM or Flash EPROM. Data hardware breakpoints (watchpoints) are useful if you want to stop when your program accesses a specific address. Hardware breakpoints are available on Intel x86, Intel I960(CX/JX/HX), MIPS R4650, and some PPC processors (PPC860, PPC603, PPC604, PPC403). The arguments of the bh( ) command are architecture specific. For more information, run the help( ) command. The number of hardware breakpoints you can set is limited by the hardware; if you exceed the maximum number, you will receive an error.
Certain WindSh commands are intended specifically for work with C++ applications. Table 5-6 summarizes these commands. For more discussion of these shell commands, see VxWorks Programmer's Guide: C++ Development.
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
In addition, you can use the Tcl routine shConfig to set the environment variable LD_CALL_XTORS within a particular shell. This allows you to use a different C++ strategy in a shell than is used on the target. For more information on shConfig, see WindSh Environment Variables.
Table 5-7 summarizes the WindSh commands that display VxWorks objects. The browser provides displays that are analogous to the output of many of these routines, except that browser windows can update their contents periodically; see 6. Browser.
Table 5-8 summarizes the WindSh commands that display information about the VxWorks network.
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
In order for a protocol-specific command to work, the appropriate protocol must be included in your VxWorks configuration.
If you invoke a name that stands for a host shell command, the shell always invokes that command, even if there is also a target routine with the same name. Thus, for example, i( ) always runs on the host, regardless of whether you have the VxWorks routine of the same name linked into your target.
However, you may occasionally need to call a target routine that has the same name as a host shell command. The shell supports a convention allowing you to make this choice: use the single-character prefix @ to identify the target version of any routine. For example, to run a target routine named i( ), invoke it with the name @i( ).
All target routines are available from WindSh. This includes both VxWorks routines and your application routines. Thus the shell provides a powerful tool for testing and debugging your applications using all the host resources while having minimal impact on how the target performs and how the application behaves.
-> taskSpawn ("tmyTask", 10, 0, 1000, myTask, fd1, 300) value =
-> testFunc (123) value =
For situations where the result of a routine is something other than a 4-byte integer, see Function Calls.
In an interactive real-time development session, it is sometimes convenient to restart everything to make sure the target is in a known state. WindSh provides the reboot( ) command or CTRL+SHIFT+X to make this easy.
When you execute reboot( ) or type CTRL+SHIFT+X, the following reboot sequence occurs:
-> reboot Rebooting...
Target connection has been lost. Restarting shell... Waiting to attach to target server......
|
NOTE: If the target server timeout (-Bt) and retry count (-Br) are too low for your target and your connection method, the new target server may abandon execution before the target finishes rebooting. The default timeout is one second, and the default retry count is three; thus, by default the target server waits three seconds for the target to reboot. If the shell does not restart in a reasonably short time after a reboot( ), try starting a new target server manually.
|
||||||||||||||||||
The bulk of this chapter discusses the shell in its most frequent style of use: attached to a normally running VxWorks system, through a target agent running in task mode. You can also use the shell with a system-mode agent. Entering system mode stops the entire target system: all tasks, the kernel, and all ISRs. Similarly, breakpoints affect all tasks. One major shell feature is not available in system mode: you cannot execute expressions that call target-resident routines. You can still spawn tasks, but bear in mind that, because the entire system is stopped, a newly-spawned task can only execute when you allow the kernel to run long enough to schedule that task.
Depending on how the target agent is configured, you may be able to switch between system mode and task mode; see 4.6 Configuring the Target-Host Communication Interface. When the agent supports mode switching, the following WindSh commands control system mode:
In this case, usrClock( ) is attached to the system clock interrupt handler which is called at each system clock tick when VxWorks is running. First suspend the system and confirm that it is suspended using either i( ) or sysStatusShow( ).
-> sysSuspend value = 0 = 0x0 -> -> i NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY --------- ---------- -------- ----- ------- ------- ------- ----- ----- tExcTask _excTask 3e8f98 0 PEND 47982 3e8ef4 0 0 tLogTask _logTask 3e6670 0 PEND 47982 3e65c8 0 0 tWdbTask 0x3f024 398e04 3 PEND 405ac 398d50 30067 0 tNetTask _netTask 3b39e0 50 PEND 405ac 3b3988 0 0 Agent mode : Extern System context : Suspended value = 0 = 0x0 -> -> sysStatusShow System context is suspended value = 0 = 0x0
Next, set the system mode breakpoint on the entry point of the interrupt handler you want to debug. Since the target agent is running in system mode, the breakpoint will automatically be a system mode breakpoint, which you can confirm with the b( ) command. Resume the system using c( ) and wait for it to enter the interrupt handler and hit the breakpoint.
-> b usrClock value = 0 = 0x0 -> b 0x00022d9a: _usrClock Task: SYSTEM Count: 0 value = 0 = 0x0 -> c value = 0 = 0x0 -> Break at 0x00022d9a: _usrClock Task: SYSTEM
You can now debug the interrupt handler. For example, you can determine which task was running when system mode was entered using taskIdCurrent( ) and i( ).
-> taskIdCurrent _taskIdCurrent = 0x838d0: value = 3880092 = 0x3b349c -> i NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY --------- ---------- -------- ----- ------- ------- ------- ----- ----- tExcTask _excTask 3e8a54 0 PEND 4eb8c 3e89b4 0 0 tLogTask _logTask 3e612c 0 PEND 4eb8c 3e6088 0 0 tWdbTask 0x44d54 389774 3 PEND 46cb6 3896c0 0 0 tNetTask _netTask 3b349c 50 READY 46cb6 3b3444 0 0 Agent mode : Extern System context : Suspended value = 0 = 0x0
You can trace all the tasks except the one that was running when you placed the system in system mode and you can step through the interrupt handler.
-> tt tLogTask 4da78 _vxTaskEntry +10 : _logTask (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 3f2bc _logTask +18 : _msgQReceive (3e62e4, 3e60dc, 20, ffffffff) 27e64 _msgQReceive +1ba: _qJobGet ([3e62e8, ffffffff, 0, 0, 0, 0]) value = 0 = 0x0 -> l _usrClock 00022d9a 4856 PEA (A6) 00022d9c 2c4f MOVEA .L A7,A6 00022d9e 61ff 0002 3d8c BSR _tickAnnounce 00022da4 4e5e UNLK A6 00022da6 4e75 RTS 00022da8 352e 3400 MOVE .W (0x3400,A6),-(A2) 00022dac 4a75 6c20 TST .W (0x20,A5,D6.L*4) 00022db0 3234 2031 MOVE .W (0x31,A4,D2.W*1),D1 00022db4 3939 382c 2031 MOVE .W 0x382c2031,-(A4) 00022dba 343a 3337 MOVE .W (0x3337,PC),D2 value = 0 = 0x0 -> s d0 = 3e d1 = 3700 d2 = 3000 d3 = 3b09dc d4 = 0 d5 = 0 d6 = 0 d7 = 0 a0 = 230b8 a1 = 3b3318 a2 = 3b3324 a3 = 7e094 a4 = 38a7c0 a5 = 0 a6/fp = bcb90 a7/sp = bcb84 sr = 2604 pc = 230ba 000230ba 2c4f MOVEA .L A7,A6 value = 0 = 0x0
-> sysResume value = 0 = 0x0 -> i NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY --------- ---------- -------- ----- ------- ------- ------- ----- ----- tExcTask _excTask 3e8f98 0 PEND 47982 3e8ef4 0 0 tLogTask _logTask 3e6670 0 PEND 47982 3e65c8 0 0 tWdbTask 0x3f024 398e04 3 READY 405ac 398d50 30067 0 tNetTask _netTask 3b39e0 50 PEND 405ac 3b3988 0 0 value = 0 = 0x0
If you want to debug an application you have loaded dynamically, set an appropriate breakpoint and spawn a task which runs when you continue the system:
-> sysSuspend value = 0 = 0x0 -> ld < test.o Loading /view/didier.temp/vobs/wpwr/target/lib/objMC68040gnutest//test.o / value = 400496 = 0x61c70 = _rn_addroute + 0x1d4 -> b address value = 0 = 0x0 -> sp test value = 0 = 0x0 -> c
Occasionally it is desirable to abort the shell's evaluation of a statement. For example, an invoked routine may loop excessively, suspend, or wait on a semaphore. This may happen as the result of errors in arguments specified in the invocation, errors in the implementation of the routine itself, or simply oversight as to the consequences of calling the routine.
To regain control of the shell in such cases, press the interrupt character on the keyboard, usually CTRL+C.1 This makes the shell stop waiting for a result and allows input of a new statement. Any remaining portions of the statement are discarded and the task that ran the function call is deleted.
Pressing CTRL+C is also necessary to regain control of the shell after calling a routine on the target that ends with exit( ) rather than return.
Occasionally a subroutine invoked from the shell may incur a fatal error, such as a bus/address error or a privilege violation. When this happens, the failing routine is suspended. If the fatal error involved a hardware exception, the shell automatically notifies you of the exception. For example:
-> taskSpawn -4 Exception number 11: Task: 0x264ed8 (tCallTask)
In cases like this, you do not need to type CTRL+C to recover control of the shell; it automatically returns to the prompt, just as if you had interrupted. Whether you interrupt or the shell does it for you, you can proceed to investigate the cause of the suspension. For example, in the case above you could run the Tornado browser on tCallTask.
An interrupted routine may have left things in a state which was not cleared when you interrupted it. For instance, a routine may have taken a semaphore, which cannot be given automatically. Be sure to perform manual cleanup if you are going to continue the application from this point.
1: The interrupt character matches whatever you normally use in UNIX shells as an interrupt; you can set it with the UNIX command stty intr. See your host system documentation for details.