Logo Search packages:      
Sourcecode: lcrash version File versions  Download package

cmd_search.c

/*
 * $Id: cmd_search.c,v 1.1 2005/02/25 22:04:04 tjm Exp $
 *
 * This file is part of lcrash, an analysis tool for Linux memory dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, and others
 *
 * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#include <lcrash.h>

#define MAX_SEARCH_SIZE 256

/* Global variables used in pattern match 
 */
kaddr_t curaddr;
FILE *of;
int align = 0;
char mask_str[MAX_SEARCH_SIZE+1];
char pattern_str[MAX_SEARCH_SIZE+1];
unsigned mask[MAX_SEARCH_SIZE / 4];

/* External prototype
 */
int kl_paddr_in_dump(kaddr_t);

/*
 * is_vmalloc_addr()
 */
kaddr_t
is_vmalloc_addr(kaddr_t addr)
{
      if (VMALLOC_START && 
                  ((addr >= VMALLOC_START) && (addr < VMALLOC_END))) {
            return(1);
      }
      return(0);
}

/*
 * get_mask_str()
 */
static int
get_mask_str(command_t *cmd, option_t *op)
{
      int i, nchars;

      if (!op->op_arg) {
            return (1);
      }

      /* Get the size of the mask string
       */
      nchars = strlen(op->op_arg);
      if (nchars > MAX_SEARCH_SIZE) {
            nchars = MAX_SEARCH_SIZE;
      }

      /* Check to see if the hex value provided in pattern has a
       * 0x prefix. If it does, then strip it off (it messes up
       * mask and nbytes count).
       */
      if (nchars > 2 && (!strncmp(op->op_arg, "0X", 2) ||
                  !strncmp(op->op_arg, "0x", 2))) {
            nchars -= 2;
            bcopy (&op->op_arg[2], mask_str, nchars);
      } else {
            bcopy (op->op_arg, mask_str, nchars);
      }
      mask_str[nchars] = 0;

      /* Make sure all the characters in our mask string are valid hex
       * digits.
       */
      for (i = 0; i < nchars; i++) {
            if (!isxdigit(mask_str[i])) {
                  fprintf(cmd->ofp, "%c: invalid mask digit\n", 
                        mask_str[i]);
                  return(1);
            }
      }
      return(0);
}

/*
 * set_value()
 */
static int
set_value(char *str, unsigned char *valstr, int max, int align)
{
      int j = 0, n, diff, nchars, ndigits;
      uint64_t value;
      char *s, w[19];
      void *v = valstr;

      s = str;
      nchars = strlen(s);
      if (nchars > max) {
            nchars = max;
      }
      ndigits = (align * 2);

      /* Force the 0x prefix to the value to ensure it is translated
       * as a hex value by GET_VALUE()
       */
      strcpy(w, "0x");
      if ((diff = (nchars % align))) {
            /* Pad the end of the string with zeros upto the next 
             * align unit  boundary.
             */
            n = nchars;
            while (n < (nchars + diff)) {
                  str[n] = '0';
                  n++;
            }
            str[n] = 0;
            nchars = n;
      }
      while (j < (nchars / ndigits)) {
            strncpy(w+2, s, ndigits);
            w[ndigits+2] = 0;
            GET_VALUE(w, &value);
            if (KL_ERROR) {
                  fprintf(KL_ERRORFP, "%s: invalid value\n", w);
                  return(1);
            }
            if (align == 8) {
                  *(uint64_t*)v = (uint64_t)value;
            } else if (align == 4) {
                  *(uint32_t*)v = (uint32_t)value;
            } else if (align == 2) {
                  *(uint16_t*)v = (uint16_t)value;
            } else {
                  *(uint8_t*)v = (uint8_t)value;
            }
            j++;
            v = (void *)((unsigned long)v + align);
            s += ndigits;
      }
      return(0);
}

static void
match_found(int off)
{
      kaddr_t adr = curaddr+off;

      fprintf(of, "MATCH: found at ");
      if ((adr >= KL_PAGE_OFFSET) || is_vmalloc_addr(curaddr+off)) {
            fprintf(of, "0x%"FMTPTR"x\n", adr);
      } else {
            fprintf(of, "physical address " "0x%"FMTPTR"x\n", adr);
      }
}

