6

Target Tools



6.1    Introduction

The Tornado development system provides a full suite of development tools that resides and executes on the host machine; this approach conserves target memory and resources. However, there are many situations in which it is desirable to have a target-resident shell, a target-resident dynamic object loader, simple target-resident debug facilities, or a target-resident system symbol table. This chapter discusses the target-resident facilities in detail.

Some situations in which the target based tools may be particularly useful are:

  • When debugging a deployed system over a simple serial connection.

  • When developing and debugging network protocols, where it is useful to see the target's view of a network.

  • To create dynamically configurable systems that can load modules from a target disk or over the network.

The target based tools are partially independent so, for instance, the target shell may be used without the target loader, and vice versa. However, for any of the other individual tools to be completely functional, the system symbol table is required.

In some situations, it may also be useful to use both the host-resident development tools and the target-resident tools at the same time. In this case, additional facilities are required so that both environments maintain consistent views of the system. For more information, see 6.4.4 Using the VxWorks System Symbol Table.

This chapter briefly describes these target-resident facilities, as well as providing an overview of the most commonly used VxWorks show routines.

For the most part, the target-resident facilities work the same as their Tornado host counterparts. For more information, see the appropriate chapters of the Tornado User's Guide.



6.2    Target-Resident Shell

For the most part, the target-resident shell works the same as the host shell (also known as WindSh or the Tornado shell). For detailed information about the host shell, as well as the differences between the host and target shell, see the Tornado User's Guide: Shell. Also see the VxWorks API Reference entries for dbgLib, shellLib, and usrLib.

6.2.1   Summarizing the Target and Host Shell Differences

The major differences between the target and host shells are:

  • The Tornado host shell provides additional commands.

  • Both shells include a C interpreter; the host shell also provides a Tcl interpreter. Both shells provide an editing mode.

  • You can have multiple host shells active for any given target; only one target shell can be active for a target at any one time.

  • The host shell allows virtual I/O; the target shell does not.

  • The host shell is always ready to execute provided that the WDB target agent is included in the system. The target shell, as well as its associated target-resident symbol tables and module loader, must be configured into the VxWorks image by including the appropriate components.

  • The target shell's input and output are directed at the same window by default, usually a console connected to the board's serial port.1 For the host shell, these standard I/O streams are not necessarily directed to the same window as the host shell.

  • The host shell can perform many control and information functions entirely on the host, without consuming target resources.

  • The host shell uses host resources for most functions so that it remains segregated from the target. This means that the host shell can operate on the target from the outside. The target shell, however, must act on itself, which means that there are limitations to what it can do. For example, to make breakable calls in the target shell, sp( ) must be used. In addition, conflicts in task priority may occur while using the target shell.


*      
WARNING: Shell commands must be used in conformance with the routine prototype, or they may cause the system to hang (as for example, using ld( ) without an argument does).

  • The target shell correctly interprets the tilde operator in pathnames, whereas the host shell cannot. For example, the following command executed from the target shell by user panloki would correctly locate /home/panloki/foo.o on the host system:

-> ld < ~/foo.o 

  • When the target shell encounters a string literal ("...") in an expression, it allocates space for the string, including the null-byte string terminator, plus some additional overhead.2 The value of the literal is the address of the string in the newly allocated storage. For example, the following expression allocates 12-plus bytes from the target memory pool, enters the string in that memory (including the null terminator), and assigns the address of the string to x:

-> x = "hello there"

The following expression can be used to return the memory to the target memory pool (see the memLib reference entry for information on memory management):

-> free (x)

Furthermore, even when a string literal is not assigned to a symbol, memory is still permanently allocated for it. For example, the following expression uses memory that is never freed:

-> printf ("hello there")

This is because if strings were only temporarily allocated, and a string literal were passed to a routine being spawned as a task, by the time the task executed and attempted to access the string, the target shell would have already released (and possibly even reused) the temporary storage where the string was held.

After extended development sessions with the target shell, the cumulative memory used for strings may be noticeable. If this becomes a problem, you must reboot your target.

The host shell also allocates memory on the target if the string is to be used there. However, it does not allocate memory on the target for commands that can be performed at the host level (such as lkup( ), ld( ), and so on).

6.2.2   Configuring VxWorks With the Target Shell

To create the target shell, you must configure VxWorks to include the INCLUDE_SHELL component.

You must also configure VxWorks with components for symbol table support (see 6.4.1 Configuring VxWorks with Symbol Tables). Additional shell components include facilities for the following:

INCLUDE_SHELL_BANNER

INCLUDE_DEBUG

INCLUDE_DISK_UTIL

INCLUDE_SYM_TBL_SHOW

You may also find it useful to include components for the module loader and unloader (see 6.3.1 Configuring VxWorks with the Loader).These components are required for the usrLib commands that load and unload modules (see 6.2.4 Loading and Unloading Object Modules from the Target Shell).

The shell task (tShell) is created with the VX_UNBREAKABLE option; therefore, breakpoints cannot be set in this task, because a breakpoint in the shell would make it impossible for the user to interact with the system. Any routine or task that is invoked from the target shell, rather than spawned, runs in the tShell context.

Only one target shell can run on a VxWorks system at a time; the target shell parser is not reentrant, because it is implemented using the UNIX tool yacc.

6.2.3   Using Target Shell Help and Control Characters

You can type the following command to display help on the shell:

-> help

Use dbgHelp for commands related to debugging.

The following target shell command lists all the available help routines:

-> lkup "Help"

The target shell has its own set of terminal-control characters, unlike the host shell, which inherits its setting from the host window from which it was invoked. Table 6-1 lists the target shell's terminal-control characters. The first four of these are defaults that can be mapped to different keys using routines in tyLib (see also Tty Special Characters).

Table 6-1:   Target Shell Terminal Control Characters


Command
Description

CTRL+C
Aborts and restarts the shell.
CTRL+H
Deletes a character (backspace).
CTRL+Q
Resumes output.
CTRL+S
Temporarily suspends output.
CTRL+U
Deletes an entire line.
CTRL+X
Reboots (trap to the ROM monitor).
ESC
Toggles between input mode and edit mode (vi mode only).

The shell line-editing commands are the same as they are for the host shell.

6.2.4   Loading and Unloading Object Modules from the Target Shell

Object modules can be dynamically loaded into a running VxWorks system with the module loader. The following is a typical load command from the shell, in which the user downloads appl.o to the appBucket domain:

[appBucket] -> ld < /home/panloki/appl.o 

The ld( ) command loads an object module from a file, or from standard input, into a specified protection domain. External references in the module are resolved during loading.

Once an application module is loaded into target memory, subroutines in the module can be invoked directly from the shell, spawned as tasks, connected to an interrupt, and so on. What can be done with a routine depends on the flags used to download the object module (visibility of global symbols or visibility of all symbols). For more information about ld, see the VxWorks API Reference entry for usrLib.

Modules can be reloaded with reld( ), which unloads the previously loaded module of the same name before loading the new version. For more information about reld, see the VxWorks API Reference entry for unldLib.

Undefined symbols can be avoided by loading the modules in the appropriate order. Linking independent files before download can be used to avoid unresolved references if there are circular references between them, or if the number of modules is unwieldy. The static linker ldarch can be used to link interdependent files, so that they can only be loaded and unloaded as a unit.

Unloading a code module removes its symbols from the target's symbol table, removes the code module descriptor and section descriptor(s) from the module list, and removes its section(s) from the memory partition(s) that held them.

For information about features of the target loader and unloader, see 6.3 Target-Resident Loader.

6.2.5   Debugging with the Target Shell

The target shell includes the same task level debugging utilities as the host shell if VxWorks has been configured with the INCLUDE_DEBUG component. For details on the debugging commands available, see the Tornado User's Guide: Shell and the VxWorks API Reference entry for dbgLib.

You are not permitted to use system mode debug utilities with the target shell.

6.2.6   Aborting Routines Executing from the Target Shell

Occasionally it is desirable to abort the shell's evaluation of a statement. For example, an invoked routine can loop excessively, suspend, or wait on a semaphore. This can happen because of errors in the arguments specified in the invocation, errors in the implementation of the routine, or oversight regarding the consequences of calling the routine. In such cases it is usually possible to abort and restart the target shell task. This is done by pressing the special target-shell abort character on the keyboard, CTRL+C by default. This causes the target shell task to restart execution at its original entry point. Note that the abort key can be changed to a character other than CTRL+C by calling tyAbortSet( ).

When restarted, the target shell automatically reassigns the system standard input and output streams to the original assignments they had when the target shell was first spawned. Thus any target shell redirections are canceled, and any executing shell scripts are aborted.

The abort facility works only if the following are true:

  • excTask( ) is running (see the Tornado User's Guide: Configuration and Build).

  • The driver for the particular keyboard device supports it (all VxWorks-supplied drivers do).

  • The device's abort option is enabled. This is done with an ioctl( ) call, usually in the root task in usrConfig.c. For information on enabling the target shell abort character, see tty Options.

Also, you may occasionally enter an expression that causes the target shell to incur a fatal error such as a bus/address error or a privilege violation. Such errors normally result in the suspension of the offending task, which allows further debugging.

However, when such an error is incurred by the target shell task, VxWorks automatically restarts the target shell, because further debugging is impossible without it. Note that for this reason, as well as to allow the use of breakpoints and single-stepping, it is often useful when debugging to spawn a routine as a task instead of just calling it directly from the target shell.

When the target shell is aborted for any reason, either because of a fatal error or because it is aborted from the terminal, a task trace is displayed automatically. This trace shows where the target shell was executing when it died.

Note that an offending routine can leave portions of the system in a state that may not be cleared when the target shell is aborted. For instance, the target shell might have taken a semaphore, which cannot be given automatically as part of the abort.

6.2.7   Using a Remote Login to the Target Shell

Remote Login From Host: telnet and rlogin

When VxWorks is first booted, the target shell's terminal is normally the system console. You can use telnet to access the target shell from a host over the network if you select INCLUDE_TELNET for inclusion in the project facility VxWorks view (see Tornado User's Guide: Projects). Defining INCLUDE_TELNET creates the tTelnetd task. To access the target shell over the network, enter the following command from the host (targetname is the name of the target VxWorks system):

% telnet "targetname" 

UNIX host systems also use rlogin to provide access to the target shell from the host. Select INCLUDE_RLOGIN for inclusion in the project facility VxWorks view to create the tRlogind task. However, note that VxWorks does not support telnet or rlogin access from the VxWorks system to the host.

A message is printed on the system console indicating that the target shell is being accessed via telnet or rlogin, and that it is no longer available from its console.

If the target shell is being accessed remotely, typing at the system console has no effect. The target shell is a single-user system--it allows access either from the system console or from a single remote login session, but not both simultaneously. To prevent someone from remotely logging in while you are at the console, use the routine shellLock( ) as follows:

-> shellLock 1 

To make the target shell available again to remote login, enter the following:

-> shellLock 0 

To end a remote-login target shell session, call logout( ) from the target shell. To end an rlogin session, type TILDE and DOT as the only characters on a line:

-> ~.  

Remote Login Security

You can be prompted to enter a login user name and password when accessing VxWorks remotely:

VxWorks login: user_name  
Password: password 

The remote-login security feature is enabled by selecting INCLUDE_SECURITY for inclusion in the project facility VxWorks view. The default login user name and password provided with the supplied system image is target and password. You can change the user name and password with the loginUserAdd( ) routine, as follows:

-> loginUserAdd "fred", "encrypted_password" 

To obtain encrypted_password, use the tool vxencrypt on the host system. This tool prompts you to enter your password, and then displays the encrypted version.

To define a group of login names, include a list of loginUserAdd( ) commands in a startup script and run the script after the system has been booted. Or include the list of loginUserAdd( ) commands to the file usrConfig.c, then rebuild VxWorks.


*      
NOTE: The values for the user name and password apply only to remote login into the VxWorks system. They do not affect network access from VxWorks to a remote system; See VxWorks Network Programmer's Guide: rlogin and telnet, Host Access Applications.

The remote-login security feature can be disabled at boot time by specifying the flag bit 0x20 (SYSFLAG_NO_SECURITY) in the flags parameter on the boot line (see Tornado Getting Started). This feature can also be disabled by deselecting INCLUDE_SECURITY in the project facility VxWorks view.

