// ========== 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 ============================================
////////////////////////////////////////////////////////////
// Symbol table submodule
// Copyright (C) 2006 Sun Microsystems, Inc.
// Symbol table implementation file
/////////////////////////////////////////////////////////
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
sprintf (sym_name
, "%s:%s", mname
, sname
);
m_name
= strdup(sym_name
);
if (m_name
) free(m_name
);
if (m_sname
) free(m_sname
);
//////////////////////////////////////////////////////////////
// Container class for all symbols
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
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
))
for (i
=max_lev
; i
>=0; 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];
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
]);
m_tbl
= (void **) calloc(m_size
[0], sizeof(void*));
for (int j
=0; j
<SYM_TBL_SIZE
; j
++)
for (int j
=0; j
<SYM_TBL_SIZE
; j
++)
// get a pointer in multi level addr tables;
// nested tables are allocated if needed
void ** SymTable::alloc( uint64_t addr
)
for ( int i
=0; i
<m_lev
; i
++)
ptr
= tbl
+ ((addr
>>m_sft
[i
]) & m_mask
[i
]);
void **next
= (void**)(*ptr
);
next
= (void **) calloc ( m_size
[i
+1], sizeof(void*));
// 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
)
for ( int i
=0; i
<m_size
[level
]; i
++ )
SymBase
*s
= (SymBase
*)tbl
[i
];
for ( int i
=0; i
<m_size
[level
]; i
++ )
if (tbl
[i
]) // nested table
delete_tbl ( (void **)tbl
[i
], level
+1 );
// search for symbols specified by symbol name;
// return pointer to symbol if found; 0 otherwise
char* name
, // symbol name
Symbol
* start
// start search from this one
Symbol
*sym
= start
? start
->m_next
: NULL
;
// hash index for the bucket
sym
= m_bucket
[sym_hash(name
)];
while (sym
) // possibly iterate through the list
if ( strcmp (sym
->m_sname
, name
) == 0 )
// traverse the list for this bucket
// find symbol specified by address ;
// return 1 if found, 0 otherwise;
uint64_t addr
, // address used to lookup the symbol
SymBase
* start
// start from this symbol
SymBase
* s
= start
? start
->m_link
: NULL
;
Symbol
*sym
= (s
->m_origin
) ? (Symbol
*)(s
->m_origin
) : (Symbol
*)s
;
if ( (addr
>= sym
->m_vaddr
) &&
(addr
< (sym
->m_vaddr
+ sym
->m_size
)) )
// symbol is in the range
// find and output address for all symbols specified by name;
// return 1 if found, 0 otherwise;
char *name
, // name used to lookup the symbol
uint32_t context
, // symbol context
FILE * fp
// output symbol name to stream if found
// hash index for the bucket
int hindex
= sym_hash ( name
);
Symbol
*sym
= m_bucket
[hindex
];
while (sym
) // possibly iterate over the list
(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
);
// traverse the list for this bucket
// find and output full symbol name by specified address ;
// return 1 if found, 0 otherwise;
uint64_t addr
, // address used to lookup the symbol
uint32_t context
, // symbol context
FILE * fp
// output symbol name to stream if found
SymBase
*s
= find ( addr
);
Symbol
*sym
= (s
->m_origin
) ? (Symbol
*)(s
->m_origin
) : (Symbol
*)s
;
(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
);
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
);
// add a new symbol to the symbol table
// return 1 if added, 0 otherwise
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))
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",
Symbol
*sym
= new Symbol(mname
, name
, vaddr
, size
, context
);
uint32_t bsize
= m_size
[m_lev
+1];
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
// find a spot in address tables
SymBase
**p_sym
= (SymBase
**)this->alloc(addr
);
if (*p_sym
==NULL
) // table slot is empty
else // something is already there
// overlap with another symbol
(*p_sym
)->attach ( new_sym
);
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
);
// insert symbol into hash list
int hindex
= sym_hash (name
); // hash index
sym
->m_next
= m_bucket
[hindex
];
// from low to upper addresses
void SymTable::print ( char *filename
, uint32_t context
)
FILE* fp
= fopen (filename
, "w");
ui
->error("cannot open %s\n", filename
);
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
);
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.
&& (print_tbl ( ui
->get_log_file(), m_tbl
, 0, total
, context
)==0))
fprintf(ui
->get_log_file(), "Total number of symbols: %i \n", total
);
int print_sym ( FILE *fp
, Symbol
*s
, uint32_t context
)
if (context
!= Symbol::ANY_CONTEXT
&& context
!= s
->context())
fprintf(fp
, "0x%016llx : 0x%016llx ",
if (s
->context() < Symbol::NO_CONTEXT
)
fprintf(fp
, ": 0x%08lx : %s \n", s
->context(), s
->name());
fprintf(fp
, ": %s \n", s
->name());
// recursively print symbols for all tables on deeper levels
FILE *fp
, // output to the stream
void ** tbl
, // table pointer
uint32_t level
, // table level
uint64_t &total
, // symbol counter
for ( int j
=0; j
<m_size
[level
]; j
++ )
SymBase
*sym
= (Symbol
*)tbl
[j
];
if (sym
->m_origin
) // range mark - skip it
Symbol
*s
= (Symbol
*)sym
;
if (print_sym (fp
, s
, context
))
if ((fp
== ui
->get_output_file()) && ((total
% 40) == 0))
fprintf ( fp
, "more? space, n - next page, q - quit\n");
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)
// print all symbols without any order -
int SymTable::hprint ( char *filename
, uint32_t context
)
FILE *fp
= ui
->get_output_file();
fp
= fopen (filename
, "w");
ui
->error("cannot open %s\n", filename
);
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
];
while (sym
) // possibly iterate through the list
if (print_sym (fp
, sym
, context
))
if ((cont
== 0) && (fp
== ui
->get_output_file()) &&
fprintf ( fp
, "more? space, n - next page, q - quit\n");
fprintf(fp
, "Total number of symbols: %i \n", total
);
fprintf(fp
, "max list size = %i at idx = %i \n", icount_max
, index_max
);