The Solaris operating environment provides two tools to verify that an application's use of Solaris interfaces conforms to the Solaris ABI. The appcert utility statically examines the Solaris library interfaces used by ELF binaries for instances of private interface usage. The appcert utility produces summary and detailed reports of any potential binary stability problems it finds. The apptrace tool uses the link-auditing capability of the run-time linker to dynamically trace Solaris library routine calls as the application runs. This capability enables developers to examine an application's use of the Solaris system interfaces.
The ABI tools enable easy, rapid identification of binaries that might have binary compatibility problems with a given Solaris release. To check binary stability, perform the following steps:
Use appcert on the current Solaris release for triage. This identifies which binaries use problematic interfaces and which do not.
Use apptrace on the target Solaris release for verification. This verifies whether interface compatibility problems exist by enabling dynamic observation of those interfaces as they are used.
The appcert utility is a Perl script that statically examines ELF binaries and compares the library symbols used against a model of public interfaces and private interfaces in a given Solaris release. The utility runs on either SPARC or Intel platforms. The utility can check interface usage for both SPARC and Intel 32-bit interfaces as well as the 64-bit interfaces on SPARC. Note that appcert only examines C language interfaces.
As new Solaris releases become available, some library interfaces might change their behavior or disappear entirely. These changes can affect the performance of applications that rely on those interfaces. The Solaris ABI defines runtime library interfaces that are safe and stable for application use. The appcert utility is designed to help developers verify an application's compliance with the Solaris ABI.
The appcert utility examines your applications for:
Private symbol usage
Static linking
Unbound symbols
Private symbols are functions or data that is used by Solaris libraries to call each other. The semantic behavior of private symbols might change, and symbols might sometimes be removed. Such symbols are called demoted symbols. The mutable nature of private symbols introduces the potential for instability in applications that depend on private symbols.
The semantics of private symbol calls between Solaris libraries might change between releases. Therefore, the creation of static links to archives degrades an application's binary stability. Dynamic links to the archive's corresponding shared object file avoid this problem.
The appcert utility uses the dynamic linker to resolve the library symbols that are used by the application being examined. Symbols that the dynamic linker cannot resolve are called unbound symbols. Unbound symbols might be caused by environment problems, such as an incorrectly set LD_LIBRARY_PATH variable. Unbound symbols might also be caused by build problems, such as omitting the definitions of the -llib or -z switches at compile time. While these examples are minor, unbound symbols that are reported by appcert might indicate a more serious problem, such as a dependency on a private symbol that no longer exists.
If the object file appcert is examining depends on libraries, those dependencies must be recorded in the object. To do so, be sure to use the compiler's -l switch when compiling the code. If the object file depends on other shared libraries, those libraries must be accessible through LD_LIBRARY_PATH or RPATH at the time you run appcert.
The appcert application cannot check 64–bit applications unless the machine is running the 64–bit Solaris kernel. Since Solaris provides no 64–bit static libraries, appcert does not perform static-linking checks on 64–bit applications.
The appcert utility cannot examine:
Object files that are completely or partially statically linked. A completely statically linked object is reported as unstable.
Executable files that do not have the execute permission set. The appcert utility skips such executables. Shared objects without the execute permission set are examined normally.
Object files whose user ID is set to root.
Non-ELF executables, such as shell scripts.
Solaris interfaces in languages other than C. The code need not be in C, but the call to the Solaris library must be.
To check your application with appcert, type:
appcert object|directory |
replacing object|directory with either:
The complete list of objects you want appcert to examine
The complete list of directories that contain such objects
You might run appcert in an environment that is different from the environment in which the application runs. If these environments are different, appcert might not be able to correctly resolve references to Solaris library interfaces.
The appcert utility uses the Solaris runtime linker to construct a profile of interface dependencies for each executable or shared object file. This profile is used to determine the Solaris system interfaces upon which the application depends. The dependencies that are outlined in the profile are compared to the Solaris ABI to verify conformance. No private interfaces should be found.
The appcert utility recursively searches directories for object files, ignoring non-ELF object files. After appcert has finished checking the application, appcert prints a rollup report to the standard output, usually the screen. A copy of this report is written in the working directory, which is usually /tmp/appcert.pid, in a file that is named Report. In the subdirectory name, pid represents the 1–to–6 digit process ID of that particular instantiation of appcert. See appcert Results for more on the directory structure to which appcert writes output files.
The following options modify the behavior of the appcert utility. You can type any of these options at the command line, after the appcert command but before the object|directory operand.
Runs appcert in batch mode.
In batch mode, the report produced by appcert contains one line for each binary checked.
A line that begins with PASS indicates the binary that is named in that line did not trigger any appcert warnings.
A line that begins with FAIL indicates problems were found in that binary.
A line that begins with INC indicates the binary that is named in that line could not be completely checked.
The file infile should contain a list of files to check, with one file name per line. These files are added to any files already specified at the command line. If you use this switch, you do not need to specify an object or directory at the command line.
Prints usage information for appcert.
By default, appcert notes any shared objects in an application, and appends the directories in which the shared objects reside to LD_LIBRARY_PATH. The -L switch disables this behavior.
By default, appcert follows symbolic links when appcert searches directories for binaries to check. The -n switch disables this behavior.
Appends the Solaris library directories /usr/openwin/lib and /usr/dt/lib to LD_LIBRARY_PATH.
Specifies a directory in which to run the library components. Temporary files are also created in the directory specified by this switch. If this switch is not specified, appcert uses the /tmp directory.
The appcert utility can be used to quickly and easily discern which applications in a given set have potential stability problems. If appcert does not report any stability problems, the application is not likely to encounter binary stability problems in subsequent Solaris releases. The following table lists some common binary stability problems.
Table 11–1 Common Binary Stability Problems
Problem |
Course of Action |
---|---|
Use of a private symbol that is known to change |
Eliminate use of symbol immediately. |
Use of a private symbol that has not changed yet |
Application can still be run for now, but eliminate use of symbol as soon as practical. |
Static linking of a library with a shared object counterpart |
Use shared object counterpart instead. |
Static linking of a library with no shared object counterpart |
Convert .a file to .so file by using the command ld -z allextract if possible. Otherwise, continue to use static library until shared object is available. |
Use of a private symbol for which no public equivalent is available |
Contact Sun and request a public interface. |
Use of a symbol that is deprecated, or use of a symbol that is planned for removal |
Application can still be run for now, but eliminate use of symbol as soon as practical. |
Use of a public symbol that has changed |
Recompile. |
Potential stability problems caused by the use of private interfaces might not occur on a given release. The behavior of private interfaces does not always change between releases. To verify that a private interface's behavior has changed in the target release, use the apptrace tool. Usage of apptrace is discussed in Using apptrace for Application Verification.
The results of the appcert utility's analysis of an application's object files are written to several files that are located in the appcert utility's working directory, typically /tmp. The main subdirectory under the working directory is appcert.pid, where pid is the process ID for that instantiation of appcert. The appcert utility's results are written to the following files:
Contains the mapping between checked binaries and the subdirectory in which appcert output specific to that binary is located.
Contains a copy of the rollup report that is displayed on stdout when appcert is run.
Contains a list of binaries that appcert was asked to check but was forced to skip, along with the reason each binary was skipped. These reasons are in the following list:
File is not a binary object
File cannot be read by the user
File name contains metacharacters
File does not have the execute bit set
A separate subdirectory is under the objects subdirectory for each object examined by appcert. Each of these subdirectories contains the following files:
check.demoted.symbols |
Contains a list of symbols that appcert suspects are demoted Solaris symbols. |
|
check.dynamic.private |
Contains a list of private Solaris symbols to which the object is directly bound. |
|
check.dynamic.public |
Contains a list of public Solaris symbols to which the object is directly bound. |
|
check.dynamic.unbound |
Contains a list of symbols not bound by the dynamic linker when running ldd -r. Lines returned by ldd containing “file not found” are also included. |
|
summary.dynamic |
Contains a printer-formatted summary of dynamic bindings in the objects appcert examined, including tables of public and private symbols used from each Solaris library. |
Returns one of four exit values.
No potential sources of binary instability were found by appcert.
The appcert utility did not run successfully.
Some of the objects checked by appcert have potential binary stability problems.
The appcert utility did not find any binary objects to check.
Private Symbol Use – An application that depends on private symbols might not run on a Solaris release different from the one in which it was developed. This phenomenon occurs because private symbols that occur in a given Solaris release might behave differently or not be present in another release. If appcert reports private symbol usage in your application, rewrite the application to avoid the use of private symbols.
Demoted Symbols – Demoted symbols are functions or data variables in a Solaris library that have been removed or have been scoped locally in a later Solaris release. An application that directly calls such a symbol fails to run on a release whose libraries do not export that symbol.
Unbound Symbols – Unbound symbols are library symbols that are referenced by the application that the dynamic linker was unable to resolve when called by appcert. While unbound symbols are not always an indicator of poor binary stability, unbound symbols might indicate a more serious problem, such as dependencies on demoted symbols.
Obsolete Library – An obsolete library might be removed from the Solaris operating environment in a future release. The appcert utility flags any use of such a library. Applications that depend on such a library might not function in a future release that does not feature the library. To avoid this problem, do not use interfaces from obsolete libraries.
Use of sys_errlist or sys_nerr – The use of the sys_errlist and sys_nerr symbols might degrade binary stability. A reference might be made past the end of the sys_errlist array. To avoid this risk, use strerror instead.
Use of strong and weak symbols – The strong symbols that are associated with weak symbols are reserved as private because their behavior might change in future Solaris releases. Applications should only directly reference weak symbols. An example of a strong symbol is _socket, which is associated with the weak symbol socket.
The apptrace utility is a C program which dynamically traces calls to Solaris library routines as an application runs. apptrace works on either SPARC or Intel platforms. apptrace can trace interface calls for both SPARC and Intel 32-bit interfaces, as well as the 64-bit interfaces on SPARC. As with appcert, apptrace only examines C language interfaces.
After using appcert to determine an application is at risk of binary instability, apptrace helps assess the degree of risk in each case. To determine an application's binary compatibility with a given release, verify the successful use of each interface used by the application with apptrace.
The apptrace utility can verify that an application is using public interfaces correctly. For example, an application that is using the open() to open the administrative file /etc/passwd directly should instead use the appropriate programmatic interfaces. This ability to inspect the usage of the Solaris ABI enables easy and rapid identification of potential interface problems.
The apptrace utility does not require any modification of the application being traced. To use apptrace, type apptrace, followed by any desired options along with the command line used to run the application of interest. The apptrace utility works by using the link-auditing capability of the runtime linker to intercept the application's calls to Solaris library interfaces. The apptrace utility then traces the calls by printing the names and values of the call's arguments and return value. The tracing output can be on a single line or arranged across multiple lines for readability. Public interfaces are printed in human-readable form. Private interfaces are printed in hexadecimal.
The apptrace utility enables selective tracing of calls, both at the level of individual interfaces and the level of libraries. For example, apptrace can trace calls to printf() coming from libnsl, or a range of calls within a specific library. The apptrace utility can also verbosely trace user-specified calls. The specifications that dictate apptrace behavior are governed by a syntax that is consistent with the usage of truss(1). The -f option directs apptrace to follow forked child processes. The -o option specifies an output file for apptrace results.
The apptrace utility traces only library-level calls and is loaded into the running application process, gaining a performance increase over truss. With the exception of printf, apptrace cannot trace calls to functions that accept variable argument lists or examine the stack or other caller information, for example, setcontext, getcontext, setjmp, longjmp, and vfork.
The following examples contain sample apptrace output from tracing a simple one-binary application, ls.
% apptrace ls /etc/passwd ls -> libc.so.1:atexit(func = 0xff3cb8f0) = 0x0 ls -> libc.so.1:atexit(func = 0x129a4) = 0x0 ls -> libc.so.1:getuid() = 0x32c3 ls -> libc.so.1:time(tloc = 0x23918) = 0x3b2fe4ef ls -> libc.so.1:isatty(fildes = 0x1) = 0x1 ls -> libc.so.1:ioctl(0x1, 0x540d, 0xffbff7ac) ls -> libc.so.1:ioctl(0x1, 0x5468, 0x23908) ls -> libc.so.1:setlocale(category = 0x6, locale = "") = "C" ls -> libc.so.1:calloc(nelem = 0x1, elsize = 0x40) = 0x23cd0 ls -> libc.so.1:lstat64(path = "/etc/passwd", buf = 0xffbff6b0) = 0x0 ls -> libc.so.1:acl(pathp = "/etc/passwd", cmd = 0x3, nentries = 0x0, aclbufp = 0x0) = 0x4 ls -> libc.so.1:qsort(base = 0x23cd0, nel = 0x1, width = 0x40, compar = 0x12038) ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:strlen(s = "") = 0x0 ls -> libc.so.1:strlen(s = "/etc/passwd") = 0xb ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:strlen(s = "") = 0x0 ls -> libc.so.1:printf(format = 0x12ab8, ...) = 11 ls -> libc.so.1:printf(/etc/passwd format = 0x12abc, ...) = 1 ls -> libc.so.1:exit(status = 0) |
The previous example shows the default tracing behavior, tracing every library call on the command ls /etc/passwd. The apptrace utility prints a line of output for every system call, indicating:
The name of the call
The library the call is in
The arguments and return values of the call
% apptrace -t \*printf ls /etc/passwd ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:printf(format = 0x12ab8, ...) = 11 ls -> libc.so.1:printf(/etc/passwd format = 0x12abc, ...) = 1 |
The previous example shows how apptrace can selectively trace calls with regular-expression syntax. In the example, calls to interfaces ending in printf, which include sprintf, are traced in the same ls command as before. Consequently, apptrace only traces the printf and sprintf calls.
% apptrace -v sprintf ls /etc/passwd ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 buf = (char *) 0x233d0 "" format = (char *) 0x12af8 "%s%s%s" ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 buf = (char *) 0x233d0 "" format = (char *) 0x12af8 "%s%s%s" /etc/passwd |
The previous example shows the verbose tracing mode, where the arguments to sprintf are printed on multiple output lines for readability. At the end, apptrace displays the output of the ls command.