6.2.8   Distributing the Demangler

The Wind River Target Shell provided as part of the suite of VxWorks development tools includes an unlinked copy of the demangler library. This library is licensed under the GNU Library General Public License Version 2, June 1991 - a copy of which can be found at www.gnu.org or by downloading sources to your GNU toolchain from the WindSurf site. Under this license the demangler library can be used without restriction during development, but VxWorks developers should be aware of the restrictions provided within the Library General Public License should the library be linked with application code as a derivative work and distributed to third parties.

If VxWorks developers wish to distribute the Wind River Target Shell while avoiding the Library General Public License restrictions, then the demangler library should be excluded from the project.

To remove the demangler from a kernel built with the Tornado project facility simply remove the "C++ symbol demangler" component.

To remove the demangler from a kernel built from a BSP (command line build) define the macro INCLUDE_NO_CPLUS_DEMANGLER in config.h.

Excluding this library will not affect the operation of the Wind River Target Shell but will reduce the human readability of C++ identifiers and symbols.



6.3    Target-Resident Loader

VxWorks lets you add code to a target system at run-time. This operation, called loading, or downloading, allows you to install target applications or to extend the operating system itself.

The downloaded code can be a set of functions, meant to be used by some other code (the equivalent of a library in other operating systems), or it can be an application, meant to be executed by a task or a set of tasks. The units of code that can be downloaded are referred to as object modules.

The ability to load individual object modules brings significant flexibility to the development process, in several different ways. The primary use of this facility during development is to unload, recompile, and reload object modules under development. The alternative is to link the developed code into the VxWorks image, to rebuild this image, and to reboot the target, every time the development code must be recompiled.

The loader also enables you to dynamically extend the operating system, since once code is loaded, there is no distinction between that code and the code that was compiled into the image that booted.

Finally, you can configure the loader to optionally handle memory allocation, on a per-load basis, for modules that are downloaded. This allows flexible use of the target's memory. The loader can either dynamically allocate memory for downloaded code, and free that memory when the module is unloaded; or, the caller can specify the addresses of memory that has already been allocated. This allows the user more control over the layout of code in memory. For more information, see 6.3.5 Specifying Memory Locations for Loading Objects.

The VxWorks target loader functionality is provided by two components: the loader proper, which installs the contents of object modules in the target system's memory; and the unloader, which uninstalls object modules. In addition, the loader relies on information provided by the system symbol table.


*      
NOTE: The target-resident loader is often confused with the bootloader, which is used to install the kernel image in memory. Although these two tools perform similar functions, and share some support code, they are separate entities. The bootloader loads only complete images, and does not perform relocations.

6.3.1   Configuring VxWorks with the Loader

By default, the loader is not included in the VxWorks image. To use the target loader, you must configure VxWorks with the INCLUDE_LOADER component. The INCLUDE_LOADER component is discussed further in subsequent sections and in the loadLib entry in the VxWorks API Reference. Adding this component automatically includes several other components that, together, provide complete loader functionality:

INCLUDE_MODULE_MANAGER

INCLUDE_SYM_TBL

INCLUDE_SYM_TBL_INIT

Including the loader does not automatically include the unloader. To add the unloader to your system, include the following component:

INCLUDE_UNLOADER

INCLUDE_SYM_TBL_SYNC


*      
CAUTION: If you want to use the target-resident symbol tables and loader in addition to the Tornado host tools, you must configure VxWorks with the INCLUDE_SYM_TBL_SYNC component to provide host-target symbol table and module synchronization. For more information, see 6.4.4 Using the VxWorks System Symbol Table.

6.3.2   Target-Loader API

Table 6-2 and Table 6-3 list the API routines and shell commands available for module loading and unloading.

Table 6-2:   Routines for Loading and Unloading Object Modules


Routine
Description

loadModule( )
Loads an object module.
loadModuleAt( )
Loads an object module into a specific memory location.
unldByModuleId( )
Unloads an object module by specifying a module ID.
unldByNameAndPath( )
Unloads an object module by specifying a name and path.

Note that all of the loader routines can be called directly from the shell or from code. The shell commands, however, are intended to be used only from the shell, not from within programs.3 In general, shell commands handle auxiliary operations, such as opening and closing a file; they also print their results and any error messages to the console.

Table 6-3:   Shell Command for Loading and Unloading Object Modules


Command
Description

ld( )
Loads an object module.
reld( )
Unloads and reloads an object module by specifying a filename or module ID.
unld( )
Unloads an object module by specifying a filename or module ID.

The use of some of these routines and commands is discussed in the following sections.

For detailed information, see the loadLib, unldLib, and usrLib entries in the VxWorks API Reference, as well as 6.3.3 Summary List of Loader Options.

6.3.3   Summary List of Loader Options

The loader's behavior can be controlled using load flags passed to loadLib and unldLib routines. These flags can be combined (using an OR operation), although some are mutually exclusive. Table 6-4, Table 6-5, and Table 6-5 group these options by category.  

Table 6-4:   Loader Options for Symbol Registration


Option
Hex Value
Description

LOAD_NO_SYMBOLS
0x2
No symbols from the module are registered in the system's symbol table. Consequently, linkage against the code module is not possible. This option is useful for deployed systems, when the module is not supposed to be used in subsequent link operations.
LOAD_LOCAL_SYMBOLS
0x4
Only local (private) symbols from the module are registered in the system's symbol table. No linkage is possible against this code module92s public symbols. This option is not very useful by it self, but is one of the base options for LOAD_ALL_SYMBOLS.
LOAD_GLOBAL_SYMBOLS
0x8
Only global (public) symbols from the module are registered in the system's symbol table. No linkage is possible against this code module's private symbols. This is the loader's default when the loadFlags parameter is left as NULL.
LOAD_ALL_SYMBOLS
0xC
Local and global symbols from the module are registered in the system's symbol table. This option is useful for debugging.

 

  

Table 6-5:   Loader Option for Code Module Visibility


Option
Hex Value
Description

HIDDEN_MODULE
0x10
The code module is not visible from the moduleShow( ) routine or the Tornado tools. This is useful on deployed systems when an automatically loaded module should not be detectable by the user.

  

