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

cmd_dis.c

/*
 * $Id: cmd_dis.c,v 1.1 2004/12/21 23:26:18 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 - 2002 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>

static uint64_t value;
static int bcount = 0;
static int acount = 0;
char *fname;

void dis_usage(command_t *);

/*
 * dis_cmd() -- Run the 'dis' command.
 */
int
dis_cmd(command_t *cmd)
{
      int size;
      char *c = (char *)NULL;
      syment_t *sp;
      kaddr_t v;
      uint64_t val;

      /* Dump a list of all instructions
       */
      if (cmd->flags & C_LIST) {
            LIST_INSTRUCTIONS(cmd->ofp);
            return(0);
      }

      /* Disassemble all of the instructions in the kernel (more or
       * less). Mainly used for testing purposes (to compare with the
       * output from idis).
       */
      if (cmd->flags & C_ALL) {
            kaddr_t t_end;

            sp = kl_lkup_symname("_text");
            v = sp->s_addr;
            sp = kl_lkup_symname("_etext");
            t_end = sp->s_addr;
            while (v <= t_end) {
                  if (cmd->flags & C_FULL) {
                        size = PRINT_INSTR(v, cmd->ofp, 1);
                  } else {
                        size = PRINT_INSTR(v, cmd->ofp, 0);
                  }
                  v += size;
            }
            return(0);
      }

      /* Disassemble all instructions for a given function
       */
      if (fname) {
            int fsize;
            kaddr_t faddr;
            /*
             * Could not be used kl_lkup_symname here because of accessing 
             * the function names is different in PPC64.
             */
            if (!(sp = get_func_name(fname))) {
                  fprintf(KL_ERRORFP,"No such function: %s\n", fname);
                  return(1);
            }
            fsize = kl_funcsize(sp->s_addr);
            faddr = sp->s_addr;
            while (faddr < (sp->s_addr + fsize)) {
                  if (cmd->flags & C_FULL) {
                        size = PRINT_INSTR(faddr, cmd->ofp, 1);
                  } else {
                        size = PRINT_INSTR(faddr, cmd->ofp, 0);
                  }
                  faddr += size;
            }
            return(0);
      }

      /* Make sure we have the right number of parameters
       */
      if (cmd->nargs > 3) {
            dis_usage(cmd);
            return (1);
      }

      /* Set the disassembler's location and the number of lines to
       * dump out before and after pc.  Also make sure our line 
       * count is correct (if only one count parameter is specified).
       */
      if (cmd->nargs) {
            if ((c = strpbrk(cmd->args[0], "+-/*"))) {
                  GET_VALUE(cmd->args[0], &value);
                  if (KL_ERROR) {
                        kl_print_error();
                        return(1);
                  }
            } else {
                  if ((sp = get_func_name(cmd->args[0]))) {
                        value = (uint64_t)sp->s_addr;
                  } else {
                        GET_VALUE(cmd->args[0], &value);
                        if (KL_ERROR) {
                              kl_print_error();
                              return(1);
                        }
                  }
            }
            if (cmd->nargs == 1) {
                  bcount = acount = 0;
            } else if (cmd->nargs == 2) {
                  GET_VALUE(cmd->args[1], &val);
                  if (KL_ERROR) {
                        kl_print_error();
                        return(1);
                  }
                  acount = (int)val;
                  if (acount < 0) {
                        KL_ERROR = KLE_BAD_LINENO;
                        kl_print_error();
                        dis_usage(cmd);
                        return(1);
                  }
                  /* Treat acount as a line count (have to subtract 
                   * the current instruction).
                   */
                  if (acount) {
                        acount--;
                  }
                  bcount = 0;
            } else if (cmd->nargs == 3) {
                  GET_VALUE(cmd->args[1], &val);
                  if (KL_ERROR) {
                        kl_print_error();
                        return(1);
                  }
                  bcount = (int)val;
                  if (bcount < 0) {
                        KL_ERROR = KLE_BAD_LINENO;
                        kl_print_error();
                        dis_usage(cmd);
                        return(1);
                  }
                  GET_VALUE(cmd->args[2], &val);
                  if (KL_ERROR) {
                        kl_print_error();
                        return(1);
                  }
                  acount = (int)val;
                  if (acount < 0) {
                        KL_ERROR = KLE_BAD_LINENO;
                        kl_print_error();
                        dis_usage(cmd);
                        return(1);
                  }
            } 
      } else {
            /* Make sure that there is a value...
             */
            if (!value) {
                  dis_usage(cmd);
                  return(1);
            }
      }
      value = (kaddr_t)PRINT_INSTR_STREAM(value, bcount, acount, 
            cmd->flags, cmd->ofp);
      if(KL_ERROR){
            fprintf(KL_ERRORFP,"dis: ");  
            kl_print_error();
            return(1);
      }
      return(0);
}

#define _DIS_USAGE "[-f] [-w outfile] [-F funcname]|addr[count|[bcount acount]]"

/*
 * dis_usage() -- Print the usage string for the 'dis' command.
 */
void
dis_usage(command_t *cmd)
{
      CMD_USAGE(cmd, _DIS_USAGE);
}

/*
 * dis_help() -- Print the help information for the 'dis' command.
 */
void
dis_help(command_t *cmd)
{
      CMD_HELP(cmd, _DIS_USAGE,
            "Display the disassembled code for addr for count "
            "instructions (the default count is 1). Alternately, "
            "display the disassembled code for addr with bcount "
            "instructions before and acount instructions after. "
            "If bcount or acount is zero, then no instructions will "
            "be displayed before or after respectively. If the dis "
            "command is issued with the -f command line option, "
            "additional information will be displayed (opcode and "
            "byte size). If the dis command is issued with the -F "
            "option followed by funcname, disassembled code "
            "will be displayed for all instructions in the function.");
}


/*
 * dis_parse() -- Parse the command line arguments for the 'dis' command.
 */
int
dis_parse(command_t *cmd)
{
      option_t *op;
      fname = NULL;

      if (set_cmd_flags(cmd, (C_WRITE|C_ALL|C_FULL), "F:")) {
            return(1);
      }
      op = cmd->options;
      while (op) {
            switch(op->op_char) {
                  case 'F':
                        fname = op->op_arg;
                        break;
            }
            op = op->op_next;
      }
      return (0);
}

/*
 * dis_complete() -- Complete arguments of 'dis' command.
 */
char *
dis_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");
      dis_usage(cmd);
      return(DRAW_NEW_ENTIRE_LINE);
}

Generated by  Doxygen 1.6.0   Back to index