Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / symbols.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: symbols.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: symbols.cc
//
// Symbol table submodule
//
// Copyright (C) 2006 Sun Microsystems, Inc.
// All rights reserved.
//
// Symbol table implementation file
//
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "types.h"
#include "symbols.h"
#include "ui.h"
#define DEBUG_ON 0
/////////////////////////////////////////////////////////
//
// Symbol class
//
Symbol::Symbol
(
char* mname, // module name
char* sname, // symbol name
uint64_t vaddr, // starting address
uint64_t size, // size of address space taken this symbol
uint32_t context // symbol context
)
: SymBase(NULL)
{
// add module name
if (sname != NULL)
{
char sym_name[128];
sprintf (sym_name, "%s:%s", mname, sname);
m_name = strdup(sym_name);
m_sname = strdup(sname);
}
else
{
m_name = NULL;
m_sname = NULL;
}
m_next = NULL;
m_vaddr = vaddr;
m_size = size;
m_context = context;
}
// destructor
Symbol::~Symbol ()
{
if (m_name ) free(m_name);
if (m_sname) free(m_sname);
}
//////////////////////////////////////////////////////////////
//
// Container class for all symbols
//
// constructor
SymTable::SymTable
(
uint32_t levels, // total number of table levels +1
uint32_t *idx_width // number of bits for table index
// on each level, plus last offset
)
{
int i;
uint32_t *wd = idx_width;
const uint32_t default_level = MAX_LEVEL+1; // number of tables + 1
uint32_t default_width[default_level] = {12,10,10,10,10,10,2};
if ((idx_width == NULL) || (levels > default_level ))
{
levels = default_level;
wd = default_width;
}
m_lev = levels-2;
int max_lev = m_lev + 1;
for (i=max_lev; i>=0; i--)
{
m_width[i] = wd[i];
m_size [i] = 1<<m_width[i];
m_mask [i] = m_size[i] -1;
m_sft [i] = (i==max_lev) ? 0 : m_width[i+1];
if ( i < max_lev)
m_sft [i] += m_sft[i+1];
#if(DEBUG_ON)
ui->verbose("\n symbol tbl level=%d, sft=%d, width=%d, size=0x%x, mask=0x%llx\n",
i, m_sft[i],m_width[i],m_size[i],m_mask[i]);
#endif
}
m_tbl = (void **) calloc(m_size[0], sizeof(void*));
for (int j=0; j<SYM_TBL_SIZE; j++)
m_bucket[j] = NULL;
m_empty = true;
}
// destructor
SymTable::~SymTable ()
{
for (int j=0; j<SYM_TBL_SIZE; j++)
{
if (m_bucket[j] != NULL)
delete m_bucket[j];
}
delete_tbl ( m_tbl, 0 );
}
// get a pointer in multi level addr tables;
// nested tables are allocated if needed
void ** SymTable::alloc( uint64_t addr )
{
void ** tbl = m_tbl;
void ** ptr = NULL;
for ( int i=0; i<m_lev; i++)
{
ptr = tbl + ((addr>>m_sft[i]) & m_mask[i]);
void **next = (void**)(*ptr);
if (next == NULL)
{
// allocate a new table
next = (void **) calloc ( m_size[i+1], sizeof(void*));
// insert a pointer
*ptr = next;
}
tbl = next;
}
// get a pointer to the leaf table entry
return (tbl + ((addr>>m_sft[m_lev]) & m_mask[m_lev]));
}
// recursively delete all tables on deeper levels
void SymTable::delete_tbl ( void ** tbl, uint32_t level)
{
if ( level == m_lev )
{
// leaf table
for ( int i=0; i<m_size[level]; i++ )
{
// remove all links
SymBase *s = (SymBase *)tbl[i];
while (s)
{
SymBase *r = s;
s = s->m_link;
if (r->m_origin)
delete (r);
else
{
delete ( (Symbol*)r);
}
}
}
free ( tbl );
}
else
{
for ( int i=0; i<m_size[level]; i++ )
{
if (tbl[i]) // nested table
delete_tbl ( (void **)tbl[i], level+1 );
free ( tbl[i] );
}
}
}
// search for symbols specified by symbol name;
// return pointer to symbol if found; 0 otherwise
Symbol* SymTable::find
(
char* name, // symbol name
Symbol* start // start search from this one
)
{
if ( this->is_empty() )
return NULL;
Symbol *sym = start ? start->m_next : NULL;
if (start == NULL)
{
// hash index for the bucket
sym = m_bucket[sym_hash(name)];
}
while (sym) // possibly iterate through the list
{
// check if name match
if ( strcmp (sym->m_sname, name) == 0 )
{
return sym;
}
// traverse the list for this bucket
sym = sym->m_next;
}
return NULL;
}
// find symbol specified by address ;
// return 1 if found, 0 otherwise;
SymBase* SymTable::find
(
uint64_t addr, // address used to lookup the symbol
SymBase* start // start from this symbol
)
{
SymBase* res = NULL;
SymBase* s = start ? start->m_link : NULL;
if(start==NULL)
s = find ( addr );
if ( s == NULL )
return 0; // not found
while (s)
{
Symbol *sym = (s->m_origin) ? (Symbol*)(s->m_origin) : (Symbol*)s;
// check the range
if ( (addr >= sym->m_vaddr) &&
(addr < (sym->m_vaddr+ sym->m_size)) )
{
// symbol is in the range
res = (SymBase*)sym;
return res;
}
s = s->m_link;
}
return res;
}
// find and output address for all symbols specified by name;
// return 1 if found, 0 otherwise;
int SymTable::fputs
(
char *name, // name used to lookup the symbol
uint32_t context, // symbol context
FILE * fp // output symbol name to stream if found
)
{
int res = 0;
if ( this->is_empty() )
return 0;
// hash index for the bucket
int hindex = sym_hash ( name );
Symbol *sym = m_bucket[hindex];
while (sym) // possibly iterate over the list
{
// check if name match
if (
(context == Symbol::ANY_CONTEXT || context == sym->m_context) &&
(strcmp (sym->m_sname, name) == 0)
)
{
fprintf(fp,"\n%s at address=0x%llx, size=0x%llx \n", sym->m_name, sym->m_vaddr, sym->m_size);
res = 1;
}
// traverse the list for this bucket
sym = sym->m_next;
}
return res;
}
// find and output full symbol name by specified address ;
// return 1 if found, 0 otherwise;
int SymTable::fputs
(
uint64_t addr, // address used to lookup the symbol
uint32_t context, // symbol context
FILE * fp // output symbol name to stream if found
)
{
int res = 0;
SymBase *s = find ( addr );
if ( s == NULL )
return 0; // not found
while (s)
{
Symbol *sym = (s->m_origin) ? (Symbol*)(s->m_origin) : (Symbol*)s;
// check the range
if (
(context == Symbol::ANY_CONTEXT || context == sym->m_context) &&
(addr >= sym->m_vaddr) &&
(addr < (sym->m_vaddr+ sym->m_size))
)
{
// symbol is in the range
fprintf (fp, "%s+0x%llx ", sym->m_name, addr - sym->m_vaddr);
res = 1;
}
#if(DEBUG_ON)
// debug print out
if (s->m_origin) fprintf (fp, "\nredirected to ->");
fprintf(fp, "0x%016llx : 0x%016llx : %s , sp=0x%llx \n",
sym->m_vaddr, sym->m_size, sym->m_name, s);
#endif
s = s->m_link;
}
return res;
}
// add a new symbol to the symbol table
// return 1 if added, 0 otherwise
int SymTable::add
(
char * mname, // module name
char * name, // symbol name
uint64_t vaddr, // starting address
uint64_t size, // range covered
uint32_t context // symbol context
)
{
if ((vaddr == ~uint64_t(0)) || (size == 0))
return 0;
uint32_t awidth = m_width[0] + m_sft[0];
uint64_t max_addr = awidth < 64 ? (uint64_t(1)<<awidth) - 1 : ~uint64_t(0);
if ( ~max_addr && (vaddr & ~max_addr) )
{
ui->warning( "Symbol: %s ingnored, address 0x%llx exceeds max addr 0x%llx for the sym table. \n",
name, vaddr, max_addr);
return 0;
}
// create a new symbol
Symbol *sym = new Symbol(mname, name, vaddr, size, context);
uint64_t addr = vaddr;
// block size
uint32_t bsize = m_size[m_lev+1];
// cover all range
for (uint64_t offset = 0; ((vaddr+offset) & ~m_mask[m_lev+1]) <= (vaddr+size); offset += bsize)
{
SymBase *new_sym = (SymBase *)sym;
if (offset !=0 ) // not first symbol in the range
{
new_sym = sym->dup();
}
// find a spot in address tables
SymBase **p_sym = (SymBase **)this->alloc(addr);
if (*p_sym==NULL) // table slot is empty
{
// insert new symbol
*p_sym = new_sym;
}
else // something is already there
{
// overlap with another symbol
(*p_sym)->attach ( new_sym );
#if(DEBUG_ON)
ui->verbose("\nnew_sym=0x%llx: %s+0x%llx was attached to p_sym=0x%llx(0x%llx) \n",
new_sym, sym->m_name, offset, *p_sym, p_sym);
#endif
}
addr += bsize;
}
// insert symbol into hash list
int hindex = sym_hash (name); // hash index
sym->m_next = m_bucket[hindex];
m_bucket[hindex] = sym;
m_empty = false;
return 1;
}
// print all symbols
// from low to upper addresses
void SymTable::print ( char *filename, uint32_t context )
{
uint64_t total = 0;
if(filename)
{
FILE* fp = fopen (filename, "w");
if ( fp == NULL )
{
ui->error("cannot open %s\n", filename);
return;
}
else
{
ui->verbose("Collect symbols to %s file\n", filename);
}
if (print_tbl ( fp, m_tbl, 0, total, context )==0)
fprintf(fp, "Total number of symbols: %i \n", total);
fclose(fp);
}
else
{
if (print_tbl ( ui->get_output_file(), m_tbl, 0, total, context )==0)
fprintf(ui->get_output_file(), "Total number of symbols: %i \n", total);
// When logging is enabled we replicate output to log file.
if (ui->get_log_file()
&& (print_tbl ( ui->get_log_file(), m_tbl, 0, total, context )==0))
fprintf(ui->get_log_file(), "Total number of symbols: %i \n", total);
}
}
// print one symbol
int print_sym ( FILE *fp, Symbol *s, uint32_t context )
{
if (context != Symbol::ANY_CONTEXT && context != s->context())
return 0;
fprintf(fp, "0x%016llx : 0x%016llx ",
s->vaddr(), s->size());
if (s->context() < Symbol::NO_CONTEXT)
fprintf(fp, ": 0x%08lx : %s \n", s->context(), s->name());
else
fprintf(fp, ": %s \n", s->name());
return 1;
}
// recursively print symbols for all tables on deeper levels
int SymTable::print_tbl
(
FILE *fp, // output to the stream
void ** tbl, // table pointer
uint32_t level, // table level
uint64_t &total, // symbol counter
uint32_t context
)
{
if ( level == m_lev )
{
// leaf table
for ( int j=0; j<m_size[level]; j++ )
{
SymBase *sym = (Symbol *)tbl[j];
while (sym)
{
if (sym->m_origin) // range mark - skip it
{
sym = sym->m_link;
continue;
}
Symbol *s = (Symbol *)sym;
if (print_sym (fp, s, context))
{
total++;
if ((fp == ui->get_output_file()) && ((total % 40) == 0))
{
fprintf ( fp, "more? space, n - next page, q - quit\n");
char c;
scanf("%c", &c);
if (c == 'q')
return 1;
}
}
sym = sym->m_link;
}
}
return 0;
}
else
{
for ( int i=0; i<m_size[level]; i++ )
{
if (tbl[i]) // nested table
if (print_tbl ( fp, (void **)tbl[i], level+1, total, context ) != 0)
return 1; // quit
}
}
return 0;
}
// print all symbols without any order -
// hash table order
int SymTable::hprint ( char *filename, uint32_t context )
{
int index_max = 0;
int icount_max = 0;
int total = 0;
int cont = 0;
FILE *fp = ui->get_output_file();
if(filename)
{
fp = fopen (filename, "w");
if ( fp == NULL )
{
ui->error("cannot open %s\n", filename);
return 1;
}
else
{
ui->verbose("Collect symbols to %s file\n", filename);
}
}
fprintf(fp, "Symbol table: \n");
for ( int j = 0; j<SYM_TBL_SIZE; j++)
{
Symbol *sym = m_bucket[j];
Symbol *prev = NULL;
int count = 0;
while (sym) // possibly iterate through the list
{
if (print_sym (fp, sym, context))
{
count +=1;
total +=1;
if ((cont == 0) && (fp == ui->get_output_file()) &&
((total % 40) == 0))
{
fprintf ( fp, "more? space, n - next page, q - quit\n");
char c;
scanf("%c", &c);
if (c == 'q')
goto quiting;
else if ( c == 'c' )
cont = 1;
}
}
sym = sym->m_next;
}
if (icount_max < count)
{
icount_max = count;
index_max = j;
}
} //for j
quiting:
fprintf(fp, "Total number of symbols: %i \n", total);
fprintf(fp, "max list size = %i at idx = %i \n", icount_max, index_max);
return 0;
}