Chapter 12. adb Macros: Part One

One of the most powerful and commonly used features of adb also happens to be one of the least well documented: adb macros. adb allows the user to read in adb commands from ASCII files instead of typing them by hand. These files, adb macro files, can contain very simple one line commands or more complex sequences that in turn can read in other macros, creating several layers of nested invocations.

The gurus who analyze UNIX system crash dump savecore files daily use macros often, saving themselves a lot of time as well as wear and tear on their fingers.

Even though adb macros are simply adb commands stored in a file, writing them is still a bit of a black art in its own right. Vendors, such as Sun, even go so far as to provide a tool to automatically generate adb macros so that the programmer need not write them from scratch. This tool is called adbgen and requires use of a C compiler.

Not everyone has access to a C compiler, so in this and the next two chapters we will not only tell you about some of the standard adb macros you might find on your UNIX system, we will also show you how to write and use your own macros without depending on adbgen.

The macro library

Most, but not all, UNIX vendors provide a directory containing adb macros. Since each flavor of UNIX differs at the kernel level, you can expect the macros to differ from vendor to vendor, from architecture to architecture, and, to a lesser degree, between operating system releases running on a vendor’s hardware platform.

In Solaris 1, the standard adb macros provided by Sun are maintained in the directory /usr/lib/adb. On Solaris 2 systems, the macros are kept in /usr/kvm/lib/adb.

Reading and understanding macros

Since adb macros contain adb commands, you should first become comfortable with adb in general before moving on to macros. Once you are ready to tackle macros, probably the easiest way to get started is by looking at the macros provided on your UNIX system while trying out the commands on a live kernel or a set of system crash dump files. If you happen to start off with the more complex macros, it is quite easy to become discouraged rather quickly, so try to work with the simplier macros at first.

Invoking adb macros

The first thing we need to understand is that some macros start working at adb’s current address, dot (.), whereas others will specify a starting location internally.

While in adb, macros are called by using the command syntax:

$<macroname 

If you need to feed the macro a new current address to work with, or a symbol name, you invoke it by using the syntax:

address$<macroname 

In this chapter, we will explore macros that demonstrate examples of each syntax.

The utsname macro

We’ve already seen one macro in use on a Solaris 2 system, utsname. As a refresher, here is how we called the utsname macro while in adb analyzing postmortem files. Note that this macro is not given a specific address with which to work.

Example 12-1. Using the utsname macro

Hiya...  adb -k unix.1 vmcore.1 
physmem 1b24 
$<utsname 
utsname: 
utsname:        sys  SunOS 
utsname+0x101:  node  panic 
utsname+0x202:  release  5.3 
utsname+0x303:  version  Generic 
utsname+0x404:  machine  sun4c 
$q 
Hiya... 

In adb, $< says to bring in or execute a macro, in this case the utsname macro. If you like, think of this as being like UNIX I/O redirection. Unless we specify a full pathname, adb assumes we want to work with the utsname macro file stored in the /usr/kvm/lib/adb directory.

Let’s take a look at /usr/kvm/lib/adb/utsname.

Example 12-1. The utsname macro

Hiya...  cd /usr/kvm/lib/adb 
Hiya...  more utsname 
utsname/"sys"8t257c 
+/"node"8t257c 
+/"release"8t257c 
+/"version"8t257c 
+/"machine"8t257c 
Hiya... 

The first thing this macro does is change our current location within adb to where the variable utsname is stored. The text “sys” is printed solely for the user’s sake, helping him to understand what is being output. The 8t says to tab out to the nearest tab stop located at a column that is a multiple of 8, then display up to 257 printable characters.

Now we move on to the next line of the utsname macro. We use + to advance our current location according to the previous display format we used. We print “node”, tab out for readability, and display up to another 257 characters.

Continuing to the last three lines, we repeat this whole process for “release”, “version”, and “machine”.

Now, how do we know what this macro is showing us? Well, if we poke around in the /usr/include/sys directory, we will find a header file called utsname.h. (Isn’t that convenient? Don’t count on such ease all of the time!) Within utsname.h we find the following information, although it is not all clustered together as shown below.

Example 12-2. Excerpts from /usr/include/sys/utsname.h

#define _SYS_NMLN       257    /* 4.0 size of utsname elements */ 
                               /* Must be at least 257 to      */ 
                               /* support Internet hostnames.  */ 
struct utsname {
      char    sysname[_SYS_NMLN]; 
      char    nodename[_SYS_NMLN]; 
      char    release[_SYS_NMLN]; 
      char    version[_SYS_NMLN]; 
       char    machine[_SYS_NMLN]; 
}; 

extern struct utsname utsname; 

