patch-2.3.10 linux/scripts/ksymoops/symbol.c
Next file: linux/scripts/ver_linux
Previous file: linux/scripts/ksymoops/re.c
Back to the patch index
Back to the overall index
- Lines: 445
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.9/linux/scripts/ksymoops/symbol.c
- Orig date:
Tue Jan 5 11:13:56 1999
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/symbol.c linux/scripts/ksymoops/symbol.c
@@ -1,444 +0,0 @@
-/*
- symbol.c.
-
- Symbol handling routines for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Mon Jan 4 09:08:19 EST 1999
- Version 0.6d
- Cast Version to int, glibc 2.1 made elf_addr_t a long.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Fix end of code calculation.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Initialise a symbol source */
-void ss_init(SYMBOL_SET *ss, const char *msg)
-{
- memset(ss, '\0', sizeof(*ss));
- ss->source = strdup(msg);
- if (!ss->source)
- malloc_error(msg);
-}
-
-/* Free dynamic data from a symbol source */
-void ss_free(SYMBOL_SET *ss)
-{
- int i;
- SYMBOL *s;
- for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
- free(s->name);
- free(ss->symbol);
- free(ss->source);
- memset(ss, '\0', sizeof(*ss));
-}
-
-/* Initialise common symbol sets */
-void ss_init_common(void)
-{
- ss_init(&ss_Version, "Version_");
-}
-
-/* Find a symbol name in a symbol source. Brute force ascending order search,
- * no hashing. If start is not NULL, it contains the starting point for the
- * scan and is updated to point to the found entry. If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by name.
- */
-SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
-{
- int i, l;
- SYMBOL *s;
- for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if ((l = strcmp(symbol, s->name)) == 0) {
- if (start)
- *start = i;
- return(s);
- }
- if (l < 0)
- break;
- }
- if (start)
- *start = i;
- return NULL;
-}
-
-/* Find an address in a symbol source. Brute force ascending order search, no
- * hashing. If start is not NULL, it contains the starting point for the scan
- * and is updated to point to the found entry. If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by address.
- */
-static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
- const elf_addr_t address, int *start)
-{
- int i;
- SYMBOL *s;
- for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if (address > s->address)
- continue;
- else if (address == s->address) {
- if (start)
- *start = i;
- return(s);
- }
- else
- break;
- }
- if (start)
- *start = i;
- return NULL;
-}
-
-/* Add a symbol to a symbol set, address in binary */
-void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
- const char type, const char keep, const char *symbol)
-{
- int i;
- char **string = NULL;
- SYMBOL *s;
- static regex_t re_symbol_ver;
- static regmatch_t *re_symbol_ver_pmatch;
- static const char procname[] = "add_symbol_n";
-
- /* Strip out any trailing symbol version _Rxxxxxxxx. */
- re_compile(&re_symbol_ver,
- "^(.*)_R[0-9a-fA-F]{8,}$",
- REG_NEWLINE|REG_EXTENDED,
- &re_symbol_ver_pmatch);
-
- i = regexec(&re_symbol_ver, symbol,
- re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0)
- re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
- &string);
-
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s %s %s '%c' %d '%s'\n",
- procname, ss->source, format_address(address),
- type, keep, i == 0 ? string[1] : symbol);
- if (ss->used > ss->alloc) {
- fprintf(stderr,
- "%s: fatal %s ss %s used (%d) > alloc (%d)\n",
- procname, prefix, ss->source, ss->used, ss->alloc);
- exit(2);
- }
- if (ss->used == ss->alloc) {
- /* increase by 20% or 10, whichever is larger, arbitrary */
- int newsize = ss->alloc*120/100;
- if (newsize < ss->alloc+10)
- newsize = ss->alloc+10;
- if (debug > 3)
- fprintf(stderr,
- "DEBUG: %s increasing %s from %d to %d "
- "entries\n",
- procname, ss->source, ss->alloc, newsize);
- ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
- if (!ss->symbol)
- malloc_error("realloc ss");
- ss->alloc = newsize;
- }
- s = ss->symbol+ss->used;
- if (i == 0) {
- s->name = string[1];
- string[1] = NULL; /* don't free this one */
- }
- else {
- s->name = strdup(symbol);
- if (!s->name)
- malloc_error("strdup symbol");
- }
- s->type = type;
- s->keep = keep;
- s->address = address;
- ++ss->used;
- re_strings_free(&re_symbol_ver, &string);
-}
-
-/* Add a symbol to a symbol set, address in character */
-void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
- const char keep, const char *symbol)
-{
- elf_addr_t a;
- static char const procname[] = "add_symbol";
- errno = 0;
- a = strtoul(address, NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s: %s address '%s' is in error",
- prefix, procname, address);
- perror(" ");
- ++errors;
- }
- add_symbol_n(ss, a, type, 1, symbol);
-}
-
-/* Map an address to symbol, offset and length, address in binary */
-char *map_address(const SYMBOL_SET *ss, const elf_addr_t address)
-{
- int i = 0, l;
- SYMBOL *s;
- static char *map = NULL;
- static int size = 0;
- static const char procname[] = "map_address_n";
-
- if (debug > 2)
- fprintf(stderr, "DEBUG: %s %s %s\n",
- procname, ss->source, format_address(address));
- s = find_symbol_address(ss, address, &i);
- if (!s && --i >= 0)
- s = ss->symbol+i; /* address is between s and s+1 */
-
- /* Extra map text is always < 100 bytes */
- if (s)
- l = strlen(s->name) + 100;
- else
- l = 100;
- if (l > size) {
- map = realloc(map, l);
- if (!map)
- malloc_error(procname);
- size = l;
- }
- if (!s) {
- if (ss->used == 0)
- snprintf(map, size, "No symbols available");
- else
- snprintf(map, size, "Before first symbol");
- }
- else if ((i+1) >= ss->used) {
- /* Somewhere past last symbol. Length of last section of code
- * is unknown, arbitrary cutoff at 32K.
- */
- elf_addr_t offset = address - s->address;
- if (offset > 32768)
- snprintf(map, size, "<END_OF_CODE+%lx/????>", offset);
- else
- snprintf(map, size, "<%s+%lx/????>", s->name, offset);
- }
- else
- snprintf(map, size,
- "<%s+%lx/%lx>",
- s->name, address - s->address,
- (s+1)->address - s->address);
- return(map);
-}
-
-/* After sorting, obsolete symbols are at the top. Delete them. */
-static void ss_compress(SYMBOL_SET *ss)
-{
- int i, j;
- SYMBOL *s;
- static const char procname[] = "ss_compress";
-
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s on table %s, before %d ",
- procname, ss->source, ss->used);
- for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if (!s->keep) {
- for (j = i; j < ss->used; ++j, ++s) {
- if (s->keep) {
- fprintf(stderr,
- "%s: fatal %s table %s is not "
- "sorted\n",
- prefix, procname, ss->source);
- exit(2);
- }
- }
- break;
- }
- }
- for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s)
- free(s->name);
- ss->used = i;
- if (debug > 1)
- fprintf(stderr, "after %d\n", ss->used);
-}
-
-static int ss_compare_atn(const void *a, const void *b)
-{
- SYMBOL *c = (SYMBOL *) a;
- SYMBOL *d = (SYMBOL *) b;
- int i;
-
- /* obsolete symbols to the top */
- if (c->keep != d->keep)
- return(d->keep - c->keep);
- if (c->address > d->address)
- return(1);
- if (c->address < d->address)
- return(-1);
- if (c->type > d->type)
- return(1);
- if (c->type < d->type)
- return(-1);
- if ((i = strcmp(c->name, d->name)))
- return(i);
- return(0);
-}
-
-/* Sort a symbol set by address, type and name */
-void ss_sort_atn(SYMBOL_SET *ss)
-{
- if (debug)
- fprintf(stderr, "DEBUG: sorting symbols for %s (atn)\n",
- ss->source);
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_atn);
- ss_compress(ss);
-}
-
-static int ss_compare_na(const void *a, const void *b)
-{
- SYMBOL *c = (SYMBOL *) a;
- SYMBOL *d = (SYMBOL *) b;
- int i;
-
- /* obsolete symbols to the top */
- if (c->keep != d->keep)
- return(d->keep - c->keep);
- if ((i = strcmp(c->name, d->name)))
- return(i);
- if (c->address > d->address)
- return(1);
- if (c->address < d->address)
- return(-1);
- return(0);
-}
-
-/* Sort a symbol set by name and address, drop duplicates. There should be
- * no duplicates but I have seen duplicates in ksyms on 2.0.35.
- */
-void ss_sort_na(SYMBOL_SET *ss)
-{
- int i;
- SYMBOL *s;
- if (debug)
- fprintf(stderr, "DEBUG: sorting symbols for %s (na)\n",
- ss->source);
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_na);
- ss_compress(ss);
- s = ss->symbol;
- for (i = 0; i < ss->used-1; ++i) {
- if (strcmp(s->name, (s+1)->name) == 0 &&
- s->address == (s+1)->address) {
- if (s->type != ' ')
- (s+1)->keep = 0;
- else
- s->keep = 0;
- }
- ++s;
- }
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_na);
- ss_compress(ss);
-}
-
-/* Copy a symbol set, including all its strings */
-SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
-{
- SYMBOL_SET *ssc;
- if (debug > 3)
- fprintf(stderr,
- "DEBUG: ss_copy %s\n", ss->source);
- ssc = malloc(sizeof(*ssc));
- if (!ssc)
- malloc_error("copy ssc");
- ss_init(ssc, ss->source);
- ssc->used = ss->used;
- ssc->alloc = ss->used; /* shrink the copy */
- ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
- if (!(ssc->symbol))
- malloc_error("copy ssc symbols");
- memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
- return(ssc);
-}
-
-/* Convert version number to major, minor string. */
-static const char *format_Version(elf_addr_t Version)
-{
- static char string[12]; /* 255.255.255\0 worst case */
- snprintf(string, sizeof(string), "%d.%d.%d",
- (int) ((Version >> 16) & 0xff),
- (int) ((Version >> 8) & 0xff),
- (int) ((Version) & 0xff));
- return(string);
-}
-
-/* Save version number. The "address" is the version number, the "symbol" is
- * the source of the version.
- */
-void add_Version(const char *version, const char *source)
-{
- static char const procname[] = "add_Version";
- int i = atoi(version);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s %s %s %s\n",
- procname, source, version, format_Version(i));
- add_symbol_n(&ss_Version, i, 'V', 1, source);
-}
-
-/* Extract Version_ number from a symbol set and save it. */
-void extract_Version(SYMBOL_SET *ss)
-{
- int i = 0;
- SYMBOL *s;
-
- s = find_symbol_name(ss, "Version_", &i);
- if (!s && i < ss->used)
- s = ss->symbol+i; /* first symbol after "Version_" */
- if (!s || strncmp(s->name, "Version_", 8))
- return;
- add_Version(s->name+8, ss->source);
-}
-
-/* Compare all extracted Version numbers. Silent unless there is a problem. */
-void compare_Version(void)
-{
- int i = 0;
- SYMBOL *s, *s0;
- static int prev_used = 0;
-
- if (!ss_Version.used)
- return;
- /* Only check if the Version table has changed in size */
- if (prev_used == ss_Version.used)
- return;
-
- ss_sort_na(&ss_Version);
- s0 = s = ss_Version.symbol;
- if (debug)
- fprintf(stderr, "DEBUG: Version %s\n",
- format_Version(s0->address));
- for (i = 0; i < ss_Version.used; ++i, ++s) {
- if (s->address != s0->address) {
- fprintf(stderr,
- "Version mismatch error. %s says %s, ",
- s0->name,
- format_Version(s0->address));
- fprintf(stderr,
- "%s says %s. Expect lots of address "
- "mismatches.\n",
- s->name,
- format_Version(s->address));
- ++errors;
- }
- }
- prev_used = ss_Version.used;
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)