1#include <common.h>
2#include <debug.h>
3#include <libelf.h>
4#include <hash.h>
5#include <string.h>
6
7void setup_hash(Elf_Data *hash_data,
8                Elf32_Word nbuckets,
9                Elf32_Word nchains)
10{
11    hash_data->d_size  = 2;
12    hash_data->d_size += nbuckets;
13    hash_data->d_size += nchains;
14    hash_data->d_buf   = CALLOC(hash_data->d_size, sizeof(Elf32_Word));
15    hash_data->d_size *= sizeof(Elf32_Word);
16    ((Elf32_Word *)hash_data->d_buf)[0] = nbuckets;
17    ((Elf32_Word *)hash_data->d_buf)[1] = nchains;
18}
19
20void add_to_hash(Elf_Data *hash_data,
21                 const char *symbol,
22                 int symindex)
23{
24    Elf32_Word *buckets  = (Elf32_Word *)hash_data->d_buf;
25    Elf32_Word nbuckets  = *buckets++;
26    Elf32_Word *chains   = ++buckets + nbuckets;
27    Elf32_Word last_chain_index;
28    unsigned long bucket = elf_hash(symbol) % nbuckets;
29
30    ASSERT(symindex != STN_UNDEF);
31
32    if (buckets[bucket] == STN_UNDEF) {
33        INFO("Adding [%s] to hash at bucket [%ld] (first add)\n",
34             symbol, bucket);
35        buckets[bucket] = symindex;
36    }
37    else {
38        INFO("Collision on adding [%s] to hash at bucket [%ld]\n",
39             symbol, bucket);
40        last_chain_index = buckets[bucket];
41        while (chains[last_chain_index] != STN_UNDEF) {
42            INFO("\ttrying at chain index [%d]...\n", last_chain_index);
43            last_chain_index = chains[last_chain_index];
44        }
45        INFO("\tsuccess at chain index [%d]...\n", last_chain_index);
46        chains[last_chain_index] = symindex;
47    }
48}
49
50int hash_lookup(Elf *elf,
51                section_info_t *hash_info,
52                section_info_t *symtab_info,
53                const char *symname,
54                GElf_Sym *sym_mem)
55{
56    Elf32_Word *hash_data = (Elf32_Word *)hash_info->data->d_buf;
57    Elf32_Word index;
58    Elf32_Word nbuckets = *hash_data++;
59    Elf32_Word *buckets = ++hash_data;
60    Elf32_Word *chains  = hash_data + nbuckets;
61
62    GElf_Sym *sym;
63
64    index = buckets[elf_hash(symname) % nbuckets];
65    while(index != STN_UNDEF)
66    {
67        sym = gelf_getsymshndx (symtab_info->data, NULL, index, sym_mem, NULL);
68        FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
69        if (!strcmp(symname,
70                    elf_strptr(elf, symtab_info->hdr->sh_link, sym->st_name)))
71            break;
72        index = chains[index];
73    }
74
75    return index;
76}
77