Using what we have learned so far, we can see in /usr/include/sys/utsname.h that utsname is the name given to a type of defined structure. The five elements of this structure contain character strings of _SYS_NMLN or 257 decimal in length. Finally, we see that the utsname structure was used elsewhere (extern) to declare a structure variable, also called utsname. In this case, to see this structure’s definition, we would have to look at the source. However, as we have seen by using the utsname macro, it is quite safe to assume that the declared utsname structure contains the system information we would expect to see there.

If you don’t happen to have a set of system crash dump files to experiment with at this time and you want to look at the utsname structure on your own Solaris 2 system, go ahead and run adb on the running kernel. To do this, you will need to be root. As an example, here is an adb session that looks at an actively running system.

Hiya... su 
Password: 
# adb -k /dev/ksyms /dev/mem 
physmem 1e15 
$<utsname 
utsname: 
utsname:        sys     SunOS 
utsname+0x101:  node    pasta 
utsname+0x202:  release 5.3 
utsname+0x303:  version Generic_Patch 
utsname+0x404:  machine sun4c 
$q 
# 

Let’s take a look at another relatively simple macro from the /usr/kvm/lib/adb directory on a Solaris 2 system and figure out what it does.

The bootobj macro

The bootobj macro is a three-line macro and, reading it, appears to show information about a file system. Here is the macro.

Example 12-3. The bootobj macro

Hiya...  cd /usr/kvm/lib/adb 
Hiya...  cat bootobj 
./"fstype"16t16C 
+/"name"16t128C 
+/"flags"16t"size"16t"vp"n3X 
Hiya... 

Unfortunately, unlike the utsname macro, execution of the bootobj macro starts at location “. ”, which means the current location. This is an example of a macro that we must call by specifying a symbol name or a new current address where the macro would start its work. The question is: For which file system or file systems was this macro designed to display data? We’ll see if we can figure that out shortly. First, let’s discuss what this macro does step by step.

The first line displays “fstype” for readability, tabs out to the display position that is a multiple of 16, then displays 16 characters. Note, unlike in the utsname macro, we are using an uppercase C modifier instead of the lowercase c. The difference is that the uppercase C says to show the contents of all 128 character positions whether or not they contain printable ASCII characters. When the value stored in memory is not printable, a “control character” representation (such as ^@ for a null byte) is printed instead.

The second line advances the current address and displays 128 characters, apparently a name of some sort, judging from the fact that we print “name” before the characters.

The last macro command line will generate two lines of output. The first line will have the words “flags”, “size”, and “vp” separated by tabs. The n says to print a newline. The 3X modifier says to display the contents of three full-word addresses in hexadecimal.

By default, adb allows for 16 character positions for each full-word hexadecimal value displayed, with a maximum of four full words displayed per line, or 4X if we were speaking in terms of adb modifiers. Knowing this about adb, the macro’s author has the “flags”, “size”, and “vp” identifiers similarly tabbed out, using the 16t modifier.

So, we now know what the macro does. Next, let’s see if we can figure out with which kernel variables this macro was designed to be used. The first place we might look would be the namelist, which we can examine via the UNIX nm command. In this case, we will pipe the output of nm into the UNIX grep command, searching for bootobj or something similar. We are only interested in objects, such as variables and structures, instead of kernel routines and other symbols, so we use grep a second time to print out the nm OBJT matches only.

Hiya...  nm /dev/ksyms | grep -i bootobj | grep OBJT 
Hiya...  nm /dev/ksyms | grep -i boot | grep OBJT 
[469]   |4027923924|      52|OBJT |LOCL |0    |ABS    |bootcode 
[5034]  |4232978432|      12|OBJT |LOCL |0    |ABS    |bootparam_addr 
[6815]  |4027926848|       4|OBJT |GLOB |0    |ABS    |path_to_inst_bootstrap 
[7229]  |4028089244|     256|OBJT |GLOB |0    |ABS    |kern_bootargs 
[7402]  |4028089636|       4|OBJT |GLOB |0    |ABS    |boothowto 
[7482]  |4027920040|       4|OBJT |GLOB |0    |ABS    |bootops 
[7501]  |4028092332|       4|OBJT |GLOB |0    |ABS    |kmacctboot 
[8707]  |4028112416|       4|OBJT |GLOB |0    |ABS    |netboot 
Hiya... 

Well, that wasn’t very helpful. Next, we will dig through the /usr/include header files. It is probably safe to assume that bootobj has something to do with the booting sequence, so we will dig through the sys subdirectory as a starting point. If that fails to find what we are looking for, we can start the search at /usr/include next time.

In this example, we will use the UNIX find command to grep through all of the sys header files. If you aren’t familiar with the find or grep commands, please refer to the man pages.