Table 6-6:   Loader Options for Resolving Common Symbols


Option
Hex Value
Description

LOAD_COMMON_MATCH_NONE
0x100
Keeps common symbols isolated, visible from the object module only. This option prevents any matching with already-existing symbols. Common symbols are added to the symbol table unless LOAD_NO_SYMBOLS is set. This is the default option.
LOAD_COMMON_MATCH_USER
0x200
Seeks a matching symbol in the system symbol table, but considers only symbols in user modules, not symbols that were in the original booted image. If no matching symbol exists, this option behaves like LOAD_COMMON_MATCH_NONE.
LOAD_COMMON_MATCH_ALL
0x400
Seeks a matching symbol in the system symbol table, considering all symbols. If no matching symbol exists, this option behaves like LOAD_COMMON_MATCH_NONE.

If several matching symbols exist for options LOAD_COMMON_MATCH_USER and LOAD_COMMON_MATCH_ALL, the order of precedence is: symbols in the bss segment, then symbols in the data segment. If several matching symbols exist within a single segment type, the symbol most recently added to the target server symbol table is used.   

Table 6-7:   Unloader Option for Breakpoints and Hooks


Option
Hex Value
Description

UNLD_KEEP_BREAKPOINTS
0x1
T he breakpoints are left in place when the code module is unloaded. This is useful for debugging, as all breakpoints are otherwise removed from the system when a module is unloaded.

  

6.3.4   Loading C++ Modules

The files produced by the toolchains are not sufficiently processed for the loader to handle them properly. For instructions on preparing a C++ file for download, see section 7.3.1 Munching C++ Application Modules.

C++ modules may include code that must be executed automatically when they are loaded and unloaded. This code consists of constructors and destructors for static instances of classes.

Constructors must be executed before any other code in the code module is executed. Similarly, destructors must be executed after the code module is no longer to be used, but before the module is unloaded. In general, executing constructors at load time and destructors at unload time is the simplest way to handle them. However, for debugging purposes, a user may want to decouple the execution of constructors and destructors from the load and unload steps.

For this reason, the behavior of the loader and unloader regarding constructors and destructors is configurable. When the C++ strategy is set to AUTOMATIC (1), the constructors and destructors are executed at load and unload time. When the C++ strategy is set to MANUAL (0), constructors and destructors are not executed by the loader or unloader. When the C++ strategy is MANUAL, the functions cplusCtors( ) and cplusDtors( ) can be used to execute the constructors or destructors for a particular code module.

The function cplusXtorSet( ) is available to change the C++ strategy at runtime. The default setting is AUTOMATIC.

For more information, see the cplusLib and loadLib entries in the VxWorks API Reference.

6.3.5   Specifying Memory Locations for Loading Objects

By default, the loader allocates the memory necessary to hold a code module. It is also possible to specify where in memory any or all of the text, data, and bss segments of an object module should be installed using the loadModuleAt( ) command. If an address is specified for a segment, then the caller must allocate sufficient space for the segment at that address before calling the load routine. If no addresses are specified, the loader allocates one contiguous area of memory for all three of the segments.

For any segment that does not have an address specified, the loader allocates the memory (using memPartAlloc( ) or, for aligned memory, using memalign( )). The base address can also be set to the value LOAD_NO_ADDRESS, in which case the loader replaces the LOAD_NO_ADDRESS value with the actual base address of the segment once the segment is installed in memory.

When working with architectures that use the ELF object module format, an additional complication arises. The basic unit of information in a relocatable ELF object file is a section. In order to minimize memory fragmentation, the loader gathers sections so that they form the logical equivalent of an ELF segment. For simplicity, these groups of sections are also referred to as segments. For more information, see ELF object module format).

The VxWorks loader creates three segments: text, data, and bss. When gathering sections together to form segments, the sections are placed into the segments in the same order in which they occur in the ELF file. It is sometimes necessary to add extra space between sections to satisfy the alignment requirements of all of the sections. When allocating space for one or more segments, care must be taken to ensure that there is enough space to permit all of the sections to be aligned properly. (The alignment requirement of a section is given as part of the section description in the ELF format. The binary utilities readelfarch and objdumparch can be used to obtain the alignment information.)

In addition, the amount of padding required between sections depends on the alignment of the base address. To ensure that there will be enough space without knowing the base address in advance, allocate the block of memory so that it is aligned to the maximum alignment requirement of any section in the segment. So, for instance, if the data segment contains sections requiring 128 and 264 byte alignment, in that order, allocate memory aligned on 264 bytes.

The other object module formats used in VxWorks (a.out and PECOFF) have basic units of information that correspond more closely to the VxWorks model of a single unit each of text, data and bss. Therefore when working with architectures that use either the a.out or PECOFF file formats, this problem of allocating extra space between sections does not arise.

The unloader can remove the sections wherever they have been installed, so no special instructions are required to unload modules that were initially loaded at specific addresses. However, if the base address was specified in the call to the loader, then, as part of the unload, unloader does not free the memory area used to hold the segment. This allocation was performed by the caller, and the de-allocation must be as well.

6.3.6   Constraints Affecting Loader Behavior

The following sections describe the criteria used to load modules.

Relocatable Object Files

A relocatable file is an object file for which text and data sections are in a transitory form, meaning that some addresses are not yet known. An executable file is one which is fully linked and ready to run at a specified address. In many operating systems, relocatable object modules are an intermediate step between source (.c, .s, .cpp) files and executable files, and only executable files may be loaded and run. The relocatable files produced by the toolchains are labeled with a .o extension.

However, in VxWorks, relocatable (.o) files are used for application code, for the following reason. To construct an executable image for download, the program's execution address and the addresses of externally defined symbols, such as library routines, must be known. Since the layout of the VxWorks image and downloaded code in memory are so flexible, these items of information are not available to a compiler running on a host machine. Therefore, the code handled by the target-resident loader must be in relocatable form, rather than an executable.

Once installed in the system's memory, the entity composed of the object module's code, data, and symbols is called a code module. For information about installed code modules, see the individual routine entries under moduleLib in the VxWorks API Reference.

Object Module Formats