/*
 * pattern_match()
 */
int
pattern_match(
      unsigned char *pattern, 
      unsigned char *mask,
      unsigned char *buf, 
      int size, 
      int nbytes, 
      int align)
{
      int i=0, j=0, found=0;

#define TOCHAR(p) (*((unsigned char*)(p)))
#define TOHALF(p) (*((unsigned short*)(p)))
#define TOWORD(p) (*((unsigned int*)(p)))
#define TODWORD(p)      (*((unsigned long long*)(p)))

      while(j<size) {
            switch(align) {
                  case 8:
                        for(i=0; i+8 <= nbytes; i+=8) {
                              if(((TODWORD(pattern+i) & 
                                          TODWORD(mask+i)) != 
                                          ( TODWORD(buf+j+i) & 
                                          TODWORD(mask+i)))) {
                                    goto next;
                              }
                        }
                        break;
                  case 4:  
                        for(i=0; i+4 <= nbytes; i+=4) {
                              if(((TOWORD(pattern+i) & 
                                          TOWORD(mask+i)) != 
                                          (TOWORD(buf+j+i) & 
                                          TOWORD(mask+i)))) {
                                    goto next;
                              }
                        }
                        break;
                  case 2: 
                        for(i=0; i+2 <= nbytes; i+=2) {
                              if(((TOHALF(pattern+i) & 
                                          TOHALF(mask+i)) != 
                                          (TOHALF(buf+j+i) & 
                                          TOHALF(mask+i)))) {
                                    goto next;
                              }
                        }
                        break;
                  default:
                        for (i=0; i < nbytes; i++) {
                              if (((buf[j+i] & mask[i]) != 
                                    (pattern[i] & mask[i]))) {
                                    goto next;
                              }
                        }
            }
            match_found(j);
            found++;
next:
            j += align;
      }
      return(found);
}

typedef struct memchnk_s {
      kaddr_t     addr;
      uint64_t    size;
} memchnk_t;

/*
 * get_memchnk()
 */
static int
get_memchnk(
      kaddr_t addr, 
      uint64_t size, 
      int len, 
      memchnk_t *memchnk)
{
      int vmaddr = 0, found_bad_page = 0;
      uint64_t nbytes;
      kaddr_t faddr = 0, naddr, paddr;
      kaddr_t max_addr;

      if (is_vmalloc_addr(addr)) {
            max_addr = VMALLOC_END;
            vmaddr = 1;
      } else {
            KL_VIRTOP(KL_HIGH_MEMORY, NULL, &max_addr);
      }
      naddr = addr;
      if (MIP->core_type == dev_kmem) {
live_again:
            nbytes = size;
            while (nbytes) {
                  if (kl_valid_physmem(naddr, nbytes)) {
                        faddr = naddr;
                        goto done;
                  }
                  if (nbytes < KL_PAGE_SIZE) {
                        /* that was our last chunk to test
                         */
                        nbytes = 0;
                  } else {
                        nbytes -= KL_PAGE_SIZE;
                  }
            }
            /* No more valid memory in this memory bank (we are at the 
             * end of memory or have hit a hole in memory). We need to 
             * try and find the next valid physical address and then 
             * go on from there.
             */
            naddr = kl_next_valid_physaddr(naddr);
            if (naddr == 0xffffffffffffffff) {
                  return(1);
            }
            goto live_again;
      } else {
            /* This is a core dump. We have to check page by page
             * because it's possible that a page is valid (from
             * a populated memory bank), but not in the dump.
             */
            faddr = 0;  
            nbytes = 0;
            while (naddr < max_addr) {
                  KL_VIRTOP(naddr, NULL, &paddr);
                  if (klib_error || (paddr == 0)) {
                        naddr += KL_PAGE_SIZE;
                        continue;
                  }
                  if (kl_paddr_in_dump(paddr)) {
                        /* Found a valid and in-the-dump page. Add
                         * it to the list.
                         */
                        if (!faddr) {
                              faddr = naddr;
                        }
                        nbytes += KL_PAGE_SIZE;
                  } else if (faddr) {
                        /* We have found at least one valid page in
                         * the dump. We have enough information to
                         * set up the memchnk and return.
                         */
                        found_bad_page++;
                        break;
                  } else if ((nbytes == 0) && !vmaddr){
                        /* We haven't found any valid pages yet. We
                         * need to make sure that we are not stepping
                         * through a hole in physical memory. If we
                         * are, then move on to the next bank.
                         *
                         * XXX -- not sure how to deal with the 
                         *        potential for a hole in kernel
                         *        vmalloced memory. For now, we just
                         *        slog through the pages...
                         * 
                         */
                        if (!kl_valid_physaddr(naddr)) {
                              naddr = kl_next_valid_physaddr(naddr);
                              if (naddr < 0xffffffffffffffff) {
                                    continue;
                              }
                        }
                  }
                  if (nbytes >= size) {
                        /* We have found MAX bytes, time to return...
                         */
                        break;
                  }
                  if (naddr == 0xffffffffffffffff) {
                        break;
                  }
                  naddr += KL_PAGE_SIZE;
            }
      }
done:
      if (faddr == 0) {
            return(1);
      }
      if (found_bad_page) {
            /* The last page checked was bad. Make
             * sure that we trim off the bytes from the
             * bad page (assuming that we did not start on 
             * a page boundry).
             */ 
            if (naddr % KL_PAGE_SIZE) {
                  nbytes -= (naddr % KL_PAGE_SIZE);
            } else {
                  nbytes -= KL_PAGE_SIZE;
            }
      }
      memchnk->addr = faddr;
      memchnk->size = (nbytes - (nbytes % len));
      return(0);
}

