static int pre_dl(DECL_ARGS) { print_offs("6n", 0); return 1; }
static int pre_bl(DECL_ARGS) { size_t icol; /* * print_offs() will increase the -offset to account for * a possible enclosing .It, but any enclosed .It blocks * just nest and do not add up their indentation. */ if (n->norm->Bl.offs) { print_offs(n->norm->Bl.offs, 0); Bl_stack[Bl_stack_len++] = 0; } switch (n->norm->Bl.type) { case LIST_enum: n->norm->Bl.count = 0; return 1; case LIST_column: break; default: return 1; } if (n->child != NULL) { print_line(".TS", MMAN_nl); for (icol = 0; icol < n->norm->Bl.ncols; icol++) print_word("l"); print_word("."); } outflags |= MMAN_nl; return 1; }
static int pre_dl(DECL_ARGS) { print_offs("6n"); return(1); }
static int pre_bd(DECL_ARGS) { outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br); if (DISP_unfilled == n->norm->Bd.type || DISP_literal == n->norm->Bd.type) print_line(".nf", 0); if (0 == n->norm->Bd.comp && NULL != n->parent->prev) outflags |= MMAN_sp; print_offs(n->norm->Bd.offs, 1); return 1; }
int main(int argc, char **argv) { if ( argc < 2 ) { printf("fltdump.exe filename.flt [-f]\n -f = dump content of FLAT sections\n"); return 1; } if ( argc > 2 && argv[2][0]=='-' && argv[2][1]=='f' ) { FLAG_DUMP_FLAT=1;} char* filename_flt = argv[1]; int rv; if ( (rv=b_file_preload(filename_flt)) <= 0 ) { fprintf(stderr, "Error load file '%s': loaded %d\n",filename_flt,rv); return 1; } flat = (struct flat_hdr*) b_get_buf(); flat_buf = (unsigned char*)b_get_buf(); char magic[5]; // "CFLA" memcpy(magic,flat->magic,4); magic[4]=0; printf("\nFLT Headers:\n"); printf("->magic %s (flat rev.%d)\n", magic, flat->rev ); if ( memcmp(magic,FLAT_MAGIC_NUMBER,4) ) { printf("This is not CHDK-FLAT!\n"); return 1; } if ( flat->rev != FLAT_VERSION ) { printf("Bad FLAT revision! It is %d while should be %d\n", flat->rev, FLAT_VERSION); } int flat_reloc_count; flat_reloc_count = (flat->import_start-flat->reloc_start)/sizeof(uint32_t); int flat_import_count; flat_import_count = (flat->file_size-flat->import_start)/sizeof(uint32_t); printf("->entry(.text) 0x%x (size %d)\n", flat->entry, flat->data_start - flat->entry ); printf("->data_start 0x%x (size %d)\n", flat->data_start, flat->bss_start - flat->data_start ); printf("->bss_start 0x%x (size %d)\n", flat->bss_start, flat->reloc_start - flat->bss_start ); printf("->reloc_start 0x%x (size %d)\n", flat->reloc_start, flat->import_start - flat->reloc_start ); printf("->import_start 0x%x (size %d)\n", flat->import_start, flat->file_size - flat->import_start ); printf("\n"); if ( flat->rev == FLAT_VERSION ) { struct ModuleInfo* _module_info = (struct ModuleInfo*)(flat_buf + flat->_module_info_offset); if ( _module_info->magicnum != MODULEINFO_V1_MAGICNUM ) { printf("Malformed module info - bad magicnum!\n"); return 1; } if ( _module_info->sizeof_struct != sizeof(struct ModuleInfo) ) { printf("Malformed module info - bad sizeof!\n"); return 1; } printf("\nModule info:\n"); printf("->Module Name: %s\n", get_flat_string(_module_info->moduleName) ); printf("->Module Ver: %d.%d\n", _module_info->module_version.major, _module_info->module_version.minor ); char* branches_str[] = {"any branch","CHDK", "CHDK_DE", "CHDK_SDM", "PRIVATEBUILD"}; int branch = (_module_info->chdk_required_branch>REQUIRE_CHDK_PRIVATEBUILD) ? REQUIRE_CHDK_PRIVATEBUILD : _module_info->chdk_required_branch; printf("->Require: %s-build%d. ", branches_str[branch], _module_info->chdk_required_ver ); if ( _module_info->chdk_required_platfid == 0 ) printf("Any platform.\n"); else printf(" Platform #%d only.\n", _module_info->chdk_required_platfid ); printf("->Description: %s\n", get_flat_string(_module_info->description) ); print_offs("->lib = ", (int)_module_info->lib,"\n"); //print_offs("->_module_loader() = ", (int)_module_info->loader,"\n"); //print_offs("->_module_unloader() = ", (int)_module_info->unloader,"\n"); //print_offs("->_module_can_unload()= ", (int)_module_info->can_unload,"\n"); //print_offs("->_module_exit_alt() = ", (int)_module_info->exit_alt,"\n"); } if ( !FLAG_DUMP_FLAT ) return 0; dump_section( "FLT_header", flat_buf, sizeof(struct flat_hdr) ); dump_section( "FLT_text", flat_buf+flat->entry, flat->data_start-flat->entry ); dump_section( "FLT_data", flat_buf+flat->data_start, flat->bss_start-flat->data_start); dump_section( "FLT_bss", flat_buf+flat->bss_start, flat->reloc_start-flat->bss_start ); int i; printf("\nDump relocations 0x%x (size=%d):\n",flat->reloc_start,flat_reloc_count*sizeof(uint32_t)); for( i = 0; i< flat_reloc_count; i++) print_offs("Offs: ",*(int*)(flat_buf+flat->reloc_start+i*sizeof(uint32_t)),"\n"); printf("\nDump imports 0x%x (size=%d):\n",flat->import_start,flat_import_count*sizeof(uint32_t)); uint32_t *new_import_buf = (uint32_t*)(flat_buf+flat->import_start); for( i = 0; i< flat_import_count; i++) { uint32_t idx = new_import_buf[i++]; int cnt = new_import_buf[i] >> 24; int j; for (j=0; j<cnt; j++) { uint32_t offs = new_import_buf[i++] & 0x00FFFFFF; print_offs((j==0)?"Offs: ":" ",offs,""); int addend = *(uint32_t*)(flat_buf+offs); printf(" = sym_%08x[%s]+0x%x\n",idx,get_import_symbol(idx),addend); } } return 0; }
/*---------------------------------------------------------------------------*/ int elfloader_load(char* filename, char* fltfile) { struct elf32_ehdr ehdr; struct elf32_shdr shdr; struct elf32_shdr strtable; unsigned int strs; unsigned int shdrptr; unsigned int nameptr; char name[12]; int i; unsigned short shdrnum, shdrsize; int ret; /* Ensure that we have a correct and compatible ELF header. */ ret = b_seek_read( 0, (char *)&ehdr, sizeof(ehdr)); if (ret != sizeof(ehdr)) return ELFFLT_INPUT_ERROR; if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { PRINTERR(stderr, "ELF header problems\n"); return ELFFLT_BAD_ELF_HEADER; } if ( FLAG_VERBOSE ) printf ("Grab section header\n"); // Grab the section header. shdrptr = ehdr.e_shoff; ret = b_seek_read( shdrptr, (char *)&shdr, sizeof(shdr)); if (ret != sizeof(shdr)) return ELFFLT_INPUT_ERROR; shdrsize = ehdr.e_shentsize; shdrnum = ehdr.e_shnum; if ( FLAG_VERBOSE ) printf ("Grab string table section\n"); // Grab the string table section for the names of the sections. ret = b_seek_read( ehdr.e_shoff + shdrsize * ehdr.e_shstrndx, (char *)&strtable, sizeof(strtable)); if (ret != sizeof(strtable)) return ELFFLT_INPUT_ERROR; strs = strtable.sh_offset; /* Parse segments headers to releavant_section entries. .text = actual code from the ELF file .data = initialized data .rodata = contains read-only data .bss = segment holds the size of the unitialized data segment .rel.text, .rel.data = relocation information for the contents of the ".text" and ".data" segments, respectively. .symtab = symbol table for this file .strtab = points to the actual string names used by the symbol table. */ // Zero size is indicator of unitialized (not found) section text.size = text.relasize = data.size = data.relasize = rodata.size = rodata.relasize = symtabsize = strtabsize = 0; bss.number = data.number = rodata.number = text.number = -1; shdrptr = ehdr.e_shoff; for(i = 0; i < shdrnum; ++i) { ret = b_seek_read( shdrptr, (char *)&shdr, sizeof(shdr)); DEBUGPRINTF("==shdrptr=0x%x, sizeof=%d; size=0x%x\n",shdrptr,sizeof(shdr),shdrsize ); if (ret != sizeof(shdr)) { PRINTERR(stderr, "input error at %s:%d :loaded%d",__FILE__,__LINE__,ret);return ELFFLT_INPUT_ERROR;} /* The name of the section is contained in the strings table. */ nameptr = strs + shdr.sh_name; DEBUGPRINTF("==nameptr=%x(%x+%x), size=%d\n",nameptr,strs,shdr.sh_name,sizeof(name) ); ret = b_seek_read( nameptr, name, sizeof(name)); if (ret != sizeof(name)) {PRINTERR(stderr, "input error at %s:%d",__FILE__,__LINE__); return ELFFLT_INPUT_ERROR;} DEBUGPRINTF("==shdrptr=0x%x, sizeof=%d; size=0x%x\n",shdrptr,sizeof(shdr),shdrsize ); if ( FLAG_DUMP_SECTIONS ) printf ("Section #%d: %-15s [section header 0x%x, offset=0x%x, size %d, vma=0x%x]\n",i,name,shdrptr, shdr.sh_offset,shdr.sh_size, shdr.sh_addr); if(strncmp(name, ".text", 5) == 0) { text.number = i; text.offset = shdr.sh_offset; text.size = shdr.sh_size; text.base_addr = shdr.sh_addr; } else if(strncmp(name, ".rel.text", 9) == 0) { text.relaoff = shdr.sh_offset; text.relasize = shdr.sh_size; } else if(strncmp(name, ".data", 5) == 0) { data.number = i; data.offset = shdr.sh_offset; data.size = shdr.sh_size; data.base_addr = shdr.sh_addr; } else if(strncmp(name, ".rodata", 7) == 0) { rodata.number = i; rodata.offset = shdr.sh_offset; rodata.size = shdr.sh_size; rodata.base_addr = shdr.sh_addr; } else if(strncmp(name, ".rel.rodata", 11) == 0) { rodata.relaoff = shdr.sh_offset; rodata.relasize = shdr.sh_size; } else if(strncmp(name, ".rel.data", 9) == 0) { data.relaoff = shdr.sh_offset; data.relasize = shdr.sh_size; } else if(strncmp(name, ".rela.", 6) == 0) { PRINTERR(stderr,"RELA relocs are not supported."); return ELFFLT_INPUT_ERROR; } else if(strncmp(name, ".symtab", 7) == 0) { symtaboff = shdr.sh_offset; symtabsize = shdr.sh_size; } else if(strncmp(name, ".strtab", 7) == 0) { strtaboff = shdr.sh_offset; strtabsize = shdr.sh_size; } else if(strncmp(name, ".bss", 4) == 0) { bss.size = shdr.sh_size; bss.number = i; bss.offset = 0; } shdrptr += shdrsize; } if(symtabsize == 0) { PRINTERR(stderr,"No symbol table found."); return ELFFLT_NO_SYMTAB; } if(strtabsize == 0) { PRINTERR(stderr,"No strings table found."); return ELFFLT_NO_STRTAB; } if(text.size == 0) { PRINTERR(stderr, "No .text segment found."); return ELFFLT_NO_TEXT; } if ( (text.relasize + rodata.relasize+ data.relasize) <=0 ) { PRINTERR(stderr,"Found no reloc sections. Please link with -r -d options.\n"); return ELFFLT_UNHANDLED_RELOC; } if (bss.size) { bss.address = (char *)malloc(bss.size); if (!bss.address) return ELFFLT_OUTPUT_ERROR; } if (data.size) { data.address = (char *)malloc(data.size); if (!data.address) return ELFFLT_OUTPUT_ERROR; } if (text.size) { text.address = (char *)malloc(text.size); if (!text.address) return ELFFLT_OUTPUT_ERROR; } if (rodata.size) { rodata.address = (char *)malloc(rodata.size); if (!rodata.address) return ELFFLT_OUTPUT_ERROR; } rodata.name=".rodata"; bss.name=".bss"; text.name=".text"; data.name=".data"; b_seek_read(text.offset, text.address, text.size); b_seek_read(data.offset, data.address, data.size); b_seek_read(rodata.offset, rodata.address, rodata.size); if ( FLAG_DUMP_SOURCE ) { dump_section( text.name, (unsigned char *)text.address, text.size ); dump_section( data.name, (unsigned char *)data.address, data.size ); dump_section( rodata.name, (unsigned char *)rodata.address, rodata.size ); } if ( FLAG_DUMP_SYMBOLS ) { dump_symtable(); } if ( FLAG_DUMP_SYMBOLS || FLAG_DUMP_SOURCE || FLAG_VERBOSE ) printf("\n\n"); if ( FLAG_VERBOSE ) printf ("Prepare flat\n"); int div0hack_size = sizeof(div0_arm); int flatmainsize = sizeof(struct flat_hdr)+text.size+div0hack_size+data.size+rodata.size+bss.size; int flatrelocsize = text.relasize+rodata.relasize+data.relasize; // Take to account aligning to int32 each section flatmainsize += align4(text.size) + align4(data.size) + align4(rodata.size) + align4(bss.size); flat_buf=malloc( flatmainsize+flatrelocsize ); if ( !flat_buf) { PRINTERR(stderr, "fail to malloc flat buf\n"); return ELFFLT_OUTPUT_ERROR;} memset(flat_buf, 0, flatmainsize+flatrelocsize); //import is subset of full reloc list, so same count is enough // but apply multiplier to take into account difference between sizeofs flat_import_buf=malloc( flatrelocsize* sizeof(import_record_t)/sizeof(reloc_record_t) ); if ( !flat_import_buf) { PRINTERR(stderr, "fail to malloc flat import buf\n"); return ELFFLT_OUTPUT_ERROR;} memset(flat_import_buf, 0, flatrelocsize); // Fill flat with sections aligned to int32 flat = (struct flat_hdr*) flat_buf; if ( FLAG_VERBOSE ) printf(">>elf2flt: load segments\n"); int offset=sizeof(struct flat_hdr); text.flat_offset = offset; memcpy( flat_buf+offset, text.address, text.size ); DEBUGPRINTF("load .txt to %x (%x->%x)\n",offset,text.size,text.size+align4(text.size)); offset+=text.size+div0hack_size+align4(text.size); rodata.flat_offset = offset; DEBUGPRINTF("load .rodata to %x (%x->%x)\n",offset,rodata.size,rodata.size+align4(rodata.size)); memcpy( flat_buf+offset, rodata.address, rodata.size ); offset+=rodata.size+align4(rodata.size); data.flat_offset = offset; DEBUGPRINTF("load .data to %x (%x->%x)\n",offset,data.size,data.size+align4(data.size)); memcpy( flat_buf+offset, data.address, data.size ); offset+=data.size+align4(data.size); bss.flat_offset = offset; DEBUGPRINTF(".bss to %x (%x->%x)\n",offset,bss.size,bss.size+align4(bss.size)); DEBUGPRINTF("result=%x\n", flatmainsize); // Initialize flat headers memcpy(flat->magic, FLAT_MAGIC_NUMBER, sizeof(flat->magic)); // Set magic (CHDK_FLAT) flat->rev = FLAT_VERSION; flat->entry = text.flat_offset; flat->data_start = rodata.flat_offset; flat->bss_start = bss.flat_offset; flat->reloc_start = flatmainsize; flat_reloc_count = 0; flat->import_start = 0; flat_import_count = 0; flat_reloc = (reloc_record_t*)(flat_buf+flatmainsize); flat_reloc_cur = flat_reloc; flat_import_cur = flat_import_buf; // _div0_arm hack add_div0_arm(); flag_unsafe_sym = 0; // Do relocations ret = relocate_section( &text); if(ret != ELFFLT_OK) return ret; ret = relocate_section( &rodata); if(ret != ELFFLT_OK) return ret; ret = relocate_section( &data); if(ret != ELFFLT_OK) return ret; if ( flag_unsafe_sym ) return ELFFLT_UNSAFE_SYMBOL; flat->import_start = flat->reloc_start+flat_reloc_count*sizeof(reloc_record_t); // Init offsets to the entry symbols if ( FLAG_VERBOSE ) printf(">>elf2flt: lookup entry symbols\n"); flat->_module_info_offset = find_symbol_inflat("_module_info", &data ); if ( flat->_module_info_offset <=0 ) { PRINTERR(stderr, "No or invalid section of _module_info. This symbol should be initialized as ModuleInfo structure.\n"); return ELFFLT_NO_MODULEINFO; } struct ModuleInfo* _module_info = (struct ModuleInfo*) (flat_buf + flat->_module_info_offset); if ( _module_info->magicnum != MODULEINFO_V1_MAGICNUM ) { PRINTERR(stderr, "Wrong _module_info->magicnum value. Please check correct filling of this structure\n"); return ELFFLT_NO_MODULEINFO; } if ( _module_info->sizeof_struct != sizeof(struct ModuleInfo) ) { PRINTERR(stderr, "Wrong _module_info->sizeof_struct value. Please check correct filling of this structure\n"); return ELFFLT_NO_MODULEINFO; } // Group import relocations // Input = array of offset/index pairs - one for each address to be relocated to a core CHDK symbol // Output = list of entries of the form: // Index, Offset1 | (N<<24), Offset2, ..., OffsetN // where each offset is a reference to the same core CHDK symbol uint32_t *new_import_buf = malloc(flat_import_count*3*sizeof(uint32_t)); uint32_t new_import_cnt = 0; int process = 1; while (process) { process = 0; for (i=0; i<flat_import_count; i++) { if (flat_import_buf[i].offs != 0) { process = 1; int cnt = 0; uint32_t idx = flat_import_buf[i].importidx; new_import_buf[new_import_cnt++] = idx; int pcnt = new_import_cnt; int j; for (j=0; j<flat_import_count; j++) { if (flat_import_buf[j].importidx == idx) { new_import_buf[new_import_cnt++] = flat_import_buf[j].offs; flat_import_buf[j].offs = 0; cnt++; } } new_import_buf[pcnt] = (cnt << 24) | new_import_buf[pcnt]; } } } flat->file_size = flat->import_start+new_import_cnt*sizeof(uint32_t); if ( FLAG_DUMP_FLT_HEADERS ) { printf("\nFLT Headers:\n"); printf("->entry 0x%x (size %d)\n", flat->entry, flat->data_start - flat->entry ); printf("->data_start 0x%x (size %d)\n", flat->data_start, flat->bss_start - flat->data_start ); printf("->bss_start 0x%x (size %d)\n", flat->bss_start, flat->reloc_start - flat->bss_start ); printf("->reloc_start 0x%x (size %d)\n", flat->reloc_start, flat_reloc_count*sizeof(reloc_record_t) ); printf("->import_start 0x%x (size %d %d)\n", flat->import_start, flat->file_size-flat->import_start, flat_import_count*sizeof(import_record_t) ); printf("\n"); printf("\nModule info:\n"); printf("->Module Name: %s\n", get_flat_string(_module_info->moduleName) ); printf("->Module Ver: %d.%d\n", _module_info->module_version.major, _module_info->module_version.minor ); char* branches_str[] = {"any branch","CHDK", "CHDK_DE", "CHDK_SDM", "PRIVATEBUILD"}; int branch = (_module_info->chdk_required_branch>REQUIRE_CHDK_PRIVATEBUILD) ? REQUIRE_CHDK_PRIVATEBUILD : _module_info->chdk_required_branch; printf("->Require: %s-build%d. ", branches_str[branch], _module_info->chdk_required_ver ); if ( _module_info->chdk_required_platfid == 0 ) printf("Any platform.\n"); else printf(" Platform #%d only.\n", _module_info->chdk_required_platfid ); printf("->Description: %s\n", get_flat_string(_module_info->description) ); print_offs("->lib = ", (int)_module_info->lib,"\n"); //print_offs("->_module_loader() = ", (int)_module_info->loader,"\n"); //print_offs("->_module_unloader() = ", (int)_module_info->unloader,"\n"); //print_offs("->_module_can_unload()= ", (int)_module_info->can_unload,"\n"); //print_offs("->_module_exit_alt() = ", (int)_module_info->exit_alt,"\n"); } if ( FLAG_DUMP_FLAT ) { dump_section( "FLT_header", (unsigned char*)flat_buf, sizeof(struct flat_hdr) ); dump_section( "FLT_text", (unsigned char*)flat_buf+flat->entry, flat->data_start-flat->entry ); dump_section( "FLT_data", (unsigned char*)flat_buf+flat->data_start, flat->bss_start-flat->data_start); dump_section( "FLT_bss", (unsigned char*)flat_buf+flat->bss_start, flat->reloc_start-flat->bss_start ); printf("\nDump relocations 0x%x (size=%d):\n",flat->reloc_start,flat_reloc_count*sizeof(reloc_record_t)); for( i = 0; i< flat_reloc_count; i++) { print_offs("Offs: ",*(int*)(flat_buf+flat->reloc_start+i*sizeof(reloc_record_t)), "\n"); } printf("\nDump imports 0x%x (size=%d):\n",flat->import_start,new_import_cnt*sizeof(uint32_t)); for (i = 0; i< new_import_cnt;) { uint32_t idx = new_import_buf[i++]; int cnt = new_import_buf[i] >> 24; int j; for (j=0; j<cnt; j++) { uint32_t offs = new_import_buf[i++] & 0x00FFFFFF; print_offs((j==0)?"Offs: ":" ",offs,""); int addend = *(uint32_t*)(flat_buf+offs); printf(" = sym_%08x[%s]+0x%x\n",idx,get_import_symbol(idx),addend); } } } int filesize = flat->file_size; printf("\n\nOutput file %s (size=%d bytes)\n",fltfile,filesize); int output_fd = open(fltfile,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0777); i = write(output_fd, flat_buf, flat->import_start); i = write(output_fd, new_import_buf, new_import_cnt*sizeof(uint32_t)); close(output_fd); return ELFFLT_OK; }