blob: 43c110fe782914cd6613a915d7a72c3f31aa620b [file] [log] [blame]
/* Generate assembler source containing symbol information
*
* Copyright 2002 by Kai Germaschewski
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Usage: nm -n vmlinux | scripts/kallsyms > symbols.S
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct sym_entry {
unsigned long long addr;
char type;
char *sym;
};
static struct sym_entry *table;
static int size, cnt;
static unsigned long long _stext, _etext, _sinittext, _einittext;
static void
usage(void)
{
fprintf(stderr, "Usage: kallsyms < in.map > out.S\n");
exit(1);
}
static int
read_symbol(FILE *in, struct sym_entry *s)
{
char str[500];
int rc;
rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
if (rc != 3) {
if (rc != EOF) {
/* skip line */
fgets(str, 500, in);
}
return -1;
}
s->sym = strdup(str);
return 0;
}
static int
symbol_valid(struct sym_entry *s)
{
if ((s->addr < _stext || s->addr > _etext)
&& (s->addr < _sinittext || s->addr > _einittext))
return 0;
if (strstr(s->sym, "_compiled."))
return 0;
return 1;
}
static void
read_map(FILE *in)
{
int i;
while (!feof(in)) {
if (cnt >= size) {
size += 10000;
table = realloc(table, sizeof(*table) * size);
if (!table) {
fprintf(stderr, "out of memory\n");
exit (1);
}
}
if (read_symbol(in, &table[cnt]) == 0)
cnt++;
}
for (i = 0; i < cnt; i++) {
if (strcmp(table[i].sym, "_stext") == 0)
_stext = table[i].addr;
if (strcmp(table[i].sym, "_etext") == 0)
_etext = table[i].addr;
if (strcmp(table[i].sym, "_sinittext") == 0)
_sinittext = table[i].addr;
if (strcmp(table[i].sym, "_einittext") == 0)
_einittext = table[i].addr;
}
}
static void
write_src(void)
{
unsigned long long last_addr;
int i, valid = 0;
char *prev;
printf("#include <asm/types.h>\n");
printf("#if BITS_PER_LONG == 64\n");
printf("#define PTR .quad\n");
printf("#define ALGN .align 8\n");
printf("#else\n");
printf("#define PTR .long\n");
printf("#define ALGN .align 4\n");
printf("#endif\n");
printf(".data\n");
printf(".globl kallsyms_addresses\n");
printf("\tALGN\n");
printf("kallsyms_addresses:\n");
for (i = 0, last_addr = 0; i < cnt; i++) {
if (!symbol_valid(&table[i]))
continue;
if (table[i].addr == last_addr)
continue;
printf("\tPTR\t%#llx\n", table[i].addr);
valid++;
last_addr = table[i].addr;
}
printf("\n");
printf(".globl kallsyms_num_syms\n");
printf("\tALGN\n");
printf("kallsyms_num_syms:\n");
printf("\tPTR\t%d\n", valid);
printf("\n");
printf(".globl kallsyms_names\n");
printf("\tALGN\n");
printf("kallsyms_names:\n");
prev = "";
for (i = 0, last_addr = 0; i < cnt; i++) {
int k;
if (!symbol_valid(&table[i]))
continue;
if (table[i].addr == last_addr)
continue;
for (k = 0; table[i].sym[k] && table[i].sym[k] == prev[k]; ++k)
;
printf("\t.byte 0x%02x\n\t.asciz\t\"%s\"\n", k, table[i].sym + k);
last_addr = table[i].addr;
prev = table[i].sym;
}
printf("\n");
}
int
main(int argc, char **argv)
{
if (argc != 1)
usage();
read_map(stdin);
write_src();
return 0;
}