/* 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: kallsyms [--all-symbols] in.map > out.S * * Table compression uses all the unused char codes on the symbols and * maps these to the most used substrings (tokens). For instance, it might * map char code 0xF7 to represent "write_" and then in every symbol where * "write_" appears it can be replaced by 0xF7, saving 5 bytes. * The used codes themselves are also placed in the table so that the * decompresion can work without "special cases". * Applied to kernel symbols, this usually produces a compression ratio * of about 50%. *
*/
if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') {
fprintf(stderr, "line format error\n"); exit(EXIT_FAILURE);
}
name = p;
len = strlen(name);
if (len >= KSYM_NAME_LEN) {
fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n" "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
name, len, KSYM_NAME_LEN); return NULL;
}
if (strcmp(name, "_text") == 0)
_text = addr;
/* Ignore most absolute/undefined (?) symbols. */ if (is_ignored_symbol(name, type)) return NULL;
/* if --all-symbols is not specified, then symbols outside the text
* and inittext sections are discarded */ if (!all_symbols) { /* * Symbols starting with __start and __stop are used to denote * section boundaries, and should always be included:
*/ if (string_starts_with(name, "__start_") ||
string_starts_with(name, "__stop_")) return 1;
if (symbol_in_range(s, text_ranges,
ARRAY_SIZE(text_ranges)) == 0) return 0; /* Corner case. Discard any symbols with the same value as * _etext _einittext; they can move between pass 1 and 2 when * the kallsyms data are added. If these symbols move then * they may get dropped in pass 2, which breaks the kallsyms * rules.
*/ if ((s->addr == text_range_text->end &&
strcmp(name, text_range_text->end_sym)) ||
(s->addr == text_range_inittext->end &&
strcmp(name, text_range_inittext->end_sym))) return 0;
}
return 1;
}
/* remove all the invalid symbols from the table */ staticvoid shrink_table(void)
{ unsignedint i, pos;
pos = 0; for (i = 0; i < table_cnt; i++) { if (symbol_valid(table[i])) { if (pos != i)
table[pos] = table[i];
pos++;
} else {
free(table[i]);
}
}
table_cnt = pos;
}
/* uncompress a compressed symbol. When this function is called, the best table
* might still be compressed itself, so the function needs to be recursive */ staticint expand_symbol(constunsignedchar *data, int len, char *result)
{ int c, rlen, total=0;
while (len) {
c = *data; /* if the table holds a single char that is the same as the one
* we are looking for, then end the search */ if (best_table[c][0]==c && best_table_len[c]==1) {
*result++ = c;
total++;
} else { /* if not, recurse and expand */
rlen = expand_symbol(best_table[c], best_table_len[c], result);
total += rlen;
result += rlen;
}
data++;
len--;
}
*result=0;
/* table of offset markers, that give the offset in the compressed stream
* every 256 symbols */
markers_cnt = (table_cnt + 255) / 256;
markers = xmalloc(sizeof(*markers) * markers_cnt);
output_label("kallsyms_names");
off = 0; for (i = 0; i < table_cnt; i++) { if ((i & 0xFF) == 0)
markers[i >> 8] = off;
table[i]->seq = i;
/* There cannot be any symbol of length zero. */ if (table[i]->len == 0) {
fprintf(stderr, "kallsyms failure: " "unexpected zero symbol length\n"); exit(EXIT_FAILURE);
}
/* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ if (table[i]->len > 0x3FFF) {
fprintf(stderr, "kallsyms failure: " "unexpected huge symbol length\n"); exit(EXIT_FAILURE);
}
/* Encode length with ULEB128. */ if (table[i]->len <= 0x7F) { /* Most symbols use a single byte for the length. */
printf("\t.byte 0x%02x", table[i]->len);
off += table[i]->len + 1;
} else { /* "Big" symbols use two bytes. */
printf("\t.byte 0x%02x, 0x%02x",
(table[i]->len & 0x7F) | 0x80,
(table[i]->len >> 7) & 0x7F);
off += table[i]->len + 2;
} for (k = 0; k < table[i]->len; k++)
printf(", 0x%02x", table[i]->sym[k]);
/* * Now that we wrote out the compressed symbol name, restore the * original name and print it in the comment.
*/
expand_symbol(table[i]->sym, table[i]->len, buf);
strcpy((char *)table[i]->sym, buf);
printf("\t/* %s */\n", table[i]->sym);
}
printf("\n");
output_label("kallsyms_markers"); for (i = 0; i < markers_cnt; i++)
printf("\t.long\t%u\n", markers[i]);
printf("\n");
free(markers);
output_label("kallsyms_token_table");
off = 0; for (i = 0; i < 256; i++) {
best_idx[i] = off;
expand_symbol(best_table[i], best_table_len[i], buf);
printf("\t.asciz\t\"%s\"\n", buf);
off += strlen(buf) + 1;
}
printf("\n");
output_label("kallsyms_token_index"); for (i = 0; i < 256; i++)
printf("\t.short\t%d\n", best_idx[i]);
printf("\n");
output_label("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) { /* * Use the offset relative to the lowest value * encountered of all relative symbols, and emit * non-relocatable fixed offsets that will be fixed * up at runtime.
*/
longlong offset;
offset = table[i]->addr - relative_base; if (offset < 0 || offset > UINT_MAX) {
fprintf(stderr, "kallsyms failure: " "relative symbol value %#llx out of range\n",
table[i]->addr); exit(EXIT_FAILURE);
}
printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
}
printf("\n");
output_label("kallsyms_relative_base"); /* Provide proper symbols relocatability by their '_text' relativeness. */ if (_text <= relative_base)
printf("\tPTR\t_text + %#llx\n", relative_base - _text); else
printf("\tPTR\t_text - %#llx\n", _text - relative_base);
printf("\n");
sort_symbols_by_name();
output_label("kallsyms_seqs_of_names"); for (i = 0; i < table_cnt; i++)
printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n",
(unsignedchar)(table[i]->seq >> 16),
(unsignedchar)(table[i]->seq >> 8),
(unsignedchar)(table[i]->seq >> 0),
table[i]->sym);
printf("\n");
}
/* table lookup compression functions */
/* count all the possible tokens in a symbol */ staticvoid learn_symbol(constunsignedchar *symbol, int len)
{ int i;
for (i = 0; i < len - 1; i++)
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
}
/* decrease the count for all the possible tokens in a symbol */ staticvoid forget_symbol(constunsignedchar *symbol, int len)
{ int i;
for (i = 0; i < len - 1; i++)
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
}
/* do the initial token count */ staticvoid build_initial_token_table(void)
{ unsignedint i;
for (i = 0; i < table_cnt; i++)
learn_symbol(table[i]->sym, table[i]->len);
}
staticunsignedchar *find_token(unsignedchar *str, int len, constunsignedchar *token)
{ int i;
for (i = 0; i < len - 1; i++) { if (str[i] == token[0] && str[i+1] == token[1]) return &str[i];
} return NULL;
}
/* replace a given token in all the valid symbols. Use the sampled symbols
* to update the counts */ staticvoid compress_symbols(constunsignedchar *str, int idx)
{ unsignedint i, len, size; unsignedchar *p1, *p2;
for (i = 0; i < table_cnt; i++) {
len = table[i]->len;
p1 = table[i]->sym;
/* find the token on the symbol */
p2 = find_token(p1, len, str); if (!p2) continue;
/* decrease the counts for this symbol's tokens */
forget_symbol(table[i]->sym, len);
/* sort by address first */ if (sa->addr > sb->addr) return 1; if (sa->addr < sb->addr) return -1;
/* sort by "weakness" type */
wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); if (wa != wb) return wa - wb;
/* sort by "linker script provide" type */
wa = may_be_linker_script_provide_symbol(sa);
wb = may_be_linker_script_provide_symbol(sb); if (wa != wb) return wa - wb;
/* sort by the number of prefix underscores */
wa = strspn(sym_name(sa), "_");
wb = strspn(sym_name(sb), "_"); if (wa != wb) return wa - wb;
/* sort by initial order, so that other symbols are left undisturbed */ return sa->seq - sb->seq;
}
/* find the minimum non-absolute symbol address */ staticvoid record_relative_base(void)
{ /* * The table is sorted by address. * Take the first symbol value.
*/ if (table_cnt)
relative_base = table[0]->addr;
}
int main(int argc, char **argv)
{ while (1) { staticconststruct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
{},
};
int c = getopt_long(argc, argv, "", long_options, NULL);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.