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
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #include "xlateincl.h"
00050
00051 #ifdef _LIBELF_XTND_EXPANDED_DATA
00052 #pragma weak xlate_named_init_elf_xtnd = _xlate_named_init_elf_xtnd
00053 #pragma weak xlate_finish_xtnd = _xlate_finish_xtnd
00054 #elif defined(BUILD_OS_DARWIN)
00055 #else
00056 #pragma weak xlate_named_init_elf = _xlate_named_init_elf
00057 #pragma weak xlate_finish = _xlate_finish
00058 #endif
00059
00060 #define streq(a,b) (strcmp(a,b) == 0)
00061 static int
00062 _xlate_initialize_v1_table(xlate_table_con tab,int is64bit)
00063 {
00064 xlate_header_v1 *lclhdrp;
00065 char * end_addr;
00066 Uword len;
00067
00068 if(tab->xc_data_size < sizeof(xlate_header_v1)) {
00069 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00070 }
00071 tab->xc_block_headers =
00072 (char *)tab->xc_section_data + sizeof(xlate_header_v1);
00073 lclhdrp = (xlate_header_v1*)tab->xc_section_data;
00074
00075 tab->xc_hdr.ich_version = (int)lclhdrp->hd_version;
00076 tab->xc_hdr.ich_tablekind = (unsigned char)lclhdrp->hd_tablekind;
00077 if(is64bit != lclhdrp->hd_is64_bit) {
00078 return XLATE_TB_STATUS_INCONSISTENT_64_BIT_INFO;
00079 }
00080 tab->xc_hdr.ich_block_size = lclhdrp->hd_block_size;
00081 tab->xc_hdr.ich_num_blocks = lclhdrp->hd_num_blocks;
00082 tab->xc_hdr.ich_total_num_entries = lclhdrp->hd_num_entries;
00083 tab->xc_hdr.ich_total_reginfo_bytes = lclhdrp->hd_reg_info_size;
00084 tab->xc_hdr.ich_new_addr_low = lclhdrp->hd_new_addr_low;
00085 tab->xc_hdr.ich_new_addr_high = lclhdrp->hd_new_addr_high;
00086 tab->xc_hdr.ich_old_addr_low = lclhdrp->hd_old_addr_low;
00087 tab->xc_hdr.ich_old_addr_high = lclhdrp->hd_old_addr_high;
00088 tab->xc_ubh_array = calloc(sizeof(uniform_block_hdr),
00089 tab->xc_hdr.ich_num_blocks);
00090 if(tab->xc_ubh_array == 0) {
00091 return XLATE_TB_STATUS_ALLOC_FAIL;
00092 }
00093 if(tab->xc_is64bit) {
00094 tab->xc_hdr.ich_new_addr_low |=
00095 ((Elf64_Addr)lclhdrp->hd_upper32_bits_new) <<32;
00096 tab->xc_hdr.ich_new_addr_high |=
00097 ((Elf64_Addr)lclhdrp->hd_upper32_bits_new) <<32;
00098 tab->xc_hdr.ich_old_addr_low |=
00099 ((Elf64_Addr)lclhdrp->hd_upper32_bits_old) <<32;
00100 tab->xc_hdr.ich_old_addr_high |=
00101 ((Elf64_Addr)lclhdrp->hd_upper32_bits_old) <<32;
00102 }
00103 tab->xc_leb_data_blocks = tab->xc_block_headers +
00104 (Uword)(tab->xc_hdr.ich_num_blocks*sizeof(xlate_blockheader_v1));
00105 end_addr = tab->xc_leb_data_blocks +
00106 (Uword)(tab->xc_hdr.ich_num_blocks*tab->xc_hdr.ich_block_size);
00107 tab->xc_reginfo_data = end_addr;
00108
00109 end_addr += tab->xc_hdr.ich_total_reginfo_bytes;
00110
00111 len = end_addr - tab->xc_section_data;
00112 if(len > tab->xc_data_size) {
00113 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00114 }
00115
00116 tab->xc_get_info_func = _xlate_get_infov1;
00117 tab->xc_search_for_addr_new = _xlate_binary_search_for_addr;
00118 switch(tab->xc_hdr.ich_tablekind) {
00119 case xlate_tk_general:
00120 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00121 tab->xc_get_range_from_block = _xlate_get_range_from_block_v1_ge;
00122 break;
00123 case xlate_tk_preserve_size:
00124 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00125 tab->xc_get_range_from_block = _xlate_get_range_from_block_v1_ps;
00126 break;
00127 case xlate_tk_preserve_order:
00128 tab->xc_search_for_addr_old = _xlate_binary_search_for_addr;
00129
00130 tab->xc_get_range_from_block = _xlate_get_range_from_block_v1_po;
00131
00132 break;
00133 default:
00134 return XLATE_TB_STATUS_BAD_TABLEKIND;
00135 }
00136 tab->xc_block_header_indexer = _xlate_index_into_blockhdrs_v1;
00137
00138 return XLATE_TB_STATUS_NO_ERROR;
00139 }
00140 static int
00141 _xlate_initialize_32_v2_table(xlate_table_con tab)
00142 {
00143
00144 char * end_addr;
00145 Uword len;
00146
00147 xlate_header32_v2* lclhdrp;
00148
00149 if(tab->xc_data_size < sizeof(xlate_header32_v2)) {
00150 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00151 }
00152 lclhdrp = (xlate_header32_v2*)tab->xc_section_data;
00153 tab->xc_block_headers = tab->xc_section_data + sizeof(xlate_header32_v2);
00154
00155 tab->xc_hdr.ich_version = (int)lclhdrp->hd_version;
00156 tab->xc_hdr.ich_tablekind = lclhdrp->hd_tablekind;
00157 tab->xc_hdr.ich_block_size = lclhdrp->hd_block_size;
00158 tab->xc_hdr.ich_num_blocks = lclhdrp->hd_num_blocks;
00159 tab->xc_hdr.ich_total_num_entries = lclhdrp->hd_num_entries;
00160 tab->xc_hdr.ich_total_reginfo_bytes = lclhdrp->hd_reg_info_size;
00161 tab->xc_hdr.ich_new_addr_low = lclhdrp->hd_new_addr_low;
00162 tab->xc_hdr.ich_new_addr_high = lclhdrp->hd_new_addr_high;
00163 tab->xc_hdr.ich_old_addr_low = lclhdrp->hd_old_addr_low;
00164 tab->xc_hdr.ich_old_addr_high = lclhdrp->hd_old_addr_high;
00165 tab->xc_leb_data_blocks = tab->xc_block_headers +
00166 (Uword)(tab->xc_hdr.ich_num_blocks*sizeof(xlate_blockheader32_v2));
00167 end_addr = tab->xc_leb_data_blocks +
00168 (Uword)(tab->xc_hdr.ich_num_blocks*tab->xc_hdr.ich_block_size);
00169 tab->xc_reginfo_data = end_addr;
00170 tab->xc_ubh_array = calloc(sizeof(uniform_block_hdr),
00171 tab->xc_hdr.ich_num_blocks);
00172 if(tab->xc_ubh_array == 0) {
00173 return XLATE_TB_STATUS_ALLOC_FAIL;
00174 }
00175
00176
00177 end_addr += tab->xc_hdr.ich_total_reginfo_bytes;
00178
00179 len = end_addr - tab->xc_section_data;
00180 if(len > tab->xc_data_size) {
00181 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00182 }
00183
00184 tab->xc_get_info_func = _xlate_get_infov2_32;
00185
00186 tab->xc_search_for_addr_new = _xlate_binary_search_for_addr;
00187 switch(tab->xc_hdr.ich_tablekind) {
00188 case xlate_tk_general:
00189 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00190 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_32_ge;
00191 break;
00192 case xlate_tk_preserve_size:
00193 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00194 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_32_ps;
00195 break;
00196 case xlate_tk_preserve_order:
00197 tab->xc_search_for_addr_old = _xlate_binary_search_for_addr;
00198 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_32_po;
00199 break;
00200 default:
00201 return XLATE_TB_STATUS_BAD_TABLEKIND;
00202 }
00203 tab->xc_block_header_indexer = _xlate_index_into_blockhdrs_v2_32;
00204
00205
00206 return XLATE_TB_STATUS_NO_ERROR;
00207 }
00208 static int
00209 _xlate_initialize_64_v2_table(xlate_table_con tab)
00210 {
00211 xlate_header64_v2 *lclhdrp;
00212 char * end_addr;
00213 Uword len;
00214
00215 if(tab->xc_data_size < sizeof(xlate_header64_v2)) {
00216 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00217 }
00218 tab->xc_block_headers = (char *)(tab->xc_section_data) +
00219 sizeof(xlate_header64_v2);
00220 lclhdrp = (xlate_header64_v2*)tab->xc_section_data;
00221
00222 tab->xc_hdr.ich_version = (int)lclhdrp->hd_version;
00223 tab->xc_hdr.ich_tablekind = lclhdrp->hd_tablekind;
00224 tab->xc_hdr.ich_block_size = lclhdrp->hd_block_size;
00225 tab->xc_hdr.ich_num_blocks = lclhdrp->hd_num_blocks;
00226 tab->xc_hdr.ich_total_num_entries = lclhdrp->hd_num_entries;
00227 tab->xc_hdr.ich_total_reginfo_bytes = lclhdrp->hd_reg_info_size;
00228 tab->xc_hdr.ich_new_addr_low = lclhdrp->hd_new_addr_low;
00229 tab->xc_hdr.ich_new_addr_high = lclhdrp->hd_new_addr_high;
00230 tab->xc_hdr.ich_old_addr_low = lclhdrp->hd_old_addr_low;
00231 tab->xc_hdr.ich_old_addr_high = lclhdrp->hd_old_addr_high;
00232 tab->xc_leb_data_blocks = tab->xc_block_headers +
00233 (Uword)(tab->xc_hdr.ich_num_blocks*sizeof(xlate_blockheader64_v2));
00234 end_addr = tab->xc_leb_data_blocks +
00235 (Uword)(tab->xc_hdr.ich_num_blocks*tab->xc_hdr.ich_block_size);
00236 tab->xc_reginfo_data = end_addr;
00237
00238 tab->xc_ubh_array = calloc(sizeof(uniform_block_hdr),
00239 tab->xc_hdr.ich_num_blocks);
00240 if(tab->xc_ubh_array == 0) {
00241 return XLATE_TB_STATUS_ALLOC_FAIL;
00242 }
00243
00244 end_addr += tab->xc_hdr.ich_total_reginfo_bytes;
00245
00246 len = end_addr - tab->xc_section_data;
00247 if(len > tab->xc_data_size) {
00248 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00249 }
00250
00251 tab->xc_get_info_func = _xlate_get_infov2_64;
00252 tab->xc_search_for_addr_new = _xlate_binary_search_for_addr;
00253 switch(tab->xc_hdr.ich_tablekind) {
00254 case xlate_tk_general:
00255 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00256 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_64_ge;
00257 break;
00258 case xlate_tk_preserve_size:
00259 tab->xc_search_for_addr_old = _xlate_special_search_for_addr;
00260 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_64_ps;
00261 break;
00262 case xlate_tk_preserve_order:
00263 tab->xc_search_for_addr_old = _xlate_binary_search_for_addr;
00264 tab->xc_get_range_from_block = _xlate_get_range_from_block_v2_64_po;
00265 break;
00266 default:
00267 return XLATE_TB_STATUS_BAD_TABLEKIND;
00268 }
00269 tab->xc_block_header_indexer = _xlate_index_into_blockhdrs_v2_64;
00270
00271
00272 return XLATE_TB_STATUS_NO_ERROR;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 static int
00287 _xlate_fill_in_table_data(xlate_table_con tab,int is64bit)
00288 {
00289 int retstatus = XLATE_TB_STATUS_NO_ERROR;
00290
00291 xlate_header32_v2 tabhdr;
00292
00293 if(tab->xc_data_size < sizeof(Elf32_Word)) {
00294 return XLATE_TB_STATUS_SECTION_TOO_SMALL;
00295 }
00296 memcpy(&tabhdr,tab->xc_section_data,sizeof(Elf32_Word));
00297
00298 tab->xc_is64bit = is64bit;
00299
00300 switch(tabhdr.hd_version) {
00301 case XLATE_TB_COPY_V1:
00302 case XLATE_TB_DEBUG_V1:
00303 case XLATE_TB_OLD_V1 :
00304 default:
00305 return XLATE_TB_STATUS_BAD_TABLEKIND;
00306
00307 case XLATE_TB_MAIN_V1:
00308 retstatus = _xlate_initialize_v1_table(tab,is64bit);
00309 break;
00310 case XLATE_TB_32_V2:
00311 if(is64bit) {
00312 return XLATE_TB_STATUS_INCONSISTENT_64_BIT_INFO;
00313 }
00314 retstatus = _xlate_initialize_32_v2_table(tab);
00315 break;
00316 case XLATE_TB_64_V2:
00317 if(!is64bit) {
00318 return XLATE_TB_STATUS_INCONSISTENT_64_BIT_INFO;
00319 }
00320 retstatus = _xlate_initialize_64_v2_table(tab);
00321 break;
00322 }
00323
00324
00325
00326
00327 return retstatus;
00328 }
00329
00330
00331
00332 int
00333 xlate_named_init_elf(Elf * elf, const char *section_name,
00334 xlate_table_con * ret_tab_ptr)
00335 {
00336 int retstatus = XLATE_TB_STATUS_NO_ERROR;
00337 xlate_table_con newtab = 0;
00338 Elf_Scn *scn = 0;
00339 int is64bit = 0;
00340 char *ident;
00341 size_t identsize;
00342 Elf_Scn *xlscn = 0;
00343 Elf64_Shdr *shdr64 = 0;
00344 Elf32_Shdr *shdr32 = 0;
00345 Elf32_Ehdr *ehdr32 = 0;
00346 Elf64_Ehdr *ehdr64 = 0;
00347 Elf_Data *xlatedata = 0;
00348 int stringindex = 0;
00349 char * sec_name;
00350
00351 if(elf_kind(elf) != ELF_K_ELF) {
00352 return XLATE_TB_STATUS_NOT_ELF;
00353 }
00354 ident = elf_getident(elf,&identsize);
00355
00356 if(ident == 0 || identsize < EI_NIDENT) {
00357 return XLATE_TB_STATUS_ELF_IDENT_BAD;
00358 }
00359 if(ident[EI_CLASS] == ELFCLASS64) {
00360 is64bit = 1;
00361 }
00362 if(is64bit) {
00363 ehdr64 = elf64_getehdr(elf);
00364 if(ehdr64 == 0 ) {
00365 return XLATE_TB_STATUS_ELF_EHDR_BAD;
00366 }
00367 stringindex = ehdr64->e_shstrndx;
00368 } else {
00369 ehdr32 = elf32_getehdr(elf);
00370 if(ehdr32 == 0 ) {
00371 return XLATE_TB_STATUS_ELF_EHDR_BAD;
00372 }
00373 stringindex = ehdr32->e_shstrndx;
00374 }
00375
00376 for(scn = elf_nextscn(elf,scn);
00377 scn != 0 && xlscn == 0
00378 ; scn = elf_nextscn(elf,scn)) {
00379 if(is64bit) {
00380 shdr64 = elf64_getshdr(scn);
00381 if(shdr64 == 0) {
00382 return XLATE_TB_STATUS_ELF_SHDR_BAD;
00383 }
00384 sec_name = elf_strptr(elf,stringindex,shdr64->sh_name);
00385 if(sec_name == 0) {
00386 return XLATE_TB_STATUS_ELF_STRPTR_BAD;
00387 }
00388 if(shdr64->sh_type != SHT_MIPS_XLATE &&
00389 shdr64->sh_type != SHT_MIPS_XLATE_DEBUG &&
00390 shdr64->sh_type != SHT_MIPS_XLATE_OLD ) {
00391 continue;
00392 }
00393 if(!streq(section_name,sec_name)) {
00394 continue;
00395 }
00396 xlscn = scn;
00397 break;
00398 } else {
00399 shdr32 = elf32_getshdr(scn);
00400 if(shdr32 == 0) {
00401 return XLATE_TB_STATUS_ELF_SHDR_BAD;
00402 }
00403 sec_name = elf_strptr(elf,stringindex,shdr32->sh_name);
00404 if(sec_name == 0) {
00405 return XLATE_TB_STATUS_ELF_STRPTR_BAD;
00406 }
00407 if(shdr32->sh_type != SHT_MIPS_XLATE &&
00408 shdr32->sh_type != SHT_MIPS_XLATE_DEBUG &&
00409 shdr32->sh_type != SHT_MIPS_XLATE_OLD ) {
00410 continue;
00411 }
00412 if(!streq(section_name,sec_name)) {
00413 continue;
00414 }
00415 xlscn = scn;
00416 break;
00417 }
00418 }
00419 if(xlscn == 0) {
00420 return XLATE_TB_STATUS_NO_XLATE;
00421 }
00422
00423 xlatedata = elf_getdata(xlscn,NULL);
00424 if(xlatedata == NULL || xlatedata->d_size == 0) {
00425 return XLATE_TB_STATUS_NO_XLATE_DATA;
00426 }
00427
00428 newtab = (xlate_table_con)malloc(sizeof(struct xlate_table_con_s));
00429 if(newtab == NULL) {
00430 return XLATE_TB_STATUS_ALLOC_FAIL;
00431 }
00432 BZERO(newtab,sizeof(struct xlate_table_con_s));
00433
00434
00435 newtab->xc_elf = elf;
00436
00437
00438 newtab->xc_section_data = xlatedata->d_buf;
00439 newtab->xc_data_size = xlatedata->d_size;
00440 if(newtab->xc_data_size != xlatedata->d_size) {
00441
00442
00443
00444
00445
00446 free(newtab);
00447 return XLATE_TB_STATUS_SECTION_TOO_BIG;
00448 }
00449
00450 retstatus = _xlate_fill_in_table_data(newtab,is64bit);
00451 if(retstatus != XLATE_TB_STATUS_NO_ERROR) {
00452 free(newtab);
00453 return retstatus;
00454 }
00455
00456 newtab->xc_valid_table = VALID_TABLE_MAGIC;
00457 *ret_tab_ptr = newtab;
00458 return retstatus;
00459 }
00460
00461 int
00462 xlate_finish(xlate_table_con tab)
00463 {
00464 int retstatus = XLATE_TB_STATUS_NO_ERROR;
00465
00466 if(!tab) {
00467 return XLATE_TB_STATUS_NULL_TABLE;
00468 }
00469 if(tab->xc_valid_table != VALID_TABLE_MAGIC) {
00470 return XLATE_TB_STATUS_INVALID_TABLE;
00471 }
00472
00473 if(tab->xc_ubh_array) {
00474 unsigned long l;
00475 uniform_block_hdr *ubhp = tab->xc_ubh_array;
00476
00477 for(l = 0; l < tab->xc_hdr.ich_num_blocks; ++l,++ubhp) {
00478 if(ubhp->ub_expanded_entries) {
00479 free(ubhp->ub_expanded_entries);
00480 ubhp->ub_expanded_entries = 0;
00481 }
00482 }
00483 free(tab->xc_ubh_array);
00484 tab->xc_ubh_array = 0;
00485 }
00486 if(tab->xc_did_elf_begin ) {
00487 elf_end(tab->xc_elf);
00488 }
00489 BZERO(tab,sizeof(*tab));
00490 free(tab);
00491 return retstatus;
00492 }