diff options
Diffstat (limited to '')
| -rw-r--r-- | project/dclib/lib-dol.c | 1208 |
1 files changed, 1208 insertions, 0 deletions
diff --git a/project/dclib/lib-dol.c b/project/dclib/lib-dol.c new file mode 100644 index 0000000..00d6972 --- /dev/null +++ b/project/dclib/lib-dol.c @@ -0,0 +1,1208 @@ + +/*************************************************************************** + * * + * _____ ____ * + * | __ \ / __ \ _ _ _____ * + * | | \ \ / / \_\ | | | | _ \ * + * | | \ \| | | | | | |_| | * + * | | | || | | | | | ___/ * + * | | / /| | __ | | | | _ \ * + * | |__/ / \ \__/ / | |___| | |_| | * + * |_____/ \____/ |_____|_|_____/ * + * * + * Wiimms source code library * + * * + *************************************************************************** + * * + * Copyright (c) 2012-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#define _GNU_SOURCE 1 +#include "lib-dol.h" + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// dol header /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void ntoh_dol_header ( dol_header_t * dest, const dol_header_t * src ) +{ + DASSERT(dest); + + if (!src) + src = dest; + else if ( dest != src ) + memcpy(dest,src,sizeof(*dest)); + + const u32 * src_ptr = src->sect_off; + u32 * dest_ptr = dest->sect_off; + u32 * dest_end = (u32*)&dest->padding; + + while ( dest_ptr < dest_end ) + *dest_ptr++ = ntohl(*src_ptr++); +} + +/////////////////////////////////////////////////////////////////////////////// + +void hton_dol_header ( dol_header_t * dest, const dol_header_t * src ) +{ + DASSERT(dest); + + if (!src) + src = dest; + else if ( dest != src ) + memcpy(dest,src,sizeof(*dest)); + + const u32 * src_ptr = src->sect_off; + u32 * dest_ptr = dest->sect_off; + u32 * dest_end = (u32*)&dest->padding; + + while ( dest_ptr < dest_end ) + *dest_ptr++ = htonl(*src_ptr++); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool IsDolHeader ( const void *data, uint data_size, uint file_size ) +{ + if ( data_size < DOL_HEADER_SIZE ) + return false; + + const dol_header_t *dol = data; + u64 total_size = 0; + + uint i; + for ( i = 0; i < DOL_N_SECTIONS; i++ ) + { + const u32 off = ntohl(dol->sect_off[i]); + const u32 size = ntohl(dol->sect_size[i]); + const u32 addr = ntohl(dol->sect_addr[i]); + noPRINT("DOL: %8x %8x %08x\n",off,size,addr); + if ( off || size || addr ) + { + if ( off & 3 + || size & 3 + || addr & 3 + || off < DOL_HEADER_SIZE + || file_size && off + size > file_size ) + { + return false; + } + total_size += size; + } + } + + return total_size && total_size < 0x7fffffff; +} + +/////////////////////////////////////////////////////////////////////////////// + +const char dol_section_name[DOL_NN_SECTIONS+1][4] = +{ + "T0", + "T1", + "T2", + "T3", + "T4", + "T5", + "T6", + + "D0", + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "D10", + + "BSS", + "ENT", + + "" +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// advanced interface /////////////// +/////////////////////////////////////////////////////////////////////////////// + +bool GetDolSectionInfo +( + dol_sect_info_t * info, // valid pointer: returned data + const dol_header_t *dol_head, // valid DOL header + uint file_size, // (file) size of 'data' + uint section // 0 .. DOL_NN_SECTIONS + // (7*TEXT, 11*DATA, BSS, ENTRY ) +) +{ + DASSERT(dol_head); + DASSERT(info); + memset(info,0,sizeof(*info)); + + if ( !dol_head || file_size < sizeof(dol_header_t) || section >= DOL_NN_SECTIONS ) + { + info->section = -1; + return false; + } + + info->section = section; + StringCopyS(info->name,sizeof(info->name),GetDolSectionName(section)); + + if ( section < DOL_N_SECTIONS ) + { + const u32 size = be32(&dol_head->sect_size[section]); + if (size) + { + info->sect_valid = true; + info->size = size; + const u32 off = info->off = be32(&dol_head->sect_off [section]); + info->addr = be32(&dol_head->sect_addr[section]); + + if ( off < file_size && size < file_size && off+size <= file_size ) + { + info->data_valid = true; + info->data = (u8*)dol_head + off; + } + } + return true; + } + + if ( section == DOL_IDX_BSS ) + { + info->sect_valid = true; + info->addr = be32(&dol_head->bss_addr); + info->size = be32(&dol_head->bss_size); + return true; + } + + if ( section == DOL_IDX_ENTRY ) + { + info->sect_valid = true; + info->addr = be32(&dol_head->entry_addr); + return true; + } + + ASSERT(0); + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FindFirstFreeDolSection +( + // returns TRUE on found + + dol_sect_info_t *info, // result + const dol_header_t *dh, // DOL header to analyse + uint mode // 0: search all sections (TEXT first) + // 1: search only TEXT sections + // 2: search only DATA sections + // 3: search all sections (DATA first) +) +{ + DASSERT(info); + DASSERT(dh); + + memset(info,0,sizeof(*info)); + + uint idx, end; + switch (mode) + { + case 0: + idx = 0; + end = DOL_N_SECTIONS; + break; + + case 3: + if (FindFirstFreeDolSection(info,dh,2)) + return true; + // fall through + + case 1: + idx = 0; + end = DOL_N_TEXT_SECTIONS; + break; + + case 2: + idx = DOL_N_TEXT_SECTIONS; + end = DOL_N_SECTIONS; + break; + + default: + idx = 0; + end = 0; + break; + } + + while ( idx < end && ntohl(dh->sect_size[idx]) ) + idx++; + + if ( idx >= end ) + { + info->section = -1; + return false; + } + + info->section = idx; + StringCopyS(info->name,sizeof(info->name),GetDolSectionName(idx)); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FindDolSectionBySelector +( + // returns TRUE on found + + dol_sect_info_t *info, // result + const dol_header_t *dh, // DOL header to analyse + const dol_sect_select_t *dss // DOL section selector +) +{ + DASSERT(info); + DASSERT(dh); + DASSERT(dss); + + if ( dss->sect_idx >= 0 ) + { + memset(info,0,sizeof(*info)); + info->section = dss->sect_idx; + memcpy(info->name,dss->name,sizeof(info->name)); + return true; + } + + return FindFirstFreeDolSection(info,dh,dss->find_mode); +} + +/////////////////////////////////////////////////////////////////////////////// + +u32 FindFreeSpaceDOL +( + // return address or NULL on not-found + + const dol_header_t *dol_head, // valid DOL header + u32 addr_beg, // first possible address + u32 addr_end, // last possible address + u32 size, // minimal size + u32 align, // aligning + u32 *space // not NULL: store available space here +) +{ + DASSERT(dol_head); + + MemMap_t mm; + InitializeMemMap(&mm); + + int i; + for ( i = 0; i < DOL_N_SECTIONS; i++ ) + { + const u32 size = ntohl(dol_head->sect_size[i]); + if (size) + { + const u32 addr = ntohl(dol_head->sect_addr[i]); + if ( addr < addr_end && addr + size > addr_beg ) + { + MemMapItem_t * mi = InsertMemMap(&mm,addr,size); + if (mi) + { + if ( i < DOL_N_TEXT_SECTIONS ) + snprintf(mi->info,sizeof(mi->info),"T%u",i); + else + snprintf(mi->info,sizeof(mi->info),"D%u", + i - DOL_N_TEXT_SECTIONS); + } + } + } + } + //PrintMemMap(&mm,stdout,3,"section"); + + u64 res_space; + const u32 res = FindFreeSpaceMemMap(&mm,addr_beg,addr_end,size,align,&res_space); + ResetMemMap(&mm); + if (space) + *space = res_space; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +u32 FindFreeBssSpaceDOL +( + // return address or NULL on not-found + + const dol_header_t *dol_head, // valid DOL header + u32 size, // min size + u32 align, // aligning + u32 *space // not NULL: store available space here +) +{ + DASSERT(dol_head); + const u32 bss_addr = ntohl(dol_head->bss_addr); + const u32 bss_size = ntohl(dol_head->bss_size); + if ( !bss_addr || !bss_size ) + { + if (space) + *space = 0; + return 0; + } + + return FindFreeSpaceDOL(dol_head,bss_addr,bss_addr+bss_size,size,align,space); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void DumpDolHeader +( + FILE * f, // dump to this file + int indent, // indention + const dol_header_t *dol_head, // valid DOL header + uint file_size, // NULL or size of file + uint print_mode // bit field: + // 1: print file map + // 2: print virtual mem map + // 4: print delta table +) +{ + DASSERT(f); + DASSERT(dol_head); + + indent = NormalizeIndent(indent); + + dol_header_t dol; + ntoh_dol_header(&dol,dol_head); + + MemMap_t mm1, mm2, mm3; + InitializeMemMap(&mm1); + InitializeMemMap(&mm2); + InitializeMemMap(&mm3); + MemMapItem_t * mi = InsertMemMap(&mm1,0,sizeof(dol_header_t)); + StringCopyS(mi->info,sizeof(mi->info),"DOL header"); + if (file_size) + { + mi = InsertMemMap(&mm1,file_size,0); + StringCopyS(mi->info,sizeof(mi->info),"--- end of file ---"); + } + + int i; + for ( i = 0; i < DOL_N_SECTIONS; i++ ) + { + const u32 size = dol.sect_size[i]; + if (size) + { + const u32 off = dol.sect_off[i]; + const u32 addr = dol.sect_addr[i]; + + char buf[sizeof(mi->info)], buf3[sizeof(mi->info)]; + if ( i < DOL_N_TEXT_SECTIONS ) + { + snprintf(buf,sizeof(buf),"text section T%u",i); + snprintf(buf3,sizeof(buf3),"%8x : T%u",addr-off,i); + } + else + { + const int j = i - DOL_N_TEXT_SECTIONS; + snprintf(buf,sizeof(buf),"data section D%u",j); + snprintf(buf3,sizeof(buf3),"%8x : D%u",addr-off,j); + } + + mi = InsertMemMap(&mm1,off,size); + strcpy(mi->info,buf); + mi = InsertMemMap(&mm2,addr,size); + strcpy(mi->info,buf); + mi = InsertMemMap(&mm3,addr,size); + strcpy(mi->info,buf3); + } + } + + if ( print_mode & 1 ) + { + fprintf(f,"%*sMemory map of DOL file:\n\n",indent,""); + PrintMemMap(&mm1,f,indent+3,"section"); + putc('\n',f); + } + + if ( print_mode & 2 ) + { + mi = InsertMemMap(&mm2,dol.bss_addr,dol.bss_size); + snprintf(mi->info,sizeof(mi->info),"bss section"); + mi = InsertMemMap(&mm2,dol.entry_addr,0); + snprintf(mi->info,sizeof(mi->info),"entry point"); + + fprintf(f,"%*sMemory map of DOL image:\n\n",indent,""); + mm2.begin = 0xffffffff; + PrintMemMap(&mm2,f,indent+3,"section"); + putc('\n',f); + } + + if ( print_mode & 4 ) + { + mm3.begin = 0xffffffff; + fprintf(f,"%*sDelta between file offset and virtual address:\n\n", + indent,"" ); + PrintMemMap(&mm3,f,indent+3," delta : section"); + putc('\n',f); + } + + ResetMemMap(&mm1); + ResetMemMap(&mm2); + ResetMemMap(&mm3); +} + +/////////////////////////////////////////////////////////////////////////////// + +int GetDolSectionAddr +( + // returns dsa->section + dol_sect_addr_t *dsa, // result: section address info + const dol_header_t *dol_head, // valid DOL header + u32 addr, // address to search + u32 size // >0: wanted size +) +{ + DASSERT(dsa); + DASSERT(dol_head); + memset(dsa,0,sizeof(*dsa)); + dsa->addr = addr; + dsa->size = size; + + int sect; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 sect_addr = ntohl(dol_head->sect_addr[sect]); + const u32 sect_size = ntohl(dol_head->sect_size[sect]); + if ( addr >= sect_addr && addr+size <= sect_addr + sect_size ) + { + dsa->sect_addr = sect_addr; + dsa->sect_offset = addr - sect_addr; + dsa->sect_size = sect_size; + StringCopyS(dsa->sect_name,sizeof(dsa->sect_name),GetDolSectionName(sect)); + return dsa->section = sect; + } + } + + //--- bss? + + const u32 bss_addr = ntohl(dol_head->bss_addr); + const u32 bss_size = ntohl(dol_head->bss_size); + if ( addr >= bss_addr && addr+size <= bss_addr + bss_size ) + { + dsa->sect_addr = bss_addr; + dsa->sect_offset = addr - bss_addr; + dsa->sect_size = bss_size; + StringCopyS(dsa->sect_name,sizeof(dsa->sect_name),"BSS"); + return dsa->section = DOL_IDX_BSS; + } + + //--- not found + + return dsa->section = -1; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetDolSectionAddrInfo +( + // returns GetCircBuf() or EmptyString on error + const dol_header_t *dol_head, // valid DOL header + u32 addr, // address to search + u32 size // >0: wanted size +) +{ + DASSERT(dol_head); + dol_sect_addr_t dsa; + if ( GetDolSectionAddr(&dsa,dol_head,addr,size) < 0 ) + return EmptyString; + + return PrintCircBuf(" (%s+%#x)",dsa.sect_name,dsa.sect_offset); +} + +/////////////////////////////////////////////////////////////////////////////// + +u32 GetDolOffsetByAddr +( + const dol_header_t *dol_head, // valid DOL header + u32 addr, // address to search + u32 size, // >0: wanted size + u32 *valid_size // not NULL: return valid size +) +{ + DASSERT(dol_head); + + int sect; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 sect_addr = ntohl(dol_head->sect_addr[sect]); + const u32 sect_size = ntohl(dol_head->sect_size[sect]); + if ( addr >= sect_addr && addr < sect_addr + sect_size ) + { + u32 max_size = sect_addr + sect_size - addr; + if (!size) + { + if (valid_size) + *valid_size = max_size; + } + else if ( size <= max_size ) + { + if (valid_size) + *valid_size = size; + } + else if (valid_size) + *valid_size = max_size; + else + return 0; + + return ntohl(dol_head->sect_off[sect]) + addr - sect_addr; + } + } + + if (valid_size) + *valid_size = 0; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +u32 GetDolAddrByOffset +( + const dol_header_t *dol_head, // valid DOL header + u32 off, // address to search + u32 size, // >0: wanted size + u32 *valid_size // not NULL: return valid size +) +{ + DASSERT(dol_head); + + int sect; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 sect_off = ntohl(dol_head->sect_off[sect]); + const u32 sect_size = ntohl(dol_head->sect_size[sect]); + + if ( off >= sect_off && off < sect_off + sect_size ) + { + u32 max_size = sect_off + sect_size - off; + if (!size) + { + if (valid_size) + *valid_size = max_size; + } + else if ( size <= max_size ) + { + if (valid_size) + *valid_size = size; + } + else if (valid_size) + *valid_size = max_size; + else + return 0; + + return ntohl(dol_head->sect_addr[sect]) + off - sect_off; + } + } + + if (valid_size) + *valid_size = 0; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AddDolAddrByOffset +( + const dol_header_t *dol_head, // valid DOL header + MemMap_t *mm, // valid destination mem map, not cleared + bool use_tie, // TRUE: use InsertMemMapTie() + u32 off, // address to search + u32 size // size, may overlay multiple sections +) +{ + DASSERT(dol_head); + DASSERT(mm); + + uint count = 0; + while ( size > 0 ) + { + u32 valid_size; + u32 addr = GetDolAddrByOffset(dol_head,off,size,&valid_size); + if ( !addr || !valid_size ) + break; + if (use_tie) + InsertMemMapTie(mm,addr,valid_size); + else + InsertMemMap(mm,addr,valid_size); + off += valid_size; + size -= valid_size; + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint TranslateDolOffsets +( + const dol_header_t *dol_head, // valid DOL header + MemMap_t *mm, // valid destination mem map, not cleared + bool use_tie, // TRUE: use InsertMemMapTie() + const MemMap_t *mm_off // NULL or mem map with offsets +) +{ + DASSERT(dol_head); + DASSERT(mm); + if (!mm_off) + return 0; + + uint mi, count = 0; + for ( mi = 0; mi < mm_off->used; mi++ ) + { + const MemMapItem_t *src = mm_off->field[mi]; + AddDolAddrByOffset(dol_head,mm,use_tie,src->off,src->size); + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint TranslateAllDolOffsets +( + const dol_header_t *dol_head, // valid DOL header + MemMap_t *mm, // valid destination mem map, not cleared + bool use_tie // TRUE: use InsertMemMapTie() +) +{ + DASSERT(dol_head); + DASSERT(mm); + + uint count = 0; + + int i; + for ( i = 0; i < DOL_N_SECTIONS; i++ ) + { + const u32 size = ntohl(dol_head->sect_size[i]); + if (size) + { + count++; + const u32 addr = ntohl(dol_head->sect_addr[i]); + MemMapItem_t *mi = use_tie + ? InsertMemMapTie(mm,addr,size) + : InsertMemMap(mm,addr,size); + if (*mi->info) + StringCopyS(mi->info,sizeof(mi->info),"..."); + else if ( i < DOL_N_TEXT_SECTIONS ) + snprintf(mi->info,sizeof(mi->info),"text section T%u",i); + else + { + const int j = i - DOL_N_TEXT_SECTIONS; + snprintf(mi->info,sizeof(mi->info),"data section D%u",j); + } + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint TranslateDolSections +( + const dol_header_t *dol_head, // valid DOL header + MemMap_t *mm, // valid destination mem map, not cleared + bool use_tie, // TRUE: use InsertMemMapTie() + uint dol_sections // bitfield of sections +) +{ + DASSERT(dol_head); + DASSERT(mm); + + dol_sect_info_t sinfo; + uint sect, count = 0; + for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ ) + { + if ( dol_sections & 1 << sect + && GetDolSectionInfo(&sinfo,dol_head,sizeof(*dol_head),sect) ) + { + count++; + uint size = sect == DOL_IDX_ENTRY ? 16 : sinfo.size; + MemMapItem_t *mi = use_tie + ? InsertMemMapTie(mm,sinfo.addr,size) + : InsertMemMap(mm,sinfo.addr,size); + + if (*mi->info) + StringCopyS(mi->info,sizeof(mi->info),"..."); + else + snprintf(mi->info,sizeof(mi->info), + "section %s",dol_section_name[sect]); + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint CountOverlappedDolSections +( + // returns the number of overlapped section by [addr,size] + + const dol_header_t *dol_head, // valid DOL header + u32 addr, // address to search + u32 size // size of addr to verify +) +{ + DASSERT(dol_head); + + u32 end = addr + size; + if ( end < addr ) // overflow + end = M1(end); + + uint sect, count = 0; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 sect_addr = ntohl(dol_head->sect_addr[sect]); + const u32 sect_size = ntohl(dol_head->sect_size[sect]); + if ( addr < sect_addr + sect_size && end > sect_addr ) + count++; + + noPRINT("%8x..%8x / %8x..%8x => %d/%u\n", + addr, end, sect_addr, sect_addr + sect_size, + addr < sect_addr + sect_size && end > sect_addr, count ); + } + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + void * memmem ( const void *l, size_t l_len, const void *s, size_t s_len ); +#endif // __APPLE__ + +/////////////////////////////////////////////////////////////////////////////// + +static u32 FindDolAddress +( + const u8 *data, // DOL data beginning with dol_header_t + uint off_begin, // begin search here + uint off_end, // end search here + const u8 *search, // data to search + uint serach_size // size of 'search' +) +{ + while ( off_begin < off_end ) + { + const u8 *res + = memmem( data+off_begin, off_end-off_begin, search, serach_size ); + if (!res) + return 0; + off_begin = res - data; + if (!(off_begin&3)) // check alignment + return off_begin; + off_begin++; + } + return 0; +} + +//----------------------------------------------------------------------------- + +u32 FindDolAddressOfVBI +( + // search in available data and return NULL if not found + + cvp data, // DOL data beginning with dol_header_t + uint data_size // size of 'data' +) +{ + if ( data_size < sizeof(dol_header_t) ) + return 0; + const dol_header_t *dh = (dol_header_t*)data; + + static const u8 search1[] = { 0x7C,0xE3,0x3B,0x78, 0x38,0x87,0x00,0x34, + 0x38,0xA7,0x00,0x38, 0x38,0xC7,0x00,0x4C }; + static const u8 search2[] = { 0x4E,0x80,0x00,0x20 }; + + int sect; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 off1 = ntohl(dh->sect_off[sect]); + const u32 size = ntohl(dh->sect_size[sect]); + if ( !size || off1 >= data_size ) + continue; + + u32 off_end = off1 + size; + if ( off_end > data_size ) + off_end = data_size; + + u32 off2 = FindDolAddress( data, off1, off_end, search1, sizeof(search1) ); + if (off2) + { + off2 = FindDolAddress( data, off2+sizeof(search1), off_end, + search2, sizeof(search2) ); + if (off2) + return ntohl(dh->sect_addr[sect]) + off2 - off1; + } + } + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +char * ScanDolSectionName +( + // returns the first uninterpreted character + + ccp arg, // comma/space separated names + int *ret_section, // not NULL: return section index + // <0: error / >=0: section index + enumError *ret_err // not NULL: return error code +) +{ + int section = -1; + enumError err = ERR_OK; + + if (!arg) + err = ERR_MISSING_PARAM; + else + { + while ( *arg && !isalnum((int)*arg) ) + arg++; + + ccp ptr = arg; + char namebuf[10], *np = namebuf; + for(;;) + { + char ch = toupper((int)*ptr); + if ( ch < 'A' || ch > 'Z' ) + break; + if ( np < namebuf + sizeof(namebuf) - 1 ) + *np++ = ch; + ptr++; + } + + int index = -1; + if (!memcmp(namebuf,"TEXT",np-namebuf)) + index = 0; + else if (!memcmp(namebuf,"DATA",np-namebuf)) + index = DOL_N_TEXT_SECTIONS; + else + { + if (!memcmp(namebuf,"BSS",np-namebuf)) + { + section = DOL_IDX_BSS; + arg = ptr; + } + else if (!memcmp(namebuf,"ENTRY",np-namebuf)) + { + section = DOL_IDX_ENTRY; + arg = ptr; + } + else + err = ERR_INVALID_DATA; + goto abort; + } + + char *end; + uint num = str2ul(ptr,&end,10); + if ( end > ptr ) + { + arg = end; + index += num; + if ( index < DOL_N_SECTIONS ) + section = index; + else + err = ERR_INVALID_DATA; + } + } + + abort:; + if (ret_section) + *ret_section = section; + if (ret_err) + *ret_err = err; + return (char*)arg; +} + +//----------------------------------------------------------------------------- + +uint ScanDolSectionList +( + // return a bitfield as section list + + ccp arg, // comma/space separated names + enumError *ret_err // not NULL: return status +) +{ + enumError err = ERR_OK; + uint sect_list = 0; + + while ( arg && *arg ) + { + int section; + enumError scan_err; + arg = ScanDolSectionName(arg,§ion,&scan_err); + if (scan_err) + { + if ( err < scan_err ) + err = scan_err; + break; + } + + if ( section >= 0 ) + sect_list |= 1 << section; + } + + if (ret_err) + *ret_err = !sect_list && err < ERR_MISSING_PARAM ? ERR_MISSING_PARAM : err; + return sect_list; +} + +//----------------------------------------------------------------------------- + +ccp DolSectionList2Text ( uint sect_list ) +{ + char buf[100], *dest = buf; + uint sect; + for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ ) + if ( sect_list & 1 << sect ) + dest = snprintfE(dest,buf+sizeof(buf),",%s",dol_section_name[sect]); + + char *res = GetCircBuf(dest-buf); + memcpy(res,buf+1,dest-buf); + return res; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// add/remove DOL sections /////////////// +/////////////////////////////////////////////////////////////////////////////// + + +uint CompressDOL +( + // return: size of compressed DOL (inline replaced) + + dol_header_t *dol, // valid dol header + FILE *log // not NULL: print memmap to this file +) +{ + DASSERT(dol); + + MemMap_t mm; + InitializeMemMap(&mm); + + uint max_off = 0, total_data_size = 0; + uint s; + for ( s = 0; s < DOL_N_SECTIONS; s++ ) + { + const u32 off = ntohl(dol->sect_off[s]); + const u32 size = ntohl(dol->sect_size[s]); + if ( off && size ) + { + MemMapItem_t *mi = InsertMemMap(&mm,off,size); + snprintf(mi->info,sizeof(mi->info),"%u",s); + total_data_size += size; + if ( max_off < off + size ) + max_off = off + size; + } + } + + if (log) + PrintMemMap(&mm,log,5,"DOL sections"); + + u8 *temp = MALLOC(total_data_size); + + uint i, new_off = 0; + for ( i = 0; i < mm.used; i++ ) + { + MemMapItem_t *mi = mm.field[i]; + uint sect = strtoul(mi->info,0,10); + DASSERT( sect < DOL_N_SECTIONS ); + const u32 off = ntohl(dol->sect_off[sect]); + const u32 size = ntohl(dol->sect_size[sect]); + + memcpy( temp + new_off, (u8*)dol + off, size ); + dol->sect_off[sect] = htonl( sizeof(dol_header_t) + new_off ); + new_off += size; + } + DASSERT( total_data_size == new_off ); + + memcpy(dol+1,temp,new_off); + FREE(temp); + return new_off + sizeof(dol_header_t); +} + +/////////////////////////////////////////////////////////////////////////////// + +uint RemoveDolSections +( + // return: 0:if not modifed, >0:size of compressed DOL + + dol_header_t *dol, // valid dol header + uint stay, // bit field of sections (0..17): SET => don't remove + uint *res_stay, // not NULL: store bit field of vlaid sections here + FILE *log // not NULL: print memmap to this file +) +{ + uint s, m, count = 0; + for ( s = 0, m = 1; s < DOL_N_SECTIONS; s++, m <<= 1 ) + { + const u32 off = ntohl(dol->sect_off[s]); + const u32 size = ntohl(dol->sect_size[s]); + if ( !off || !size ) + stay &= ~m; + + if ( !(stay&m) && off ) + { + dol->sect_off[s] = dol->sect_size[s] = dol->sect_addr[s] = 0; + count++; + } + } + + if (res_stay) + *res_stay = stay; + + return count ? CompressDOL(dol,log) : 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// Gecko Code Handler /////////////// +/////////////////////////////////////////////////////////////////////////////// + +bool IsValidGCH +( + const gch_header_t *gh, // valid header + uint file_size // size of file +) +{ + DASSERT(gh); + + if ( file_size < sizeof(*gh) || ntohl(gh->magic) != GCH_MAGIC_NUM ) + return false; + + const u32 addr = ntohl(gh->addr); + const u32 size = ntohl(gh->size); + const u32 entry = ntohl(gh->vbi_entry); + + if ( addr < 0x80000000 || sizeof(*gh) + size > file_size ) + return false; + + if ( entry && ( entry < addr || entry >= addr + size - 4 )) + return false; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp DecodeWCH +( + // returns NULL on success, or a short error message + + wch_control_t *wc, // store only, (initialized) + void *data, // source data, modified if type != 0 + uint size, // size of 'data' + DecompressWCH_func decompress // NULL or decompression function +) +{ + DASSERT(wc); + DASSERT( data || !size ); + + memset(wc,0,sizeof(*wc)); + if ( !data || size < sizeof(wch_header_t) + sizeof(wch_segment_t) ) + return "To small for a WCH file"; + + const wch_header_t *wh = data; + wc->wh.magic = ntohl(wh->magic); + wc->wh.version = ntohl(wh->version); + wc->wh.size = ntohl(wh->size); + if ( wc->wh.magic != WCH_MAGIC_NUM || wc->wh.version > 1 ) + return "Invalid WCH header"; + + const wch_segment_t *ptr = wh->segment; + if ( wc->wh.version == 1 && decompress ) + { + wc->temp_size = wc->wh.size; + wc->temp_data = MALLOC(wc->temp_size); + DASSERT(wc->temp_data); + + uint data_size = size - sizeof(wch_header_t); + if ( decompress(wc,(void*)ptr,data_size) != ERR_OK ) + return "Decompression of WCH failed."; + ptr = (wch_segment_t*)wc->temp_data; + } + + const wch_segment_t *end = (wch_segment_t*)( (u8*)ptr + wc->wh.size ); + noPRINT("%p %p [%zd]\n",ptr,end,(u8*)end-(u8*)ptr); + + uint iseg; + wch_segment_t *dseg = wc->seg; + for ( iseg = 0; iseg < WCH_MAX_SEG; iseg++, dseg++ ) + { + if (!ptr->type) + break; + dseg->type = ntohl(ptr->type); + dseg->addr = ntohl(ptr->addr); + dseg->size = ntohl(ptr->size); + dseg->main_entry = ntohl(ptr->main_entry); + dseg->main_entry_old = ntohl(ptr->main_entry_old); + dseg->vbi_entry = ntohl(ptr->vbi_entry); + dseg->vbi_entry_old = ntohl(ptr->vbi_entry_old); + + u8 *src_data = (u8*)ptr->data; + wc->seg_data[iseg] = src_data; + ptr = (wch_segment_t*)(ptr->data + ALIGN32(dseg->size,4)); + if ( ptr > end ) + { + wc->is_valid = false; + return "Damaged WCH data"; + } + } + wc->n_seg = iseg; + memset(dseg,0,sizeof(*dseg)); + wc->is_valid = true; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetWCH ( wch_control_t * wc ) +{ + if ( wc && wc->temp_data ) + { + FREE(wc->temp_data); + wc->temp_data = 0; + wc->temp_size = 0; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// virtual dumps /////////////// +/////////////////////////////////////////////////////////////////////////////// + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// E N D /////////////// +/////////////////////////////////////////////////////////////////////////////// |
