Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  symsearch.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

/*
 * Helper functions for finding the symbol in an ELF which is "nearest"
 * to a given address.
 */

#include <xalloc.h>
#include "modpost.h"

struct syminfo {
 unsigned int symbol_index;
 unsigned int section_index;
 Elf_Addr addr;
};

/*
 * Container used to hold an entire binary search table.
 * Entries in table are ascending, sorted first by section_index,
 * then by addr, and last by symbol_index.  The sorting by
 * symbol_index is used to ensure predictable behavior when
 * multiple symbols are present with the same address; all
 * symbols past the first are effectively ignored, by eliding
 * them in symsearch_fixup().
 */

struct symsearch {
 unsigned int table_size;
 struct syminfo table[];
};

static int syminfo_compare(const void *s1, const void *s2)
{
 const struct syminfo *sym1 = s1;
 const struct syminfo *sym2 = s2;

 if (sym1->section_index > sym2->section_index)
  return 1;
 if (sym1->section_index < sym2->section_index)
  return -1;
 if (sym1->addr > sym2->addr)
  return 1;
 if (sym1->addr < sym2->addr)
  return -1;
 if (sym1->symbol_index > sym2->symbol_index)
  return 1;
 if (sym1->symbol_index < sym2->symbol_index)
  return -1;
 return 0;
}

static unsigned int symbol_count(struct elf_info *elf)
{
 unsigned int result = 0;

 for (Elf_Sym *sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
  if (is_valid_name(elf, sym))
   result++;
 }
 return result;
}

/*
 * Populate the search array that we just allocated.
 * Be slightly paranoid here.  The ELF file is mmap'd and could
 * conceivably change between symbol_count() and symsearch_populate().
 * If we notice any difference, bail out rather than potentially
 * propagating errors or crashing.
 */

static void symsearch_populate(struct elf_info *elf,
          struct syminfo *table,
          unsigned int table_size)
{
 bool is_arm = (elf->hdr->e_machine == EM_ARM);

 for (Elf_Sym *sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
  if (is_valid_name(elf, sym)) {
   if (table_size-- == 0)
    fatal("%s: size mismatch\n", __func__);
   table->symbol_index = sym - elf->symtab_start;
   table->section_index = get_secindex(elf, sym);
   table->addr = sym->st_value;

   /*
 * For ARM Thumb instruction, the bit 0 of st_value is
 * set if the symbol is STT_FUNC type. Mask it to get
 * the address.
 */

   if (is_arm && ELF_ST_TYPE(sym->st_info) == STT_FUNC)
    table->addr &= ~1;

   table++;
  }
 }

 if (table_size != 0)
  fatal("%s: size mismatch\n", __func__);
}

/*
 * Do any fixups on the table after sorting.
 * For now, this just finds adjacent entries which have
 * the same section_index and addr, and it propagates
 * the first symbol_index over the subsequent entries,
 * so that only one symbol_index is seen for any given
 * section_index and addr.  This ensures that whether
 * we're looking at an address from "above" or "below"
 * that we see the same symbol_index.
 * This does leave some duplicate entries in the table;
 * in practice, these are a small fraction of the
 * total number of entries, and they are harmless to
 * the binary search algorithm other than a few occasional
 * unnecessary comparisons.
 */

static void symsearch_fixup(struct syminfo *table, unsigned int table_size)
{
 /* Don't look at index 0, it will never change. */
 for (unsigned int i = 1; i < table_size; i++) {
  if (table[i].addr == table[i - 1].addr &&
      table[i].section_index == table[i - 1].section_index) {
   table[i].symbol_index = table[i - 1].symbol_index;
  }
 }
}

void symsearch_init(struct elf_info *elf)
{
 unsigned int table_size = symbol_count(elf);

 elf->symsearch = xmalloc(sizeof(struct symsearch) +
           sizeof(struct syminfo) * table_size);
 elf->symsearch->table_size = table_size;

 symsearch_populate(elf, elf->symsearch->table, table_size);
 qsort(elf->symsearch->table, table_size,
       sizeof(struct syminfo), syminfo_compare);

 symsearch_fixup(elf->symsearch->table, table_size);
}

void symsearch_finish(struct elf_info *elf)
{
 free(elf->symsearch);
 elf->symsearch = NULL;
}

/*
 * Find the syminfo which is in secndx and "nearest" to addr.
 * allow_negative: allow returning a symbol whose address is > addr.
 * min_distance: ignore symbols which are further away than this.
 *
 * Returns a pointer into the symbol table for success.
 * Returns NULL if no legal symbol is found within the requested range.
 */

Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr,
    unsigned int secndx, bool allow_negative,
    Elf_Addr min_distance)
{
 unsigned int hi = elf->symsearch->table_size;
 unsigned int lo = 0;
 struct syminfo *table = elf->symsearch->table;
 struct syminfo target;

 target.addr = addr;
 target.section_index = secndx;
 target.symbol_index = ~0;  /* compares greater than any actual index */
 while (hi > lo) {
  unsigned int mid = lo + (hi - lo) / 2;  /* Avoids overflow */

  if (syminfo_compare(&table[mid], &target) > 0)
   hi = mid;
  else
   lo = mid + 1;
 }

 /*
 * table[hi], if it exists, is the first entry in the array which
 * lies beyond target.  table[hi - 1], if it exists, is the last
 * entry in the array which comes before target, including the
 * case where it perfectly matches the section and the address.
 *
 * Note -- if the address we're looking up falls perfectly
 * in the middle of two symbols, this is written to always
 * prefer the symbol with the lower address.
 */

 Elf_Sym *result = NULL;

 if (allow_negative &&
     hi < elf->symsearch->table_size &&
     table[hi].section_index == secndx &&
     table[hi].addr - addr <= min_distance) {
  min_distance = table[hi].addr - addr;
  result = &elf->symtab_start[table[hi].symbol_index];
 }
 if (hi > 0 &&
     table[hi - 1].section_index == secndx &&
     addr - table[hi - 1].addr <= min_distance) {
  result = &elf->symtab_start[table[hi - 1].symbol_index];
 }
 return result;
}

Messung V0.5
C=75 H=92 G=83

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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 und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge