blob: 83946f6108a80d3c7d5d5d85cb928d1389676093 [file] [log] [blame]
/*
* Kernel Debugger Architecture Independent Instruction Disassembly
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
*/
#include <stdarg.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/lkdb.h>
#include <linux/kdbprivate.h>
disassemble_info kdb_di;
/*
* lkdb_id
*
* Handle the id (instruction display) command.
*
* id [<addr>]
*
* Parameters:
* argc Count of arguments in argv
* argv Space delimited command line arguments
* Outputs:
* None.
* Returns:
* Zero for success, a kdb diagnostic if failure.
* Locking:
* None.
* Remarks:
*/
int
lkdb_id(int argc, const char **argv)
{
kdb_machreg_t pc;
int icount;
int diag;
int i;
char *mode;
int nextarg;
long offset = 0;
static kdb_machreg_t lastpc;
struct disassemble_info *dip = &kdb_di;
char lastbuf[50];
unsigned long word;
kdb_di.fprintf_func = kdb_dis_fprintf;
kdba_id_init(&kdb_di);
if (argc != 1) {
if (lastpc == 0) {
return LKDB_ARGCOUNT;
} else {
sprintf(lastbuf, "0x%lx", lastpc);
argv[1] = lastbuf;
argc = 1;
}
}
/*
* Fetch PC. First, check to see if it is a symbol, if not,
* try address.
*/
nextarg = 1;
diag = lkdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL);
if (diag)
return diag;
kdba_check_pc(&pc);
if (lkdb_getarea(word, pc))
return(0);
/*
* Number of lines to display
*/
diag = lkdbgetintenv("IDCOUNT", &icount);
if (diag)
return diag;
mode = lkdbgetenv("IDMODE");
diag = kdba_id_parsemode(mode, dip);
if (diag) {
return diag;
}
for(i=0; i<icount; i++) {
pc += kdba_id_printinsn(pc, &kdb_di);
lkdb_printf("\n");
}
lastpc = pc;
return 0;
}
/*
* lkdb_id1
*
* Disassemble a single instruction at 'pc'.
*
* Parameters:
* pc Address of instruction to disassemble
* Outputs:
* None.
* Returns:
* Zero for success, a kdb diagnostic if failure.
* Locking:
* None.
* Remarks:
*/
void
lkdb_id1(unsigned long pc)
{
char *mode;
int diag;
kdb_di.fprintf_func = kdb_dis_fprintf;
kdba_id_init(&kdb_di);
/*
* Allow the user to specify that this instruction
* should be treated differently.
*/
mode = lkdbgetenv("IDMODE");
diag = kdba_id_parsemode(mode, &kdb_di);
if (diag) {
lkdb_printf("lkdb_id: bad value in 'IDMODE' environment variable ignored\n");
}
(void) kdba_id_printinsn(pc, &kdb_di);
lkdb_printf("\n");
}
/*
* kdb_dis_fprintf
*
* Format and print a string.
*
* Parameters:
* file Unused paramter.
* fmt Format string
* ... Optional additional parameters.
* Returns:
* 0
* Locking:
* Remarks:
* Result of format conversion cannot exceed 255 bytes.
*/
int
kdb_dis_fprintf(PTR file, const char *fmt, ...)
{
char buffer[256];
va_list ap;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
lkdb_printf("%s", buffer);
return 0;
}
/*
* kdb_dis_fprintf_dummy
*
* A dummy printf function for the disassembler, it does nothing.
* This lets code call the disassembler to step through
* instructions without actually printing anything.
* Inputs:
* Always ignored.
* Outputs:
* None.
* Returns:
* Always 0.
* Locking:
* none.
* Remarks:
* None.
*/
int
kdb_dis_fprintf_dummy(PTR file, const char *fmt, ...)
{
return(0);
}
/*
* kdb_disinit
*
* Initialize the disassembly information structure
* for the GNU disassembler.
*
* Parameters:
* None.
* Outputs:
* None.
* Returns:
* Zero for success, a kdb diagnostic if failure.
* Locking:
* None.
* Remarks:
*/
void __init
lkdb_id_init(void)
{
kdb_di.stream = NULL;
kdb_di.application_data = NULL;
kdb_di.symbols = NULL;
kdb_di.num_symbols = 0;
kdb_di.flags = 0;
kdb_di.private_data = NULL;
kdb_di.buffer = NULL;
kdb_di.buffer_vma = 0;
kdb_di.buffer_length = 0;
kdb_di.bytes_per_line = 0;
kdb_di.bytes_per_chunk = 0;
kdb_di.insn_info_valid = 0;
kdb_di.branch_delay_insns = 0;
kdb_di.data_size = 0;
kdb_di.insn_type = 0;
kdb_di.target = 0;
kdb_di.target2 = 0;
}