#define PAGECHUNK 128 /* 2 megs on a 16k page system.  multiple of 2 */

/*
 * search_memory()
 */
int
search_memory(
      unsigned char *pattern, 
      unsigned char *mask, 
      int nbytes,
      kaddr_t start_addr, 
      uint64_t length, 
      int align,
      int flags, 
      FILE *ofp)
{
      int found, isvmaddr = 0, large_search = 0; 
      unsigned i;
      kaddr_t addr, s; 
      kaddr_t start, limit;
      unsigned char *buf;
      int chunkbsize;
      memchnk_t memchnk;

      isvmaddr = is_vmalloc_addr(start_addr);

      if (isvmaddr || (start_addr >=  KL_PAGE_OFFSET)) {
            fprintf(ofp, "  START = %0"FMTPTR"x\n", start_addr);
      } else {
            fprintf(ofp, "  START = %0"FMTPTR"x (Physical Address)\n", 
                  start_addr);
      }
      fprintf(ofp, " LENGTH = %"FMTPTR"d bytes ", length);

      if (length < KL_PAGE_SIZE) {
            fprintf(ofp, "\n");
      } else {
            fprintf(ofp, "(%"FMTPTR"d%s page%s)\n", 
                  length/KL_PAGE_SIZE, (length%KL_PAGE_SIZE) ? "+" : "", 
                  (((length/KL_PAGE_SIZE) == 1) && 
                  !(length%KL_PAGE_SIZE)) ? "" : "s");
      }

      fprintf(ofp, "PATTERN = ");
      if (flags & C_STRING) {
            fprintf(ofp, "\"");
            for (i = 0; i < nbytes; i++) {
                  fprintf(ofp, "%c", pattern[i]);
                  if (!((i + 1) % 60)) {
                        fprintf(ofp, "\n          ");
                  }
            }
            fprintf(ofp, "\"");
      } else {
            void *pp = pattern;

            for (i = 0; i < nbytes/align; i++) {
                  switch (align) {
                        case 8:
                              fprintf(ofp, "%016"FMTPTR"x", 
                                    *(uint64_t*)pp);
                              if (!((i + 1) % 2)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 4:
                              fprintf(ofp, "%08x", *(uint32_t*)pp);
                              if (!((i + 1) % 4)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 2:
                              fprintf(ofp, "%04hx", *(uint16_t*)pp);
                              if (!((i + 1) % 8)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 1:
                              fprintf(ofp, "%02hhx", *(uint8_t*)pp);
                              if (!((i + 1) % 16)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;
                  }
                  pp = (void*)((unsigned long)pp + align);
            }
      }

      fprintf(ofp, "\n");
      if (!(flags & C_STRING)) {
            void *mp = mask;

            fprintf(ofp, "   MASK = ");
            for (i = 0; i < nbytes/align; i++) {
                  switch (align) {
                        case 8:
                              fprintf(ofp, "%016"FMTPTR"x", 
                                    *(uint64_t*)mp);
                              if (!((i + 1) % 2)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 4:
                              fprintf(ofp, "%08x", *(uint32_t*)mp);
                              if (!((i + 1) % 4)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 2:
                              fprintf(ofp, "%04hx", *(uint16_t*)mp);
                              if (!((i + 1) % 8)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;

                        case 1:
                              fprintf(ofp, "%02hhx", *(uint8_t*)mp);
                              if (!((i + 1) % 16)) {
                                    fprintf(ofp, "\n          ");
                              } else {
                                    fprintf(ofp, " ");
                              }
                              break;
                  }
                  mp = (void*)((unsigned long)mp + align);
            }
            fprintf(ofp, "\n\n");
      } else {
            fprintf(ofp, "\n");
      }

      /* Determine the size of the buffer block size. For large searches
       * (greater than 2GB), we allocate a large buffer to improve 
       * performance. For smaller searches, we search through memory one
       * page at a time.
       */
      if (length > (PAGECHUNK * KL_PAGE_SIZE)) {
            /* Large memory search. Load the memory to search into a 
             * big chunk to speed things up. 
             */
            chunkbsize = (PAGECHUNK * KL_PAGE_SIZE);
            large_search = 1;
      } else {
            chunkbsize = KL_PAGE_SIZE;
      }

      /* Adjust the size of chunkbsize so that is aligned for the
       * number of bytes in our pattern. Note that we don't have to
       * factor in the size of align as the pattern size has already
       * been adjusted to match. 
       */
      if (chunkbsize % nbytes) {
            chunkbsize -= (chunkbsize % nbytes);
      }

      /* Allocate a buffer for our search block.
       */
      buf = (unsigned char *)kl_alloc_block(chunkbsize, K_TEMP);

      if (isvmaddr) {
            /* Start address is from kernel vmalloc space. We need
             * to cycle through memory via kernel virtual address,
             * not physical address.
             */
            start = start_addr;
      } else {
            /* Get the physial address for start_addr.
             */
            KL_VIRTOP(start_addr, NULL, &start);
      }
      addr = start;
      limit = (start + length);

      /* Set the output file pointer
       */
      of = ofp;

      while(addr < limit) {
            if ((limit - addr) >= chunkbsize) {
                  s = chunkbsize;
            } else {
                  s = (limit - addr);
            }
            if (large_search) {
                  if (get_memchnk(addr, s, nbytes, &memchnk)) {
                        break;
                  }
                  /* Make sure we have the right address and size
                   * values (we might have just stepped over a hole
                   * in memory).
                   */
                  addr = memchnk.addr;
                  s = memchnk.size;

                  /* Check to see if there are enough bytes to 
                   * search. It may be that there was a valid
                   * chunk, but not enough bytes to span our search 
                   * len. If that's the case, then skip to the
                   * start of the next page (reducing the number of
                   * bytes searched by the number of byts skipped).
                   */
                  if (s == 0) {
                        addr += (KL_PAGE_SIZE - (addr % KL_PAGE_SIZE));
                        continue;
                  }
            }
            if (isvmaddr) {
                  curaddr = addr;
            } else {
                  curaddr = addr|KL_PAGE_OFFSET;
            }
            GET_BLOCK(addr, s, buf);
            if (KL_ERROR) {
                  /* Just push ahead...
                   */
                  if (isvmaddr || large_search) {
                        addr += s;
                  } else {
                        addr += chunkbsize;
                  }
                  continue;
            }
            found += pattern_match(pattern, mask, buf, s, nbytes, align);
            if (isvmaddr || large_search) {
                  addr += s;
                  s = chunkbsize;
            } else {
                  if ((limit - addr) >= chunkbsize) {
                        addr += chunkbsize;
                        s = chunkbsize;
                  } else {
                        s = 0;
                        addr = limit;
                  }
            }
            /* Step back the number of extra bytes beyond alignment.
             */
            if (addr < limit) {
                  addr -= (nbytes - align);
            }
      }
      kl_free_block(buf);
      return(found);
}

/*
 * search_cmd() -- Run the 'search' command to look through memory.
 */
int
search_cmd(command_t *cmd)
{
      int i, align, mode, nchars, nbytes;
      kaddr_t start_addr, length = 0;
      unsigned char *pattern;
      char *s;

      /* Truncate any search pattern larger than MAX_SEARCH_SIZE (this
       * should never happen as the maximum command paramater length is
       * 256 characters -- the same as MAX_SEARCH_SIZE).
       */
      nchars = strlen(cmd->args[0]);
      if (nchars > MAX_SEARCH_SIZE) {
            nchars = MAX_SEARCH_SIZE;
      }

      /* Check to see if this is an ASCII string search. If it is, set the
       * C_STRING and C_BYTE flags (and turn off all other flags). Otherwise,
       * Make sure the pattern value contains only hex digits and that the
       * number of hex digits is correct. 
       */
      if (cmd->args[0][0] == '\"') {

            if (lcrash_debug) {
                  fprintf(cmd->ofp, "search_cmd: input string = %s\n", 
                        cmd->args[0]);
            }
            cmd->flags &= ~(C_HWORD|C_WORD| C_DWORD);
            cmd->flags |= (C_STRING | C_BYTE);

            /* Strip off the leading and tailing double quotes (") 
             */
            bcopy (&cmd->args[0][1], cmd->args[0], nchars - 1);
            nchars--;
            if (cmd->args[0][nchars - 1] == '\"') {
                  nchars--;
            }
            cmd->args[0][nchars] = 0;
            nbytes = nchars;
      } else {
            /* If none of the flags (C_BYTE, C_HWORD, C_WORD, or 
             * C_DWORD) is set. Make the default align value match 
             * the word size of the target system (C_DWORD for 64-bit
             * systems, C_WORD for everything else).
             */
            if (!(cmd->flags & C_BYTE) && !(cmd->flags & C_HWORD) && 
                              !(cmd->flags & C_DWORD)) {
                  switch (KL_NBPW) {
                        case 8:
                              cmd->flags |= C_DWORD;
                              break;
                        default:
                              cmd->flags |= C_WORD;
                              break;
                  }
            }

            /* Check to make sure that multiple flag values are not set. If
             * they are, go with the flag representing the smallest memory
             * boundary size (e.g., go with C_BYTE if both C_BYTE and 
             * C_HWORD are set).
             */
            if (cmd->flags & C_BYTE) {
                  cmd->flags &= ~(C_HWORD|C_WORD|C_DWORD);
            } else if (cmd->flags & C_HWORD) {
                  cmd->flags &= ~(C_WORD|C_DWORD);
            } else if (cmd->flags & C_WORD) {
                  cmd->flags &= ~(C_DWORD);
            }

            /* Check to see if the hex value provided in pattern has a
             * 0x prefix. If it does, then strip it off (it messes up
             * pattern and nbytes count).
             */
            if (nchars > 2 && (!strncmp(cmd->args[0], "0X", 2) || 
                           !strncmp(cmd->args[0], "0x", 2))) {
                        nchars -= 2;
                        bcopy (&cmd->args[0][2], cmd->args[0], nchars);
                        cmd->args[0][nchars] = 0;
            }

            /* Trim off any extra hex digits. Also make sure that there are
             * at least enough hex digits for the size of the search unit 
             * (byte, hword, dword, etc.).
             */
            if (cmd->flags & C_BYTE) {
                  if (nchars < 2) {
                        fprintf(cmd->ofp, "%s: pattern must consist of "
                              "at least 2 hex digits for a byte "
                              "search\n", cmd->args[0]);
                        return(1);
                  }
                  nchars -= (nchars % 2);
            } else if (cmd->flags & C_HWORD) {
                  if (nchars < 4) {
                        fprintf(cmd->ofp, "%s: pattern must consist of "
                              "at least 4 hex digits for a halfword "
                              "search\n", cmd->args[0]);
                        return(1);
                  }
                  nchars -= (nchars % 4);
            } else if (cmd->flags & C_WORD) {
                  if (nchars < 8) {
                        fprintf(cmd->ofp, "%s: pattern must consist of "
                              "at least 8 hex digits for a word "
                              "search\n", cmd->args[0]);
                        return(1);
                  }
                  nchars -= (nchars % 8);
            } else if (cmd->flags & C_DWORD) {
                  if (nchars < 16) {
                        fprintf(cmd->ofp, "%s: pattern must consist of "
                              "at least 16 hex digits for a "
                              "doubleword search\n", cmd->args[0]);
                        return(1);
                  }
                  nchars -= (nchars % 16);
            } 
            nbytes = nchars / 2;
      }

      /* Setup memory serach step according to user supplied allignment. 
       * We also need to know the align value when setting up the mask.
       */
      if (cmd->flags & C_BYTE) {
            align=1;
      } else if (cmd->flags & C_HWORD) {
            align=2;
      } else if (cmd->flags & C_WORD) {
            align=4;
      } else {
            align=8;
      }

      pattern = (unsigned char *)kl_alloc_block(MAX_SEARCH_SIZE+1, K_TEMP);

      /* Copy the ASCII pattern in command argument into pattern array
       * (as ASCII text or numeric values).
       */
      if (cmd->flags & C_STRING) {
            strncpy((char*)pattern, cmd->args[0], nbytes);
      } else {
            /* At this time, there should be nothing but hex digits in 
             * the command line argument (and no spaces). We need to
             * copy the string over into pattern_str[].
             */ 
            strncpy(pattern_str, cmd->args[0], nchars);
            pattern_str[nchars] = 0;
            set_value(pattern_str, (void*)pattern, MAX_SEARCH_SIZE, align);
      }

      /* If no mask was specified, fill nbytes of mask array with ones.
       */
      if (cmd->flags & C_MASK) {
            set_value(mask_str, (void*)mask, MAX_SEARCH_SIZE, align);
      } else {
            s = (char*)mask;
            for (i = 0; i < nbytes; i++) {
                  s[i] = 0xff;
            }
      }

      /* Set memory location for start of search and search length 
       */ 
      if (cmd->nargs == 1) {
            start_addr = KL_PAGE_OFFSET;
      } else {
            kl_get_value(cmd->args[1], &mode, 0, &start_addr);
            if (KL_ERROR) {
                  kl_print_error();
                  return(1);
            }

            /* a PFN was entered --  convert to physical address
             */
            if (mode == 1) { 
                  start_addr = PGNO_TO_PADDR(start_addr);
            }
            if (cmd->nargs == 3) {
                  kl_get_value(cmd->args[2], NULL, 0, &length);
                  if (KL_ERROR) {
                        kl_print_error();
                        return(1);
                  }
            } 
      }

      /* If the length value was not set vial a command line argument,
       * then we need to derive it from the start address and the type
       * of address being searched.
       */
      if (!length) {
            /* Check to see if the start address falls withing vmalloc 
             * space. if it does, we have to search memory one page at 
             * a time. That's because the physical pages that back up 
             * the vmalloc space are not in any particular order.
             */
            if (is_vmalloc_addr(start_addr)) {
                  length = (VMALLOC_END - start_addr);
            } else if (start_addr < KL_PAGE_OFFSET) {
                  /* Not vmalloc addr and not kernel addr, so must be
                   * physical addr (or at least we shall treat it as 
                   * such).
                   */
                  length = (KL_HIGH_MEMORY - KL_PAGE_OFFSET) - start_addr;
            } else {
                  /* Kernel address directly mapped to physical memory.
                   */
                  length = (KL_HIGH_MEMORY - start_addr);
            }
      }

        if(length <= 0) {
                fprintf(cmd->ofp, "Please specifiy a length fo the search.\n");
        } else {
                search_memory(pattern, (unsigned char *)mask, nbytes, 
                  start_addr, length, align, cmd->flags, cmd->ofp);
        }
      kl_free_block((void *)pattern);
      return(0);
}

#define _SEARCH_USAGE \
  "[-B] [-H] [-W] [-D] [-w outfile] [-m mask] \n" \
      "\t\tpattern [start_address] [length]"

/*
 * search_usage() -- Print the usage string for the 'search' command.
 */
void
search_usage(command_t *cmd)
{
      CMD_USAGE(cmd, _SEARCH_USAGE);
}

/*
 * search_help() -- Print the help information for the 'search' command.
 */
void
search_help(command_t *cmd)
{
      CMD_HELP(cmd, _SEARCH_USAGE,
            "Locate contiguous bytes of memory that match the value "
            "contained in pattern, beginning at address for length bytes. "
            "Pattern consists of a string of, from one to 256 hexadecimal "
            "digits (with no embedded spaces). The first unit value in "
            "the pattern (long long, int, short, and byte) is anded (&) "
            "with the associated value in mask and compared to the "
            "contents in memory (which also has the mask applied to it). "
            "If there is a match, then the next unit value is compared "
            "until all the values in the pattern have been compared. If "
            "there is a match for all values in the pattern, then the "
            "address of the match is displayed.\n\n"
            
            "If the -D option is issued, the search is conducted on "
            "double word (eight byte) boundaries. If the -W option is "
            "issued, the search is conducted on word (four byte) "
            "boundaries. If the -H option is issued, the search is "
            "conducted on halfword (two byte) boundaries. If the -B "
            "option is issued, the search will be performed on a "
            "byte-by-byte basis. A custom mask can be supplied using "
            "the -m command line option. If no mask is specified, the "
            "mask defaults to all ones for the size of pattern. For all "
            "but string searches, the number of hex digits specified for "
            "pattern cannot be less than will fit into the memory "
            "boundary size specified. For example, patterns for halfword "
            "boundary searches, must contain (at least) eight hex digits "
            "(two per byte). Also, any extra digits beyond the specified "
            "boundary will be trimmed off from the right side of the "
            "input line.\n\n"
            
            "In addition to finding matches for hex values in memory, it "
            "is possible to search for strings of characters as well. "
            "Just begin and end the character search pattern with double "
            "quotes (\"). The ASCII value for each character in the "
            "string will form the corresponding byte values in the search "
            "pattern.\n\n"
            
            "The start address can be specified as either a virtual "
            "address (mapped or unmapped), a physical address, or as a PFN "
            "(directly following a pound '#' sign). If no address is "
            "specified (or if the one specified does not map to a valid "
            "physical memory address), address defaults to the the kernel "
            "address that maps to the start of physical memory. An "
            "optional length parameter specifies the number of bytes to "
            "search. If length is not specified, it will be set equal to "
            "the size of physical memory minus the starting physical "
            "address. Note that length can be specified ONLY when a "
            "address has been specified.\n\n"
            
            "Note for LITTLE ENDIAN systems. Special care has to be taken "
            "when constructing a search pattern of more than one unit "
            "size. The numeric value of the search pattern should contain "
            "the search values on a unit-by-unit basis as they would be "
            "displayed by the dump command, NOT as they are stored in "
            "physical memory. That is because the byte order is reversed "
            "(swapped) in memory on little endian systems. The search "
            "command takes this into account when performing its "
            "comparison. This is not an issue with BIG ENDIAN systems "
            "as the bytes in the search pattern and the bytes in memory "
            "are in the same order.");
}

/*
 * search_parse() -- Parse the command line arguments for 'search'.
 */
int
search_parse(command_t *cmd)
{
        option_t *op;

        if (set_cmd_flags(cmd, (C_TRUE|C_WRITE), "m:BDHW")) {
                return(1);
        }
        op = cmd->options;
        while (op) {
                switch(op->op_char) {
                        case 'm':
                                cmd->flags |= C_MASK;
                        if (get_mask_str(cmd, op)) {
                              return(1);
                        }
                                break;
                        case 'B':
                                cmd->flags |= C_BYTE;
                                break;

                        case 'D':
                                cmd->flags |= C_DWORD;
                                break;

                        case 'H':
                                cmd->flags |= C_HWORD;
                                break;

                        case 'W':
                                cmd->flags |= C_WORD;
                                break;
                }
                op = op->op_next;
        }
        return(0);
}

/*
 * search_complete() -- Complete arguments of 'search' command.
 */
char *
search_complete(command_t *cmd)
{
        char *ret;

        /* complete standard options (for example, -w option) arguments
         */
        if ((ret = complete_standard_options(cmd)) != NOT_COMPLETED) {
                return(ret);
        }
        fprintf(cmd->ofp, "\n");
        search_usage(cmd);
        return(DRAW_NEW_ENTIRE_LINE);
}

Generated by  Doxygen 1.6.0   Back to index