There are several standard formats for both relocatable and executable object files. In the Tornado development environment, there is a single preferred object module format for each supported target architecture. For most architectures, the preferred format is now Executable and Linkable Format (ELF). Exceptions are the 68K toolchain, which produces a.out object files, and the NT simulator toolchain, which produces pecoff object files.

The VxWorks loader can handle most object files generated by the supported toolchains.


*      
NOTE: Not all possible relocation operations that are supported by an architecture are necessarily supported by the loader. This will usually only affect users writing assembly code.

ELF object module format

An relocatable ELF object file is essentially composed of two categories of elements: the headers and the sections. The headers describe the sections, and the sections contain the actual text and data to be installed.

An executable ELF file is a collection of segments, which are aggregations of sections. The VxWorks loader performs an aggregation step on the relocatable object files that is similar to the process carried out by toolchains when producing an executable ELF file. The resulting image consists of one text segment, one data segment, and one bss segment. (A general ELF executable file may have more than one segment of each type, but the VxWorks loader uses the simpler model of at most one segment of each type.) The loader installs the following categories of sections in the system's memory:

  • text sections that hold the application's instructions

  • data sections that hold the application's initialized data

  • bss sections that hold the application's un-initialized data

  • read-only data sections that hold the application's constant data

Read-only data sections are placed in the text segment by the loader.

a.out Object Module Format

Object files in the a.out file format are fairly simple, and are already very close to the VxWorks abstraction of code modules. Similarly to ELF files, they contain both headers and sections. In other literature on file formats, the 'sections' of an a.out file are sometimes referred to as sections and sometimes as segments, even within the same work, depending on the context. Since only one text section, one data section, and one bss section are permitted in an a.out file, a.out sections are essentially equivalent segments, for our purposes.

The text, data, and bss sections of the a.out object module become the text, data and bss segments of the loaded code module.

PECOFF Object Module Format

The PECOFF object module format is only used in VxWorks for the Windows simulator architecture.

The basic unit of information in a PECOFF object module is also called a section. The allowed size a section is limited by the PECOFF file format. Therefore, it is possible, although not common, to have more than one text or data section in a PECOFF file.

The VxWorks target loader only handles PECOFF object files that have at most one text section, one data section, and one bss section. These sections become the text, data, and bss segments of VxWorks code module.

Linking and Reference Resolution

The VxWorks loader performs some of the same tasks as a traditional linker in that it prepares the code and data of an object module for the execution environment. This includes the linkage of the module's code and data to other code and data.

The loader is unlike a traditional linker in that it does this work directly in the target system's memory, and not in producing an output file.

In addition, the loader uses routines and variables that already exist in the VxWorks system, rather than library files, to relocate the object module that it loads. The system symbol table (see 6.4.4 Using the VxWorks System Symbol Table) is used to store the names and addresses of functions and variables already installed in the system.This has the side effect that once symbols are installed in the system symbol table, they are available for future linking by any module that is loaded. Moreover, when attempting to resolve undefined symbols in a module, the loader uses all global symbols compiled into the target image, as well as all global symbols of previously loaded modules. As part of the normal load process, all of the global symbols provided by a module are registered in the system symbol table. You can override this behavior by using the LOAD_NO_SYMBOLS load flag (see Table 6-4).

The system symbol table allows name clashes to occur. For example, suppose a symbol named func exists in the system. A second symbol named func is added to the system symbol table as part of a load. From this point on, all links to func are to the most recently loaded symbol. See also, 6.4.1 Configuring VxWorks with Symbol Tables.

The Sequential Nature of Loading

The VxWorks loader loads code modules in a sequential manner. That is, a separate load is required for each separate code module. Suppose a user has two code modules named A_module and B_module, and A_module references symbols that are contained in B_module. The user may either use the host-resident linker to combine A_module and B_module into a single module, or may load B_module first, and then load A_module.

When code modules are loaded, they are irreversibly linked to the existing environment; meaning that, once a link from a module to an external symbol is created, that link cannot be changed without unloading and reloading the module.

Therefore dependencies between modules must be taken into account when modules are loaded to ensure that references can be resolved for each new module, using either code compiled into the VxWorks image or modules that have already been loaded into the system.

Failure to do so results in incompletely resolved code, which retains references to undefined symbols at the end of the load process. For diagnostic purposes, the loader prints a list of missing symbols to the console. This code should not be executed, since the behavior when attempting to execute an improperly relocated instruction is not predictable.

Normally, if a load fails, the partially installed code is removed. However, if the only failure is that some symbols are unresolved, the code is not automatically unloaded. This allows the user to examine the result of the failed load, and even to execute portions of the code that are known to be completely resolved. Therefore, code modules that have unresolved symbols must be removed by a separate unload command, unld( ).

Note that the sequential nature of the VxWorks loader means that unloading a code module which has been used to resolve another code module may leave references to code or data which are no longer available. Execution of code holding such dangling references may have unexpected results.

Resolving Common Symbols

Common symbols provide a challenge for the VxWorks loader that is not confronted by a traditional linker. Consider the following example:

#include <stdio.h>  
 
int willBeCommon;  
 
void main (void) {}  
    { 
    ...  
    }

The symbol willBeCommon is uninitialized, so it is technically an undefined symbol. Many compilers will generate a 'common' symbol in this case.

ANSI C allows multiple object modules to define uninitialized global symbols of the same name. The linker is expected to consistently resolve the various modules references to these symbols by linking them against a unique instance of the symbol. If the different references specify different sizes, the linker should define a single symbol with the size of the largest one and link all references against it.

This is not a difficult task when all of the modules are present at the time linkage takes place. However, because VxWorks modules are loaded sequentially, in independent load operations, the loader cannot know what modules will be loaded or what sets of common symbols might be encountered in the future.

Therefore, the VxWorks target loader has an option that allows control over how common symbols are linked. The default behavior for the loadLib API functions is to treat common symbols as if there were no previous matching reference (LOAD_COMMON_MATCH_NONE). The result is that every loaded module has its own copy of the symbol. The other possible behaviors are to permit common symbols to be identified either with any matching symbol in the symbol table (LOAD_COMMON_MATCH_ALL), or with any matching symbol that was not in the original booted image (LOAD_COMMON_MATCH_USER).