Hiya...  cd /usr/include/sys 
Hiya...  find . -exec grep -i bootobj {} /dev/null ; 
./bootconf.h:struct bootobj {
./bootconf.h:extern struct bootobj rootfs; 
./bootconf.h:extern struct bootobj dumpfile; 
./bootconf.h:extern struct bootobj swapfile; 
Hiya... 

Note

The use of /dev/null in the grep command exec’ed within the find command may have you wondering a bit. If only one filename is given for grep to search, we will not see the name of the file along with the matching strings. We are using /dev/null as nothing more than a second file name. Actually, any filename would have done. Try the same command with and without /dev/null specified, and you’ll understand the significance of using it.

So, we have found that /usr/include/sys/bootconf.h defines a bootobj structure. We need to read this header file to learn more about this structure. Here is the portion of /usr/include/sys/bootconf.h that talks about the bootobj structure.

Example 12-4. Excerpts from /usr/include/sys/bootconf.h

/* 
 * Boot configuration information 
 */ 

#define BO_MAXFSNAME    16 
#define BO_MAXOBJNAME   128 

struct bootobj {
        char  bo_fstype[BO_MAXFSNAME];        /* vfs type name (e.g. nfs) */ 
        char  bo_name[BO_MAXOBJNAME];         /* name of object */ 
        int   bo_flags;                       /* flags, see below */ 
        int   bo_size;                        /* number of blocks */ 
        struct vnode *bo_vp;                  /* vnode of object */ 
}; 

/* 
 * flags 
 */ 
#define BO_VALID        0x01    /* all information in object is valid */ 
#define BO_BUSY         0x02    /* object is busy */ 

extern struct bootobj rootfs; 
extern struct bootobj dumpfile; 
extern struct bootobj swapfile; 

As defined here, bootobj structures consist of 16 characters reflecting a virtual file system type, 128 characters representing an object name, a full-word integer flags value, another integer showing the size in blocks, and finally, a pointer (a full-word value) to a vnode structure declared as *bo_vp. So far, this is right in line with what the bootobj macro will be displaying.

Only three structures of type bootobj are declared for use. These are dumpfile, which we have seen earlier, rootfs, and swapfile. These three variables will be in the symbol table. To confirm this, we will quickly grep through nm’s output.

Hiya...  nm /dev/ksyms | grep rootfs 
[8662]  |4027916920|     156|OBJT |GLOB |0    |ABS    |rootfs 
Hiya...  nm /dev/ksyms | grep swapfile 
[1285]  |4028028788|       4|OBJT |LOCL |0    |ABS    |nswapfiles 
[8378]  |4027917076|     156|OBJT |GLOB |0    |ABS    |swapfile 
Hiya...  nm /dev/ksyms | grep dumpfile 
[6059]  |4027917232|     156|OBJT |GLOB |0    |ABS    |dumpfile 
Hiya... 

Note that the sizes of rootfs, swapfile, and dumpfile are each listed as 156. This decimal value represents the size in bytes. Does it fit what we found in the bootobj structure? Absolutely!

16 chars + 128 chars + 3 full words = 16 bytes + 128 bytes + 12 bytes = 156 bytes

We are now fairly confident what the bootobj macro was designed to examine. Let’s use adb to look at all three variables on a live system Remember, since the bootobj macro starts at the current address, we need to feed the macro a valid starting point.

Example 12-2. Using the bootobj macro against three kernel variables

# adb -k /dev/ksyms /dev/mem 
physmem 1e15 
rootfs$<bootobj 
rootfs: 
rootfs:         fstype          ufs^@^@^@^@^@^@^@^@^@^@^@^@^@ 
rootfs+0x10:    name            /iommu@f,e0000000/sbus@f,e0001000/espdma@f,40000 
                0/esp@f,800000/sd@3,0:a^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@ 
rootfs+0x90:    flags           size            vp 
                0               0               0 
swapfile$<bootobj 
swapfile: 
swapfile:       fstype          ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
swapfile+0x10:  name            ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@ 
swapfile+0x90:  flags           size            vp 
                0               0               0 
dumpfile$<bootobj 
dumpfile: 
dumpfile:       fstype          ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
dumpfile+0x10:  name            /dev/dsk/c0t1d0s1^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
                ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ 
dumpfile+0x90:  flags           size            vp 
                0               30200           fc2d7604 
$q 

To find out how these structures are initialized and later used, we would have to look at the source code.

We have learned a few new concepts by examining the bootobj macro, most importantly, how to attempt to establish what variables the macro was designed to be used with when its execution starts at the current location, “.”.

Summary

To summarize, after looking at the utsname and bootobj macros, we have seen how to use the following adb commands within a macro:

symbolname/        Change the current address +/                 Advance the current address /“printed text”    Print text for our own use /t                 Tab over /c                 Print byte as a character (if displayable) /C                 Print byte as a character (or ^@ if not displayable) /X                 Print full word as a hexadecimal value /n                 Print a newline 

In the next chapter, we will tackle some of the more complex macros and their features.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.24.134