mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-09 00:53:16 +00:00
* shell/cmds.c, shell/shell.c: Remove fileno-hacks. * monitor/mon-symbols.c: Remove #undef __STRICT_ANSI__.
483 lines
11 KiB
C
483 lines
11 KiB
C
/*
|
|
* File: symbols.c
|
|
*
|
|
* Description:
|
|
* Symbol table manager for the RTEMS monitor.
|
|
* These routines may be used by other system resources also.
|
|
*
|
|
*
|
|
* TODO:
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
|
|
#include <rtems.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <rtems/monitor.h>
|
|
#include <rtems/symbols.h>
|
|
|
|
|
|
rtems_symbol_table_t *
|
|
rtems_symbol_table_create()
|
|
{
|
|
rtems_symbol_table_t *table;
|
|
|
|
table = (rtems_symbol_table_t *) malloc(sizeof(rtems_symbol_table_t));
|
|
memset((void *) table, 0, sizeof(*table));
|
|
|
|
table->growth_factor = 30; /* 30 percent */
|
|
|
|
return table;
|
|
}
|
|
|
|
void
|
|
rtems_symbol_table_destroy(rtems_symbol_table_t *table)
|
|
{
|
|
rtems_symbol_string_block_t *p, *pnext;
|
|
|
|
if (table)
|
|
{
|
|
if (table->addresses)
|
|
(void) free(table->addresses);
|
|
table->addresses = 0;
|
|
p = table->string_buffer_head;
|
|
while (p)
|
|
{
|
|
pnext = p->next;
|
|
free(p);
|
|
p = pnext;
|
|
}
|
|
table->string_buffer_head = 0;
|
|
table->string_buffer_current = 0;
|
|
|
|
free(table);
|
|
}
|
|
}
|
|
|
|
rtems_symbol_t *
|
|
rtems_symbol_create(
|
|
rtems_symbol_table_t *table,
|
|
char *name,
|
|
rtems_unsigned32 value
|
|
)
|
|
{
|
|
int symbol_length;
|
|
size_t newsize;
|
|
rtems_symbol_t *sp;
|
|
|
|
symbol_length = strlen(name) + 1; /* include '\000' in length */
|
|
|
|
/* need to grow the table? */
|
|
if (table->next >= table->size)
|
|
{
|
|
if (table->size == 0)
|
|
newsize = 100;
|
|
else
|
|
newsize = table->size + (table->size / (100 / table->growth_factor));
|
|
|
|
table->addresses = (rtems_symbol_t *) realloc((void *) table->addresses, newsize * sizeof(rtems_symbol_t));
|
|
if (table->addresses == 0) /* blew it; lost orig */
|
|
goto failed;
|
|
table->size = newsize;
|
|
}
|
|
|
|
sp = &table->addresses[table->next];
|
|
sp->value = value;
|
|
|
|
/* Have to add it to string pool */
|
|
/* need to grow pool? */
|
|
|
|
if ((table->string_buffer_head == 0) ||
|
|
(table->strings_next + symbol_length) >= SYMBOL_STRING_BLOCK_SIZE)
|
|
{
|
|
rtems_symbol_string_block_t *p;
|
|
|
|
p = (rtems_symbol_string_block_t *) malloc(sizeof(rtems_symbol_string_block_t));
|
|
if (p == 0)
|
|
goto failed;
|
|
p->next = 0;
|
|
if (table->string_buffer_head == 0)
|
|
table->string_buffer_head = p;
|
|
else
|
|
table->string_buffer_current->next = p;
|
|
table->string_buffer_current = p;
|
|
|
|
table->strings_next = 0;
|
|
}
|
|
|
|
sp->name = table->string_buffer_current->buffer + table->strings_next;
|
|
(void) strcpy(sp->name, name);
|
|
|
|
table->strings_next += symbol_length;
|
|
table->sorted = 0;
|
|
table->next++;
|
|
|
|
return sp;
|
|
|
|
/* XXX Not sure what to do here. We've possibly destroyed the initial
|
|
symbol table due to realloc failure */
|
|
failed:
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Qsort entry point for compare by address
|
|
*/
|
|
|
|
static int
|
|
rtems_symbol_compare(const void *e1,
|
|
const void *e2)
|
|
{
|
|
rtems_symbol_t *s1, *s2;
|
|
s1 = (rtems_symbol_t *) e1;
|
|
s2 = (rtems_symbol_t *) e2;
|
|
|
|
if (s1->value < s2->value)
|
|
return -1;
|
|
if (s1->value > s2->value)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Sort the symbol table using qsort
|
|
*/
|
|
|
|
static void
|
|
rtems_symbol_sort(rtems_symbol_table_t *table)
|
|
{
|
|
qsort((void *) table->addresses, (size_t) table->next,
|
|
sizeof(rtems_symbol_t), rtems_symbol_compare);
|
|
table->sorted = 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Search the symbol table by address
|
|
* This code based on CYGNUS newlib bsearch, but changed
|
|
* to allow for finding closest symbol <= key
|
|
*/
|
|
|
|
rtems_symbol_t *
|
|
rtems_symbol_value_lookup(
|
|
rtems_symbol_table_t *table,
|
|
rtems_unsigned32 value
|
|
)
|
|
{
|
|
rtems_symbol_t *sp;
|
|
rtems_symbol_t *base;
|
|
rtems_symbol_t *best = 0;
|
|
rtems_unsigned32 distance;
|
|
rtems_unsigned32 best_distance = ~0;
|
|
rtems_unsigned32 elements;
|
|
|
|
if (table == 0)
|
|
table = rtems_monitor_symbols;
|
|
|
|
if ((table == 0) || (table->size == 0))
|
|
return 0;
|
|
|
|
if (table->sorted == 0)
|
|
rtems_symbol_sort(table);
|
|
|
|
base = table->addresses;
|
|
elements = table->next;
|
|
|
|
while (elements)
|
|
{
|
|
sp = base + (elements / 2);
|
|
if (value < sp->value)
|
|
elements /= 2;
|
|
else if (value > sp->value)
|
|
{
|
|
distance = value - sp->value;
|
|
if (distance < best_distance)
|
|
{
|
|
best_distance = distance;
|
|
best = sp;
|
|
}
|
|
base = sp + 1;
|
|
elements = (elements / 2) - (elements % 2 ? 0 : 1);
|
|
}
|
|
else
|
|
return sp;
|
|
}
|
|
|
|
if (value == base->value)
|
|
return base;
|
|
|
|
return best;
|
|
}
|
|
|
|
/*
|
|
* Search the symbol table for the exact matching address.
|
|
* If the symbol table has already been sorted, then
|
|
* call the regular symbol value lookup, however, it it
|
|
* has not yet been sorted, search it sequentially.
|
|
* This routine is primarily used for low level symbol
|
|
* lookups (eg. from exception handler and interrupt routines)
|
|
* where the penality of sorted is not wanted and where
|
|
* an exact match is needed such that symbol table order
|
|
* is not important.
|
|
*/
|
|
const rtems_symbol_t *
|
|
rtems_symbol_value_lookup_exact(
|
|
rtems_symbol_table_t *table,
|
|
rtems_unsigned32 value
|
|
)
|
|
{
|
|
rtems_unsigned32 s;
|
|
rtems_symbol_t *sp;
|
|
|
|
if (table == 0)
|
|
{
|
|
table = rtems_monitor_symbols;
|
|
if (table == 0)
|
|
return NULL;
|
|
}
|
|
|
|
if (table->sorted)
|
|
{
|
|
sp = rtems_symbol_value_lookup(table, value);
|
|
if ( rtems_symbol_value(sp) == value )
|
|
return sp;
|
|
else
|
|
return NULL; /* not an exact match */
|
|
}
|
|
|
|
for (s = 0, sp = table->addresses; s < table->next; s++, sp++)
|
|
{
|
|
if ( sp->value == value )
|
|
return sp;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Search the symbol table by string name (case independent)
|
|
*/
|
|
|
|
rtems_symbol_t *
|
|
rtems_symbol_name_lookup(
|
|
rtems_symbol_table_t *table,
|
|
char *name
|
|
)
|
|
{
|
|
rtems_unsigned32 s;
|
|
rtems_symbol_t *sp;
|
|
|
|
if (table == 0)
|
|
{
|
|
table = rtems_monitor_symbols;
|
|
if (table == 0)
|
|
return NULL;
|
|
}
|
|
|
|
for (s = 0, sp = table->addresses; s < table->next; s++, sp++)
|
|
{
|
|
if ( strcasecmp(sp->name, name) == 0 )
|
|
return sp;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void *
|
|
rtems_monitor_symbol_next(
|
|
void *object_info,
|
|
rtems_monitor_symbol_t *canonical,
|
|
rtems_id *next_id
|
|
)
|
|
{
|
|
rtems_symbol_table_t *table;
|
|
rtems_unsigned32 n = rtems_get_index(*next_id);
|
|
|
|
table = *(rtems_symbol_table_t **) object_info;
|
|
if (table == 0)
|
|
goto failed;
|
|
|
|
if (n >= table->next)
|
|
goto failed;
|
|
|
|
/* NOTE: symbols do not have id and name fields */
|
|
|
|
if (table->sorted == 0)
|
|
rtems_symbol_sort(table);
|
|
|
|
_Thread_Disable_dispatch();
|
|
|
|
*next_id += 1;
|
|
return (void *) (table->addresses + n);
|
|
|
|
failed:
|
|
*next_id = RTEMS_OBJECT_ID_FINAL;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rtems_monitor_symbol_canonical(
|
|
rtems_monitor_symbol_t *canonical_symbol,
|
|
rtems_symbol_t *sp
|
|
)
|
|
{
|
|
canonical_symbol->value = sp->value;
|
|
canonical_symbol->offset = 0;
|
|
strncpy(canonical_symbol->name, sp->name, sizeof(canonical_symbol->name));
|
|
}
|
|
|
|
|
|
void
|
|
rtems_monitor_symbol_canonical_by_name(
|
|
rtems_monitor_symbol_t *canonical_symbol,
|
|
char *name
|
|
)
|
|
{
|
|
rtems_symbol_t *sp;
|
|
|
|
sp = rtems_symbol_name_lookup(0, name);
|
|
|
|
canonical_symbol->value = sp ? sp->value : 0;
|
|
|
|
strncpy(canonical_symbol->name, name, sizeof(canonical_symbol->name));
|
|
canonical_symbol->offset = 0;
|
|
}
|
|
|
|
void
|
|
rtems_monitor_symbol_canonical_by_value(
|
|
rtems_monitor_symbol_t *canonical_symbol,
|
|
void *value_void_p
|
|
)
|
|
{
|
|
unsigned32 value = (unsigned32) value_void_p;
|
|
rtems_symbol_t *sp;
|
|
|
|
sp = rtems_symbol_value_lookup(0, value);
|
|
if (sp)
|
|
{
|
|
canonical_symbol->value = sp->value;
|
|
canonical_symbol->offset = value - sp->value;
|
|
strncpy(canonical_symbol->name, sp->name, sizeof(canonical_symbol->name));
|
|
}
|
|
else
|
|
{
|
|
canonical_symbol->value = value;
|
|
canonical_symbol->offset = 0;
|
|
canonical_symbol->name[0] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
unsigned32
|
|
rtems_monitor_symbol_dump(
|
|
rtems_monitor_symbol_t *canonical_symbol,
|
|
boolean verbose
|
|
)
|
|
{
|
|
unsigned32 length = 0;
|
|
|
|
/*
|
|
* print the name if it exists AND if value is non-zero
|
|
* Ie: don't print some garbage symbol for address 0
|
|
*/
|
|
|
|
if (canonical_symbol->name[0] && (canonical_symbol->value != 0))
|
|
{
|
|
if (canonical_symbol->offset == 0)
|
|
length += printf("%.*s",
|
|
(int) sizeof(canonical_symbol->name),
|
|
canonical_symbol->name);
|
|
else
|
|
length += printf("<%.*s+0x%x>",
|
|
(int) sizeof(canonical_symbol->name),
|
|
canonical_symbol->name,
|
|
canonical_symbol->offset);
|
|
if (verbose)
|
|
length += printf(" [0x%x]", canonical_symbol->value);
|
|
}
|
|
else
|
|
length += printf("[0x%x]", canonical_symbol->value);
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
void
|
|
rtems_monitor_symbol_dump_all(
|
|
rtems_symbol_table_t *table,
|
|
boolean verbose
|
|
)
|
|
{
|
|
rtems_unsigned32 s;
|
|
rtems_symbol_t *sp;
|
|
|
|
if (table == 0)
|
|
{
|
|
table = rtems_monitor_symbols;
|
|
if (table == 0)
|
|
return;
|
|
}
|
|
|
|
if (table->sorted == 0)
|
|
rtems_symbol_sort(table);
|
|
|
|
for (s = 0, sp = table->addresses; s < table->next; s++, sp++)
|
|
{
|
|
rtems_monitor_symbol_t canonical_symbol;
|
|
|
|
rtems_monitor_symbol_canonical(&canonical_symbol, sp);
|
|
rtems_monitor_symbol_dump(&canonical_symbol, TRUE);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'symbol' command
|
|
*/
|
|
|
|
void
|
|
rtems_monitor_symbol_cmd(
|
|
int argc,
|
|
char **argv,
|
|
unsigned32 command_arg,
|
|
boolean verbose
|
|
)
|
|
{
|
|
int arg;
|
|
rtems_symbol_table_t *table;
|
|
|
|
table = *(rtems_symbol_table_t **) command_arg;
|
|
if (table == 0)
|
|
{
|
|
table = rtems_monitor_symbols;
|
|
if (table == 0)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Use object command to dump out whole symbol table
|
|
*/
|
|
if (argc == 1)
|
|
rtems_monitor_symbol_dump_all(table, verbose);
|
|
else
|
|
{
|
|
rtems_monitor_symbol_t canonical_symbol;
|
|
|
|
for (arg=1; argv[arg]; arg++)
|
|
{
|
|
rtems_monitor_symbol_canonical_by_name(&canonical_symbol, argv[arg]);
|
|
rtems_monitor_symbol_dump(&canonical_symbol, verbose);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|