00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #ifndef __MINGW32__
00039 #include <sys/mman.h>
00040 #endif
00041 #if defined(BUILD_OS_DARWIN)
00042 #include <darwin_elf.h>
00043 #else
00044 #include <elf.h>
00045 #endif
00046 #include <fcntl.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <ctype.h>
00050 #include <ar.h>
00051 #include <strings.h>
00052 #include "defs.h"
00053 #include "mempool.h"
00054
00055 struct archive_hash {
00056 struct archive_hash *next;
00057 char* name;
00058 INT offset;
00059 };
00060
00061 struct archive_hash_table {
00062 struct ar_hdr *str_table;
00063 struct archive_hash **hash_table;
00064 struct archive_hash *buckets;
00065 INT size;
00066
00067
00068 INT current_idx;
00069 INT last_idx;
00070 INT n_entries;
00071 };
00072
00073 #define ELF_AR_STRING_NAME "// "
00074
00075 static UINT32
00076 elfhash(char *pname)
00077 {
00078 register UINT32 h = 0;
00079 register char ch;
00080
00081 while (ch = *pname++) {
00082 register UINT32 g;
00083 h = (h << 4) + ch;
00084 if (g = (h & 0xF0000000)) {
00085 h ^= g >> 24;
00086 h &= ~g;
00087 }
00088 }
00089 return h;
00090 }
00091
00092 static UINT64
00093 round (UINT64 addr, UINT64 align)
00094 {
00095 if ((INT64) align-- <= 1)
00096 return addr;
00097
00098 return ((addr + align) & ~align);
00099 }
00100
00101
00102 #ifndef __GNUC__
00103 #pragma pack(1)
00104 struct unalign_word {
00105 UINT32 w;
00106 };
00107 struct unalign_longlong {
00108 UINT64 x;
00109 };
00110 #pragma pack(0)
00111 #else
00112 struct unalign_word {
00113 UINT32 w;
00114 } __attribute__ ((aligned (1), packed));
00115 struct unalign_longlong {
00116 UINT64 x;
00117 } __attribute__ ((aligned (1), packed));
00118 #endif
00119
00120 #ifndef _LIGHTWEIGHT_INLINER
00121 void *
00122 Digest_Archive (void* handle, MEM_POOL* m, INT64 file_size)
00123 {
00124 struct ar_hdr *symtab, *strtab;
00125 struct archive_hash_table *p;
00126 struct archive_hash *buckets;
00127 char *end_of_symtab, *end_of_strtab;
00128 BOOL ar64 = FALSE;
00129
00130 symtab = (struct ar_hdr *) ((char *)handle + SARMAG);
00131
00132 if (strncmp (symtab->ar_name, ELF_AR64_SYMTAB_NAME,
00133 ELF_AR64_SYMTAB_NAME_LEN) == 0) {
00134 ar64 = TRUE;
00135 }
00136 else if (strncmp (symtab->ar_name, ELF_AR_SYMTAB_NAME,
00137 ELF_AR_SYMTAB_NAME_LEN) ) {
00138 fprintf(stderr, "Expecting WHIRL archives...\n");
00139 return NULL;
00140 }
00141
00142 end_of_symtab = (char *)handle + SARMAG + sizeof(struct ar_hdr) +
00143 atol (symtab->ar_size);
00144
00145 p = (struct archive_hash_table *) MEM_POOL_Alloc (m, sizeof(struct archive_hash_table));
00146
00147
00148 INT* file_offset;
00149 file_offset = (INT*)((char *)handle + SARMAG + sizeof(struct ar_hdr));
00150
00151
00152
00153
00154
00155 INT n_entries;
00156 char *name;
00157 if (ar64) {
00158 n_entries = (INT) ((struct unalign_longlong *) file_offset)->x;
00159 file_offset = (INT*)((char *)file_offset + sizeof(unalign_longlong));
00160 name = (char *) ((char*)file_offset + n_entries*sizeof(unalign_longlong));
00161 }
00162 else {
00163 n_entries = *(INT*)file_offset;
00164 ++file_offset;
00165 name = (char *) (file_offset + n_entries);
00166 }
00167
00168
00169
00170
00171 for (p->size = 1; p->size < n_entries; p->size *= 2);
00172
00173 p->hash_table = (struct archive_hash **)
00174 MEM_POOL_Alloc (m, sizeof(struct archive_hash *) * p->size);
00175
00176 BZERO ((char *)p->hash_table, sizeof(struct archive_hash *) * p->size);
00177
00178 p->buckets = buckets = (struct archive_hash *)
00179 MEM_POOL_Alloc (m, sizeof(struct archive_hash) * n_entries);
00180
00181 p->n_entries = n_entries;
00182
00183 while (n_entries > 0) {
00184 UINT hash_value;
00185
00186 if (ar64)
00187 buckets->offset = ((struct unalign_longlong *) file_offset)->x;
00188 else
00189 buckets->offset = *(INT *)file_offset;
00190
00191 buckets->name = name;
00192 hash_value = elfhash (name) & (p->size - 1);
00193
00194 buckets->next = p->hash_table[hash_value];
00195 p->hash_table[hash_value] = buckets;
00196
00197 while (*name++ != 0);
00198 buckets++;
00199 if (ar64) {
00200 file_offset = (INT*)((char *)file_offset + sizeof(unalign_longlong));
00201 }
00202 else {
00203 ++file_offset;
00204 }
00205
00206 n_entries--;
00207 }
00208
00209 p->current_idx = 0;
00210 p->last_idx = -1;
00211
00212
00213 p->str_table = 0;
00214 if (end_of_symtab >= ((char *)handle + file_size))
00215 return p;
00216
00217 strtab = (struct ar_hdr *) end_of_symtab;
00218 if (strncmp (strtab->ar_name, ELF_AR_STRING_NAME, sizeof(strtab->ar_name)) == 0)
00219 p->str_table = strtab;
00220
00221 return p;
00222
00223 }
00224
00225 void
00226 Cleanup_Archive_Handle (void *handle, MEM_POOL* m)
00227 {
00228 struct archive_hash_table *p;
00229
00230 p = (struct archive_hash_table *) handle;
00231
00232 MEM_POOL_FREE (m, p->hash_table);
00233 MEM_POOL_FREE (m, p->buckets);
00234 MEM_POOL_FREE (m, p);
00235
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 off_t
00246 Defined_By_Archive (char *name, void* handle)
00247 {
00248 struct archive_hash_table *p;
00249 struct archive_hash *bucket;
00250
00251 p = (struct archive_hash_table *) handle;
00252 bucket = p->hash_table[elfhash (name) % p->size];
00253
00254 while (bucket) {
00255 if (strcmp (bucket->name, name) == 0)
00256 return bucket->offset;
00257 bucket = bucket->next;
00258 }
00259
00260 return 0;
00261
00262 }
00263 #endif
00264 char *
00265 Read_Member_Name (struct ar_hdr *header, void* handle, MEM_POOL* m)
00266 {
00267 struct archive_hash_table *p;
00268 char *name;
00269 INT len;
00270 char *buf;
00271
00272 p = (struct archive_hash_table *) handle;
00273
00274 if (header->ar_name[0] == '/') {
00275 int str_offset = atoi (header->ar_name + 1);
00276 if (p->str_table == 0)
00277 return const_cast<char *>("");
00278
00279 name = (char *) p->str_table + sizeof(struct ar_hdr) + str_offset;
00280 } else {
00281 name = header->ar_name;
00282 }
00283
00284 for (len = 1; name[len] != '/'; len++);
00285
00286 buf = (char *) MEM_POOL_Alloc (m, len+1);
00287 strncpy (buf, name, len);
00288 buf[len] = 0;
00289 return buf;
00290 }
00291
00292 off_t
00293 Next_Archive_Member (char* base, off_t offset, INT64 size)
00294 {
00295 struct ar_hdr *ar;
00296
00297 if (offset == 0) {
00298 offset = SARMAG;
00299 ar = (struct ar_hdr *) (base + offset);
00300 while (ar->ar_name[0] == '/' && !isdigit(ar->ar_name[1])) {
00301 offset += atol(ar->ar_size) + sizeof(struct ar_hdr);
00302 offset = (off_t)round (offset, 2);
00303 if (offset >= size)
00304 return 0;
00305 ar = (struct ar_hdr *) (base + offset);
00306 }
00307 } else {
00308 ar = (struct ar_hdr *) (base + offset);
00309 offset += atol(ar->ar_size) + sizeof(struct ar_hdr);
00310 offset = (off_t)round (offset, 2);
00311 if (offset >= size)
00312 return 0;
00313 }
00314 return offset;
00315 }
00316
00317