diff options
author | Richard Lowe <richlowe@richlowe.net> | 2011-09-25 05:29:49 +0100 |
---|---|---|
committer | Richard Lowe <richlowe@richlowe.net> | 2011-09-25 05:29:49 +0100 |
commit | d322ce9e5e9bb437d93bf09b5354eede23491de7 (patch) | |
tree | 7a3cc5a877d01d51391e9f27a5a929aae8eda1e3 /usr/src/cmd/dis/dis_target.c | |
parent | 2408d5be4d43f2c643cbcf11db3a58722a9153b2 (diff) | |
parent | 2807a6ec36a80c58154d9929cf429e8d6100f20a (diff) | |
download | illumos-joyent-d322ce9e5e9bb437d93bf09b5354eede23491de7.tar.gz |
Merge remote-tracking branch 'illumos/master' into gcc/upgrade
Conflicts:
usr/src/common/dis/i386/dis_tables.c
Diffstat (limited to 'usr/src/cmd/dis/dis_target.c')
-rw-r--r-- | usr/src/cmd/dis/dis_target.c | 139 |
1 files changed, 118 insertions, 21 deletions
diff --git a/usr/src/cmd/dis/dis_target.c b/usr/src/cmd/dis/dis_target.c index 54eb8a3bb5..c509157335 100644 --- a/usr/src/cmd/dis/dis_target.c +++ b/usr/src/cmd/dis/dis_target.c @@ -21,6 +21,8 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Copyright 2011 Jason King. All rights reserved. */ #include <assert.h> @@ -34,6 +36,8 @@ #include <sys/fcntl.h> #include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/types.h> #include "dis_target.h" #include "dis_util.h" @@ -58,6 +62,19 @@ typedef struct sym_entry { } sym_entry_t; /* + * Create a map of the virtual address ranges of every section. This will + * allow us to create dummpy mappings for unassigned addresses. Otherwise + * multiple sections with unassigned addresses will appear to overlap and + * mess up symbol resolution (which uses the virtual address). + */ +typedef struct dis_shnmap { + const char *dm_name; /* name of section */ + uint64_t dm_start; /* virtual address of section */ + size_t dm_length; /* address length */ + boolean_t dm_mapped; /* did we assign the mapping */ +} dis_shnmap_t; + +/* * Target data structure. This structure keeps track of the ELF file * information, a few bits of pre-processed section index information, and * sorted versions of the symbol table. We also keep track of the last symbol @@ -75,6 +92,8 @@ struct dis_tgt { int dt_symcount; /* # of symbol table entries */ struct dis_tgt *dt_next; /* next target (for archives) */ Elf_Arhdr *dt_arhdr; /* archive header (for archives) */ + dis_shnmap_t *dt_shnmap; /* section address map */ + size_t dt_shncount; /* # of sections in target */ }; /* @@ -105,17 +124,23 @@ struct dis_scn { #define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0) /* - * Pick out the best symbol to used based on the sections available in the - * target. We prefer SHT_SYMTAB over SHT_DYNSYM. + * Save the virtual address range for this section and select the + * best section to use as the symbol table. We prefer SHT_SYMTAB + * over SHT_DYNSYM. */ /* ARGSUSED */ static void -get_symtab(dis_tgt_t *tgt, dis_scn_t *scn, void *data) +tgt_scn_init(dis_tgt_t *tgt, dis_scn_t *scn, void *data) { int *index = data; *index += 1; + tgt->dt_shnmap[*index].dm_name = scn->ds_name; + tgt->dt_shnmap[*index].dm_start = scn->ds_shdr.sh_addr; + tgt->dt_shnmap[*index].dm_length = scn->ds_shdr.sh_size; + tgt->dt_shnmap[*index].dm_mapped = B_FALSE; + /* * Prefer SHT_SYMTAB over SHT_DYNSYM */ @@ -292,6 +317,14 @@ construct_symtab(dis_tgt_t *tgt) continue; } + /* + * If we had to map this section, its symbol value + * also needs to be mapped. + */ + if (tgt->dt_shnmap[sym->se_shndx].dm_mapped) + sym->se_sym.st_value += + tgt->dt_shnmap[sym->se_shndx].dm_start; + sym++; } @@ -304,6 +337,40 @@ construct_symtab(dis_tgt_t *tgt) } /* + * Assign virtual address ranges for sections that need it + */ +static void +create_addrmap(dis_tgt_t *tgt) +{ + uint64_t addr; + int i; + + if (tgt->dt_shnmap == NULL) + return; + + /* find the greatest used address */ + for (addr = 0, i = 1; i < tgt->dt_shncount; i++) + if (tgt->dt_shnmap[i].dm_start > addr) + addr = tgt->dt_shnmap[i].dm_start + + tgt->dt_shnmap[i].dm_length; + + addr = P2ROUNDUP(addr, 0x1000); + + /* + * Assign section a starting address beyond the largest mapped section + * if no address was given. + */ + for (i = 1; i < tgt->dt_shncount; i++) { + if (tgt->dt_shnmap[i].dm_start != 0) + continue; + + tgt->dt_shnmap[i].dm_start = addr; + tgt->dt_shnmap[i].dm_mapped = B_TRUE; + addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000); + } +} + +/* * Create a target backed by an ELF file. */ dis_tgt_t * @@ -393,9 +460,14 @@ dis_tgt_create(const char *file) return (NULL); } + current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) * + ehdr.e_shnum); + current->dt_shncount = ehdr.e_shnum; + idx = 0; - dis_tgt_section_iter(current, get_symtab, &idx); + dis_tgt_section_iter(current, tgt_scn_init, &idx); + create_addrmap(current); if (current->dt_symidx != 0) construct_symtab(current); @@ -488,6 +560,28 @@ dis_tgt_destroy(dis_tgt_t *tgt) } /* + * Given an address, return the section it is in and set the offset within + * the section. + */ +const char * +dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset) +{ + int i; + + for (i = 1; i < tgt->dt_shncount; i++) { + if ((addr >= tgt->dt_shnmap[i].dm_start) && + (addr < tgt->dt_shnmap[i].dm_start + + tgt->dt_shnmap[i].dm_length)) { + *offset = addr - tgt->dt_shnmap[i].dm_start; + return (tgt->dt_shnmap[i].dm_name); + } + } + + *offset = 0; + return (NULL); +} + +/* * Given an address, returns the name of the corresponding symbol, as well as * the offset within that symbol. If no matching symbol is found, then NULL is * returned. @@ -577,29 +671,20 @@ dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result, /* * Given an address, return the starting offset of the next symbol in the file. - * Relies on the fact that this is only used when we encounter a bad instruction - * in the input stream, so we know that the last symbol looked up will be in the - * cache. */ off_t dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr) { - sym_entry_t *sym = tgt->dt_symcache; - uint64_t start; - - /* make sure the cached symbol and address are valid */ - if (sym == NULL || addr < sym->se_sym.st_value || - addr >= sym->se_sym.st_value + sym->se_sym.st_size) - return (0); - - start = sym->se_sym.st_value; + sym_entry_t *sym; - /* find the next symbol */ - while (sym != tgt->dt_symtab + tgt->dt_symcount && - sym->se_sym.st_value == start) - sym++; + for (sym = tgt->dt_symcache; + sym != tgt->dt_symtab + tgt->dt_symcount; + sym++) { + if (sym->se_sym.st_value >= addr) + return (sym->se_sym.st_value - addr); + } - return (sym->se_sym.st_value - addr); + return (0); } /* @@ -635,6 +720,15 @@ dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data) continue; } + /* + * dis_tgt_section_iter is also used before the section map + * is initialized, so only check when we need to. If the + * section map is uninitialized, it will return 0 and have + * no net effect. + */ + if (sdata.ds_shdr.sh_addr == 0) + sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start; + func(tgt, &sdata, data); } } @@ -740,6 +834,9 @@ dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data) continue; } + if (tgt->dt_shnmap[sym->se_shndx].dm_mapped) + shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start; + /* * Verify that the address lies within the section that we think * it does. |