Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / ui_elfsym.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: ui_elfsym.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
////////////////////////////////////////////////////////////
//
// File: ui_elfsym.cc
//
// Copyright (C) 2005-2007 Sun Microsystems, Inc.
// All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "types.h"
#include "blaze_globals.h"
#include "cpu_interface.h"
#include "ui_elfsym.h"
#include "ui.h"
// symbol table
SymTable *g_sym_table = NULL;
extern int load_symbols(char* elf_fname, uint64_t text_base, uint64_t data_base, uint32_t context);
/////////////////////////////////////////////
//
// symbol table
//
static int load_sym (char *file_name, uint32_t context);
static int load_elf_sym(char* file_name, uint64_t text_base, uint64_t data_base,
uint32_t context=Symbol::ANY_CONTEXT, bool elffile=false);
static int print_symtab_usage()
{
ui->output("load symbol table usage (all params are in Hex):\n load_sym -elffile|-elfsym|-vsym -f <file_name> \
[-x <text start addr>] [-d <data start addr>] [-ctx <contextID>]\n");
return 0;
}
typedef enum { UNK_FILE, ELF_FILE, ELF_SYM, V_SYM } sym_file_t;
int load_sym_ui_cmd (void*, int argc, char **argv)
{
if (ANY_RUNNING_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
uint64_t text_base = 0;
uint64_t data_base = 0;
char *file_name;
uint32_t context = Symbol::ANY_CONTEXT;
sym_file_t file_type = UNK_FILE;
// check command options
if ( argc < 4 || argc > 10 )
return print_symtab_usage();
for (int i=1; i<argc; i++)
{
if ((strcmp(argv[i], "-x")==0) && ((i+1)<argc))
{
// set text base value
text_base = int(strtoull(argv[++i], NULL, 16));
}
else if ((strcmp(argv[i], "-d")==0) && ((i+1)<argc))
{
// set data base value
data_base = int(strtoull(argv[++i], NULL, 16));
}
else if ((strcmp(argv[i], "-f")==0) && ((i+1)<argc) )
{
// elf file name
file_name = argv[++i];
}
else if ((strcmp(argv[i], "-ctx")==0) && ((i+1)<argc) )
{
// symbols context
char *ctx = argv[++i];
errno = 0;
if (strcmp(ctx, "hv") == 0)
{
context = Symbol::NO_CONTEXT;
}
else if (strcmp(ctx, "k") == 0)
{
context = Symbol::NUCLEUS;
}
else
{
context = strtoul(ctx, NULL, 16);
}
if(errno)
{
ui->error("\n -ctx <contextID> cannot figure out context id, should be 0,k,hv,or a hex number > 0 \n");
return 0;
}
}
else if (strcmp(argv[i], "-elffile")==0)
{
file_type = ELF_FILE;
}
else if (strcmp(argv[i], "-elfsym")==0)
{
file_type = ELF_SYM;
}
else if (strcmp(argv[i], "-vsym")==0)
{
file_type = V_SYM;
}
else if (strcmp(argv[i], "?")==0)
{
return print_symtab_usage();
}
}
if (!file_name)
{
ui->error("missing file name \n");
return print_symtab_usage();
}
switch ( file_type )
{
case ELF_FILE: // elf file
{
// allocate symbol table
if (g_sym_table == NULL)
{
uint32_t idx[4] = {12, 6, 8, 6};
g_sym_table = new SymTable(4, idx);
}
load_symbols(file_name, text_base, data_base, context);
}
//load_elf_sym(file_name, text_base, data_base, true);
break;
case ELF_SYM : // symbol table extracted from elf module
load_elf_sym(file_name, text_base, data_base, context);
break;
case V_SYM : // special symbol file
load_sym(file_name, context);
break;
default:
ui->error("unknown symbol table type, load_sym should have -elffile, -elfsym or -vsym.\n");
}
return 1;
}
/////////////////////////////////////////////////////////////
// read symbol table file
static int load_sym (char *file_name, uint32_t context)
{
// Open symtab file
FILE *file = fopen(file_name,"r");
if (file == NULL) { ui->perror (file_name); return 0; }
char line[512];
char delimeter[] = " :\t\n";
// allocate symbol table
if (g_sym_table == NULL)
{
g_sym_table = new SymTable();
}
ui->output("Loading %s special symbols...", file_name);
const uint64_t UNKNOWN = ~uint64_t(0);
while(fgets(line, 512, file) != NULL)
{
// parse symbol info:
// symbolname vaddr raddr paddr
char *symbol = strtok(line, delimeter);
char *addr = strtok(NULL, delimeter);
uint64_t va = strtoull(addr, NULL, 16);
if (strcmp(addr, "X") == 0)
va = UNKNOWN;
addr = strtok(NULL, delimeter);
uint64_t ra = strtoull(addr, NULL, 16);
if (strcmp(addr, "X") == 0)
ra = UNKNOWN;
addr = strtok(NULL, delimeter);
uint64_t pa = strtoull(addr, NULL, 16);
if (strcmp(addr, "X") == 0)
pa = UNKNOWN;
// insert symbol
g_sym_table->add(file_name,symbol, va, 4, context);
}
ui->output("Done. \n");
return 1;
}
//////////////////////////////////////////////////////////
static int load_elf_sym
(
char* file_name,
uint64_t text_base,
uint64_t data_base,
uint32_t context,
bool elf_file
)
{
const int bsize = 1024;
char sline[1024];
errno = 0;
// Open symtab file
FILE *file = NULL;
if (elf_file)
{
sprintf( sline, "nm -xvs %s", file_name);
file = popen( sline, "r" );
}
else
{
file = fopen( file_name,"r" );
}
if (file == NULL)
{
ui->perror (file_name);
return 0;
}
char delimeter[] = " |\n";
// allocate symbol table
if (g_sym_table == NULL)
{
uint32_t idx[4] = {12, 6, 8, 6};
g_sym_table = new SymTable(4, idx);
}
ui->output("Loading %s elf symbols...", file_name);
while(fgets(sline, bsize, file) != NULL)
{
if ((sline[0]=='[') && !isdigit(sline[1]))
continue;
// parse symbol info line
// [Index] | Value | Size | Type | Bind | Other | Shname | Name
char *idx = strtok(sline, delimeter);
if (idx == NULL)
continue;
char *value = strtok(NULL, delimeter);
if (value == NULL)
continue;
char *size = strtok(NULL, delimeter);
if (size == NULL)
continue;
char *type = strtok(NULL, delimeter);
if (type == NULL)
continue;
char *bind = strtok(NULL, delimeter);
if (bind == NULL)
continue;
char *oth = strtok(NULL, delimeter);
if (oth == NULL)
continue;
char *shname = strtok(NULL, delimeter);
if (shname == NULL)
continue;
char *name = strtok(NULL, delimeter);
if (name == NULL)
continue;
errno = 0;
uint64_t va = strtoull(value, NULL, 16);
uint64_t sz = strtoull(size, NULL, 16);
if (errno)
{
ui->perror(name);
continue;
}
if (sz == 0) // skip symbols(lebels) with zero size
continue;
if ( strcmp (shname, ".text") == 0)
{
// text symbol
va += text_base;
}
else if (strcmp (type, "OBJT") == 0)
{
//data symbol
if (strcmp (shname, ".data") == 0)
{
// initialized data
va += data_base;
}
else if (strcmp (shname, ".bss" )==0)
{
// uninitialized data
if (strcmp (bind, "GLOB" ) == 0)
va += data_base;
else
continue;
}
else
continue;
}
else
continue;
// insert symbol
g_sym_table->add(file_name, name, va, sz, context);
}
if ( elf_file )
pclose ( file );
else
fclose ( file );
ui->output("Done. \n");
return 1;
}
//////////////////////////////////////////////////////////
int unload_sym_ui_cmd (void*, int argc, char **argv)
{
// Unload symbol table
if (ANY_RUNNING_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
if ( argc > 1)
{
ui->error("unload symbol table, usage:\n unload_sym \n");
return 0;
}
if (g_sym_table != NULL)
{
delete(g_sym_table);
g_sym_table = NULL;
}
return 1;
}
//////////////////////////////////////////////////////////
// print symbols
static int print_sym_usage()
{
ui->output("sym command usage:\n sym [-ctx <contextID>] [-o filename]-all|-a <addr>|-s <name>\n");
return 0;
}
int symbols_ui_cmd (void*, int argc, char **argv)
{
if (g_sym_table == NULL)
{
ui->error("There is no symbol table allocated \n");
return 0;
}
char *file_name = NULL;
uint32_t context = Symbol::ANY_CONTEXT;
// check command options
if ( argc < 2 )
return print_sym_usage();
for (int i=1; i<argc; i++)
{
if (strcmp(argv[i], "-all")==0)
{
// show all symbols
g_sym_table->print(file_name, context);
return 1;
}
else if (strcmp(argv[i], "-hash")==0)
{
g_sym_table->hprint(file_name, context);
return 1;
}
else if ((strcmp(argv[i], "-s")==0) && ((i+1)<argc) )
{
// search for symbol by name
char *name = argv[++i];
if (!g_sym_table->fputs(name, context, ui->get_output_file()))
ui->error("%s not found\n", name);
if (ui->get_log_file())
g_sym_table->fputs(name, context, ui->get_log_file());
return 1;
}
else if ((strcmp(argv[i], "-a")==0) && ((i+1)<argc))
{
// addr
char *addr = argv[++i];
uint64_t vaddr = strtoull(addr, NULL, 16);
if (g_sym_table->fputs(vaddr, context, ui->get_output_file()))
{
if (ui->get_log_file())
g_sym_table->fputs(vaddr, context, ui->get_log_file());
ui->output("at address = 0x%llx\n", vaddr);
}
else
{
if (ui->get_log_file())
g_sym_table->fputs(vaddr, context, ui->get_log_file());
ui->error("address %s not found\n", addr );
}
return 1;
}
else if ((strcmp(argv[i], "-ctx")==0) && ((i+1)<argc) )
{
// symbols context
char *ctx = argv[++i];
errno = 0;
if (strcmp(ctx, "hv") == 0)
{
context = Symbol::NO_CONTEXT;
}
else if (strcmp(ctx, "k") == 0)
{
context = Symbol::NUCLEUS;
}
else
{
context = strtoul(ctx, NULL, 16);
}
if(errno)
{
ui->error("-ctx <contextID> cannot figure out context id, should be 0,k,hv,or a hex number > 0 \n");
return 0;
}
}
else if ((strcmp(argv[i], "-o")==0) && ((i+1)<argc) )
{
file_name = argv[++i];
}
else if (strcmp(argv[i], "?")==0)
{
return print_sym_usage();
}
}
return 1;
}
//////////////////////////////////////////////////////////////
//
// where ui command
//
static int print_routine_name ( uint64_t pc )
{
if (!g_sym_table->fputs(pc, Symbol::ANY_CONTEXT, ui->get_output_file()))
{
ui->error("unknown routine \n");
return 1;
}
if (ui->get_log_file())
g_sym_table->fputs(pc, Symbol::ANY_CONTEXT, ui->get_log_file());
return 0;
}
int where_ui_cmd (void*, int argc, char **argv)
{
// Unload symbol table
if (ANY_RUNNING_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
if ( argc > 1)
{
ui->error("show call stack, usage:\n where \n");
return 0;
}
for (int i=0; i<=g_vcpu_id_max; i++)
{
// for each vcpu
Vcpu *cpu = get_vcpu(i);
if (!cpu)
continue;
// get pc value
uint64_t pc = 0;
cpu->get_reg(VCPU_ASR_PC, &pc);
ui->output("cpu[%i]: pc=0x%llx ",cpu->id(), pc);
if (g_sym_table != NULL)
{
print_routine_name(pc);
// get sp value
uint64_t sp = 0;
cpu->get_reg(VCPU_IRF_0 + 14, &sp);
// get fp value
uint64_t fp = 0;
cpu->get_reg(VCPU_IRF_0 + 30, &fp);
// get ret address
uint64_t ret_addr = 0;
cpu->get_reg(VCPU_IRF_0 + 31, &ret_addr);
ui->output("called from address 0x%llx ", ret_addr);
print_routine_name(ret_addr);
// check trap level
uint64_t tl = 0;
cpu->get_reg(VCPU_PR_TL, &tl);
uint64_t cur_tl = tl;
for( ;tl > 0; tl--)
{
ui->output("Trap Level = %llx ", tl);
uint64_t tpc = 0;
cpu->set_reg(VCPU_PR_TL, tl);
int stat = cpu->get_reg(VCPU_PR_TPC, &tpc);
if (stat == 0)
{
print_routine_name(tpc);
}
}
cpu->set_reg(VCPU_PR_TL, cur_tl);
}
ui->output("\n");
}
return 1;
}