The option to specify matching of common symbols may be set in each call using the loadLib API. Extreme care should be used when mixing the different possible common matching behaviors for the loader. It is much safer to pick a single matching behavior and to use it for all loads. For detailed descriptions of the matching behavior under each option, see Table 6-6.


*      
NOTE: Note that the shell load command, ld, has a different mechanism for controlling how common symbols are handled and different default behavior. For details, see the reference entry for usrLib.



6.4    Target-Resident Symbol Tables

A symbol table is a data structure that stores information that describes the routines, variables, and constants in all modules, and any variables created from the shell. There is a symbol table library, which can be used to manipulate the two different types of symbol tables: a user system table and a system symbol table, which is the most commonly used.

Symbol Entries

Each symbol in the table comprises three items:

name

value

type

Symbol Updates

The symbol table is updated whenever modules are loaded into, or unloaded from, the target. You can control the precise information stored in the symbol table by using the loader options listed in Table 6-4.

Searching the Symbol Library

You can easily search all symbol tables for specific symbols. To search from the shell, use lkup( ). For details, see the lkup( ) reference entry. To search programmatically, use the symbol library API's, which can be used to search the symbol table by address, by name, and by type, and a function that may be used to apply a user-supplied function to every symbol in the symbol table. For details, see the symLib reference entry.

6.4.1   Configuring VxWorks with Symbol Tables

The basic configuration is required for all symbol tables. This configuration provides the symbol table library, and is sufficient for a user symbol table. However, it is not sufficient for creating a system symbol table. This section describes both the basic configuration, and the additional configuration necessary to create a system symbol table.

For information about user symbol tables, see 6.4.6 Creating User Symbol Tables. For information about the system symbol table, see 6.4.4 Using the VxWorks System Symbol Table.

Basic Configuration

The most basic configuration for a symbol table is to include the component, INCLUDE_SYM_TBL. This provides the basic symbol table library, symLib, (which is not equivalent to the system symbol table) and sufficient configuration for creating user symbol tables. The symbol table library component includes configuration options, which allow you to modify the symbol table width and control whether name clashes are permitted.

  • Hash Table Width

The INCLUDE_SYM_TBL component includes a configuration parameter that allows the user to change the default symbol table "width". The parameter SYM_TBL_HASH_SIZE_LOG2 defines the "width" of the symbol table's hash table. It takes a positive value that is interpreted as a power of two. The default value for SYM_TBL_HASH_SIZE_LOG2 is 8; thus, the default "width" of the symbol table is 256. Using smaller values requires less memory, but degrades lookup performance, so the search takes longer on average. For information about changing this parameter, see the Tornado User's Guide: Configuration and Build.

  • Name Clash Handling

The system symbol table, sysSymTbl, can be configured to allow or disallow name clashes. The flags used to call symTblCreate( ) determine whether or not duplicate names are permitted in a symbol table. If set to FALSE, only one occurrence of a given symbol name is permitted. When name clashes are permitted, the most recently added symbol of several with the same name is the one that is returned when searching the symbol table by name.

System Symbol Table Configuration

To include information about the symbols present in the kernel--and therefore to enable the shell, loader, and debugging facilities to function properly--a system symbol table must be created and initialized. You create a system symbol table at initialization time by including one of the following components:

  • INCLUDE_STANDALONE_SYM_TBL .  

Creates a built-in system symbol table, in which both the system symbol table and the VxWorks image are contained in the same module. This type of symbol table is described in 6.4.2 Creating a Built-In System Symbol Table.

  • INCLUDE_NET_SYM_TBL .  

Creates an separate system symbol table as a .sym file that is downloaded to the VxWorks system. This type of symbol table is described in 6.4.3 Creating a Loadable System Symbol Table.

When the system symbol table is first created at system initialization time, it contains no symbols. Symbols must be added to the table at run-time. Each of these components handles the process of adding symbols differently.


*      
NOTE: When building in a BSP directory, rather than using the project facility, including the component INCLUDE_STANDALONE_SYM_TBL is not sufficient. Instead, build the make target "vxWorks.st." This configuration is for a "standalone" image, and does not initialize the network facilities on the target. To use both the standalone symbol table and the target network facilities, configure your image using the project facility. For details, see the Tornado User's Guide: Projects.

6.4.2   Creating a Built-In System Symbol Table

A built-in system symbol table copies information into wrapper code, which is then compiled and linked into the kernel when the system is built.

Generating the Symbol Information

A built-in system symbol table relies on the makeSymTbl utility to obtain the symbol information. This utility uses the gnu utility nmarch to generate information about the symbols contained in the image. Then it processes this information into the file symTbl.c that contains an array, standTbl, of type SYMBOL described in Symbol Entries. Each entry in the array has the symbol name and type fields set. The address (value) field is not filled in by makeSymTbl.

Compiling and Linking the Symbol File

The symTbl.c file is treated as a normal .c file, and is compiled and linked with the rest of the VxWorks image. As part of the normal linking process, the toolchain linker fills in the correct address for each global symbol in the array. When the build completes, the symbol information is available in the image as a global array of VxWorks SYMBOL's. After the kernel image is loaded into target memory at system initialization, the information from the global SYMBOL array is used to construct the system symbol table.

The definition of the standTbl array can be found in the following files (only after a build). These files are generated as part of the build of the VxWorks image:

installDir/target/config/BSPname/symTbl.c

installDir/target/proj/projDir/buildDir/symTbl.c

Advantages of Using a Built-in System Symbol Table

Although this method creates a resulting VxWorks image (module file) that is larger than it would be without symbols, the built-in symbol table has advantages, some of which are useful when the download link is slow. These advantages are:

  • It saves memory if you are not otherwise using the target loader, because it does not require the target loader (and associated components) to be configured into the system.

  • It does not require the target to have access to a host (unlike the downloadable system symbol table).

  • It is faster than loading two files (the image and .sym files) because network operations4 on a file take longer than the data transfer to memory.

  • It is useful in deployed ROM-based systems that have no network connectivity, but require the shell as user interface.

6.4.3   Creating a Loadable System Symbol Table

A loadable symbol table is built into a separate object module file (vxWorks.sym file). This file is downloaded to the system separately from the system image, at which time the information is copied into the symbol table.

