Displaying Memory

Almost any boot monitor you use with an embedded system provides some type of memory display command. The memory display command can be a very useful tool, even for the high-level software developer. If the memory display command supports the hexadecimal and decimal display of address space and provides for 1-, 2-, and 4-byte data units, the CLIs fundamental ability to deal with symbols allows the monitor to display variables in their basic symbolic form. For example, assume I have a short variable called varB and I want to display it in decimal. I could use the following command:

 dm 2d %varB 1 

where dm is the display memory command, -2d is an option string indicating that the data is to be displayed in two-byte decimal units, %varB is the name of the variable to be displayed, and 1 indicates that only one unit is to be displayed. The result is that you have the ability to display variables just as you would with a high-level debugger, and all you need to do is make sure that your on-board symtbl file is synchronized with the application youre debugging.

You could go one step further and build a few simple scripts that save on the typing. For example, the following scripts display different integer formats

file int2:

 dm 2d $ARG1 1     #Decimal 16-bit integer 

file uint4:

 dm 4 $ARG1        #Hex 32-bit integer (no d option, means display      in hexadecimal) 

Now instead of typing dm 2d %varB 1 , the int2 script could be used:

 int2 %varB 

A simple -s option could also be incorporated into dm so that memory could be displayed as character strings instead of raw hexadecimal. Listing 12.1 is the start of the code for the monitor command that implements this display memory command, dm .

Listing 12.1: Code for Display Memory Command.
image from book
 char *DmHelp[] = {     "Display Memory",     "-[24bdefs] {addr} [cnt]",     " -2   short access",     " -4   long access",     " -b   binary",     " -d   decimal",     " -e   endian swap",     " -f   fifo mode",     " -m   use 'more'",     " -s   string",     " -v {var} quietly load 'var' with element at addr",     0, }; #define BD_NULL         0 #define BD_RAWBINARY    1 #define BD_ASCIISTRING  2 int Dm(int argc,char *argv[]) {     int     i, count, count_rqst, width, opt, more, size, fifo;     int     hex_display, bin_display, endian_swap;     char    *varname, *prfmt, *vprfmt;     uchar   *cp, cbuf[16];     ushort  *sp;     ulong   *lp, add;     width = 1;     more = fifo = 0;     bin_display = BD_NULL;     hex_display = 1;     endian_swap = 0;     varname = (char *)0;     while((opt=getopt(argc,argv,"24bdefmsv:")) != -1) {         switch(opt) {         case '2':             width = 2;             break;         case '4':             width = 4;             break;         case 'b':             bin_display = BD_RAWBINARY;             break;         case 'd':             hex_display = 0;             break;         case 'e':             endian_swap = 1;             break;         case 'f':             fifo = 1;             break;         case 'm':             more = 1;             break;         case 'v':             varname = optarg;             break;         case 's':             bin_display = BD_ASCIISTRING;             break;         default:             return(CMD_PARAM_ERROR);         }     }     add = strtoul(argv[optind],(char **)0,0);     if (argc-(optind-1) == 3) {         count_rqst = strtoul(argv[optind+1],(char **)0,0);         count_rqst *= width;     }     else         count_rqst = 128; 
image from book
 

Listing 12.1 details the argument option processing. The first few lines are a default initialization. A call to getopt() allows the user to override the default options. Options include specification of the width of the accesses (default is 1 byte; short and long accesses can be set). The ability to dump from FIFO is provided, as are a few other variations on the format of the output, such as dumping raw binary, endian-swapping the data, dumping ASCII strings, or presenting the values in decimal (instead of the default ASCII-coded hexadecimal). The final half- dozen lines of Listing 12.1 retrieve arguments from the command line to establish the address of the memory dump and the size.

Listing 12.2 lists the code that formats the result. The content of the hex_display and width variables are used to build a format string that printf uses later in the function. Two format strings are built in Listing 12.2. One format string is for the output of the data to the console ( prfmt ), and the other is for formatting the content of a shell variable that might have been specified by the v option ( vprfmt ).

Listing 12.2: Formatting the Results.
image from book
 if (hex_display) {         switch(width) {         case 1:             prfmt = "%02X ";             break;         case 2:             prfmt = "%04X ";             break;         case 4:             prfmt = "%08X ";             break;         }         vprfmt = "0x%x";     }     else {         switch(width) {         case 1:             prfmt = "%3d ";             break;         case 2:             prfmt = "%5d ";             break;         case 4:             prfmt = "%12d ";             break;         }         vprfmt = "%d";     } 
image from book
 
Listing 12.3: Binary and ASCII Formatting.
image from book
 if (bin_display != BD_NULL) {         cp = (uchar *)add;         if (bin_display == BD_ASCIISTRING) {             puts(cp);             if (varname) {                 shell_sprintf(varname,vprfmt,cp+strlen(cp)+1);             }         }         else {             for(i=0;i<count_rqst;i++) {                 putchar(*cp++);             }         }         putchar('\n');         return(CMD_SUCCESS);     } 
image from book
 

If the option to display as binary or ASCII string is set, the code of Listing 12.3 is executed, and the command is completed. Note that for either of these display modes, the access width is 1 byte only.

The final loop (see Listing 12.4) is the code that dumps memory in 1-, 2-, or 4- byte units. The listing shows only the code for width == 2 . The other width options are processed similarly. Every 16 bytes, a new line is started. If the v option is used, then there is no display. The content of the specified address is simply placed into a shell variable, and the command completes. The loop itself is used to support the m option, which, if used, prompts the user for more data to be dumped.

Listing 12.4: Controlling Data Width.
image from book
 do {         count = count_rqst;         if (width == 1) {              ...         }         else if (width == 2) {             sp = (ushort *)add;                  if (varname) {                 shell_sprintf(varname,vprfmt,                     endian_swap ? swap2(*sp) : *sp);             }             else {                 while(count>0) {                     printf("%08lx: ",(ulong)sp);                     if (count > 16)                         size = 16;                     else                             size = count;                              for(i=0;i<size;i+=2) {                         printf(prfmt,                             endian_swap ? swap2(*sp) : *sp);                         if (!fifo)                             sp++;                     }                     putchar('\n');                     count -= size;                     if (!fifo) {                         add += size;                         sp = (ushort *)add;                     }                 }             }         }         else if (width == 4) {              ...         }     } while (more && More());     return(CMD_SUCCESS); } 
image from book
 


Embedded Systems Firmware Demystified
Embedded Systems Firmware Demystified (With CD-ROM)
ISBN: 1578200997
EAN: 2147483647
Year: 2002
Pages: 118
Authors: Ed Sutter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net