Creating the .sym File

The loadable system symbol table uses a vxWorks.sym file, rather than the symTbl.c file. The vxWorks.sym file is created by using the objcopy utility to strip all sections, except the symbol information, from the final VxWorks image. The resulting symbol information is placed into a file named vxWorks.sym.

For architectures using the ELF object module format for the VxWorks image, the vxWorks.sym file is also in the ELF format, and contains only a SYMTAB section and a STRTAB section. In general, the file vxWorks.sym is in the same object format as other object files compiled for the target by the installed toolchain.

Loading the .sym File

During boot and initialization, the vxWorks.sym file is downloaded using the loader, which directly calls loadModuleAt( ). To download the vxWorks.sym file, the loader uses the current default device, which is described in 4.2.1 Filenames and the Default Device.

To download the VxWorks image, the loader also uses the default device, as is current at the time of that download. Therefore, the default device used to download the vxWorks.sym file may, or may not, be the same device. This is because the default device can be set, or reset, by other initialization code that runs. This modification can happen after the VxWorks image is downloaded, but before the symbol table is downloaded.

Nevertheless, in standard VxWorks configurations, that do not include customized system initialization code, the default device at the time of the download of the vxWorks.sym, is usually set to one of the network devices, and using either rsh or ftp as the protocol.

Advantages of Using the Loadable System Symbol Table

Using a downloadable symbol table requires that the loader component be present. Therefore, the system must have sufficient memory for the loader and its associated components. A summary of the advantages of using the loadable system symbol table are:

  • It is convenient, if the loader is required for other purposes as well.

  • It is slightly faster to build than a built-in system symbol table.

6.4.4   Using the VxWorks System Symbol Table

Once it is initialized, the VxWorks system symbol table includes a complete list of the names and addresses of all global symbols in the compiled image that is booted. This information is needed on the target to enable the full functionality of the 'target tools' libraries. For example:

The target tools maintain the system symbol table so that it contains up to date name and address information for all of the code statically compiled into the system or dynamically downloaded. (You can use the LOAD_NO_SYMBOLS option to hide loaded modules, so that their symbols do not appear in the system symbol table; see Table 6-5).

If the facilities provided by the symbol table library are needed for non-operating system code, another symbol table may be created and manipulated using the symbol library.

Symbols are dynamically added to, and removed from, the system symbol table each time any of the following occurs:

  • as modules are loaded and unloaded

  • as variables are dynamically created using the shell

  • by the wdb agent when synchronizing symbol information with the host

The exact dependencies between the system symbol table and the other target tools are as follows:

Loader

The loader requires the system symbol table. The system symbol table does not require the presence of the loader. The target-based loader and code module management requires the system symbol table when loading code that must be linked against code already on the target.

Debugging Tools

The target-based symbolic debugging, facilities and user commands such as i and tt, rely on the system symbol table to provide information about entry points of tasks, symbolic contents of call stacks, and so on. Without the system symbol table, they can still be used but, their usefulness is greatly reduced.

Target Shell

The target shell does not strictly require the system symbol table, but its functionality is greatly limited without it. The target shell requires the system symbol table to provide the ability to run functions using their symbolic names. The target-based shell uses the system symbol table to execute shell commands, to call system routines, and to edit global variables. The target shell also includes the library usrLib, which contains the commands i, ti, sp, period, and bootChange.

wdb Agent

The wdb agent adds symbols to the system symbol table as part of the symbol synchronization with the host.


*      
NOTE: If you choose to use both the host-resident and target-resident tools at the same time, use the synchronization method to ensure that both the host and target resident tools share the same list of symbols. The synchronization applies only to symbols and modules, not to other information such as breakpoints.

6.4.5   Synchronizing Host and Target-Resident Symbol Tables

There is another symbol table, the target server symbol table, which resides on the host and is used and maintained by the host tools. This symbol table is referred to in this chapter as the host symbol table. The host symbol table can exist even if there is no system symbol table on the target. There is an optional mechanism that relies on the wdb agent, which is used to synchronize the host and target symbol tables information (INCLUDE_SYM_TBL_SYNC). To enable this mechanism on the host, the target server must be started with the -s option. For more information on setting this option for the target server, see the Tornado User's Guide.

6.4.6   Creating User Symbol Tables

Although it is possible for a user application to manipulate symbols in the system's symbol table, this is not a recommended practice. Addition and removal of symbols to and from the symbol table is designed to be carried out only by operating system libraries. Any other use of the system symbol table may interfere with the proper operation of the operating system; and even simply introducing additional symbols could have an adverse and unpredictable effect on linking any modules that are subsequently downloaded.

Therefore, user-defined symbols should not be added programmatically to the system symbol table. Instead, when an application requires a symbol table for its own purposes, a user symbol table should be created. For more information, see the symLib entry in the VxWorks API Reference.



6.5    Show Routines

VxWorks includes system information routines which print pertinent system status on the specified object or service; however, they show only a snapshot of the system service at the time of the call and may not reflect the current state of the system. To use these routines, you must define the associated configuration macro (see the Tornado User's Guide: Projects). When you invoke them, their output is sent to the standard output device. Table 6-8 lists common system show routines:

Table 6-8:   Show Routines


Call
Description
Configuration Macro

envShow( )
Displays the environment for a given task on stdout.
INCLUDE_TASK_SHOW
memPartShow( )
Shows the partition blocks and statistics.
INCLUDE_MEM_SHOW
memShow( )
System memory show routine.
INCLUDE_MEM_SHOW
moduleShow( )
Shows statistics for all loaded modules.
INCLUDE_MODULE_MANAGER
msgQShow( )
Message queue show utility (both POSIX and wind).
INCLUDE_POSIX_MQ_SHOW INCLUDE_MSG_Q_SHOW
semShow( )
Semaphore show utility (both POSIX and wind).
INCLUDE_SEM_SHOW, INCLUDE_POSIX_SEM_SHOW
show( )
Generic object show utility.
stdioShow( )
Standard I/O file pointer show utility.
INCLUDE_STDIO_SHOW
taskSwitchHookShow( )
Shows the list of task switch routines.
INCLUDE_TASK_HOOKS_SHOW
taskCreateHookShow( )
Shows the list of task create routines.
INCLUDE_TASK_HOOKS_SHOW
taskDeleteHookShow( )
Shows the list of task delete routines.
INCLUDE_TASK_HOOKS_SHOW
taskShow( )
Displays the contents of a task control block.
INCLUDE_TASK_SHOW
wdShow( )
Watchdog show utility.
INCLUDE_WATCHDOGS_SHOW

An alternative method of viewing system information is the Tornado browser, which can be configured to update system information periodically. For information on this tool, see the Tornado User's Guide: Browser.

VxWorks also includes network information show routines, which are described in the VxWorks Network Programmer's Guide. These routines are initialized by defining INCLUDE_NET_SHOW in your VxWorks configuration; see the Tornado User's Guide: Configuration and Build. Table 6-9 lists commonly called network show routines:

Table 6-9:   Network Show Routines


Call
Description

ifShow( )
Display the attached network interfaces.
inetstatShow( )
Display all active connections for Internet protocol sockets.
ipstatShow( )
Display IP statistics.
netPoolShow( )
Show pool statistics.
netStackDataPoolShow( )
Show network stack data pool statistics.
netStackSysPoolShow( )
Show network stack system pool statistics.
mbufShow( )
Report mbuf statistics.
netShowInit( )
Initialize network show routines.
arpShow( )
Display entries in the system ARP table.
arptabShow( )
Display the known ARP entries.
routestatShow( )
Display routing statistics.
routeShow( )
Display host and network routing tables.
hostShow( )
Display the host table.
mRouteShow( )
Print the entries of the routing table.



6.6    Common Problems

This section lists frequently encountered problems that can occur when using the target tools.

Target Shell Debugging Never Hits a Breakpoint

I set a breakpoint on a function I called from the target shell, but the breakpoint is not being hit. Why not?

Instead of running the function directly, use taskSpawn( ) with the function as the entry point.

The target shell task runs with the VX_UNBREAKABLE option. Functions that are called directly from the target shell command prompt, are executed within the context of the target shell task. Therefore, breakpoints set within the directly called function will not be hit.

Insufficient Memory

The loader reports insufficient memory to load a module; however, checking available memory indicates the amount of available memory to be sufficient. What is happening and how do I fix it?

Download the file using a different device. Loading an object module from a host file system mounted through NFS only requires enough memory for one copy of the file (plus a small amount of overhead).

The target-resident loader calls the device drivers through a VxWorks' transparent mechanism for file management, which makes calls to open, close, and ioctl. If you use the target-resident loader to load a module over the network (as opposed to loading from a target-system disk), the amount of memory required to load an object module depends on what kind of access is available to the remote file system over the network. This is because, depending on the device that is actually being used for the load, the calls initiate very different operations.

For some devices, the I/O library makes a copy of the file in target memory. Loading a file that is mounted over a device using such a driver requires enough memory to hold two copies of the file simultaneously. First, the entire file is copied to a buffer in local memory when opened. Second, the file resides in memory when it is linked to VxWorks. This copy is then used to carry out various seek and read operations. Therefore, using these drivers requires sufficient memory available to hold two copies of the file to be downloaded, as well as a small amount of memory for the overhead required or the load operation.

"Relocation Does Not Fit" Error Message

When downloading, the following types of error messages occur:

"Relocation does not fit in 26 bits."  

The actual number received in the error message varies (26, or 23, or ...) depending on the architecture. What does this error mean and what should I do?

Recompile the object file using -Xcode-absolute-far for the Diab compilers, and for GNU compilers, the appropriate "long call" option, -mlongCallOption.

Some architectures have instructions that use less than 32 bits to reference a nearby position in memory. Using these instructions can be more efficient than always using 32 bits to refer to nearby places in memory.

The problem arises when the compiler has produced such a reference to something that lies farther away in memory than the range that can be accessed with the reduced number of bits. For instance, if a call to printf is encoded with one of these instructions, the load may succeed if the object code is loaded near the kernel code, but fail if the object code is loaded farther away from the kernel image.

Missing Symbols

Symbols in code modules downloaded from the host do not appear from the target shell, and vice versa. Symbols created from the host shell are not visible from the target shell, or symbols created from the target shell are not visible from the host shell. Why is this happening, and how can I get them to appear?

Check to see if the symbol synchronization is enabled for the target server as well as compiled into the image. For more information, see 6.4.5 Synchronizing Host and Target-Resident Symbol Tables.

The symbol synchronization mechanism must be enabled separately on the host and and target.

Loader is Using Too Much Memory

Including the target loader causes the amount of available memory to be much smaller. How can I get more memory?

Use the host tools (windsh, host loader, and so on) rather than the target tools and remove all target tools from your VxWorks image. For details, see the Tornado User's Guide.

Including the target loader causes the system symbol table to be included. This symbol table contains the name, address, and type of every global symbol in the compiled VxWorks image.

Using the target-resident loader takes additional memory away from your application--most significantly for the target-resident symbol table required by the target-resident loader.

Symbol Table Unavailable

The system symbol table failed to download onto my target. How can I use the target shell to debug the problem, since I cannot call functions by name?

Use addresses of functions and data, rather than using the symbolic names. The addresses can be obtained from the VxWorks image on the host, using the nmarch utility.

The following is an example from a Unix host:

> nmarch vxWorks | grep memShow  
0018b1e8 T memShow  
0018b1ac T memShowInit 

Use this information to call the function by address from the target shell. (The parentheses are mandatory when calling by address.)

-> 0x0018b1e8 () 
 status   bytes    blocks   avg block  max block  
------ --------- -------- ---------- ---------- 
current  
  free   14973336     20      748666     12658120  
  alloc  14201864    16163       878        - 
cumulative  
  alloc  21197888   142523       148        -  
  value = 0 = 0x0 


1:  Provided that suitable hardware is available, standard input and output can be redirected once the shell is running with ioGlobalStdSet( ).

2:  The amount of memory allocated is rounded up to the minimum allocation unit for the architecture in question, plus the amount for the header for that block of memory.

3:  In future releases, calling shell commands programmatically may not be supported.

4:  That use open( ), seek( ), read( ), and close( ).