123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227 |
- /***************************************************************************
- * *
- * _____ ____ *
- * | __ \ / __ \ _ _ _____ *
- * | | \ \ / / \_\ | | | | _ \ *
- * | | \ \| | | | | | |_| | *
- * | | | || | | | | | ___/ *
- * | | / /| | __ | | | | _ \ *
- * | |__/ / \ \__/ / | |___| | |_| | *
- * |_____/ \____/ |_____|_|_____/ *
- * *
- * Wiimms source code library *
- * *
- ***************************************************************************
- * *
- * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
- * *
- ***************************************************************************
- * *
- * This library 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 library 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);
- addr &= ~0x40000000; // remove mirror bit
- 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, // offset 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, // offset 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 search_size // size of 'search'
- )
- {
- while ( off_begin < off_end )
- {
- const u8 *res
- = memmem( data+off_begin, off_end-off_begin, search, search_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;
- }
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// sizeof_info_t: dol ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- // [[sizeof_info_dol]]
- const sizeof_info_t sizeof_info_dol[] =
- {
- SIZEOF_INFO_TITLE("DOL")
- SIZEOF_INFO_ENTRY(dol_header_t)
- SIZEOF_INFO_ENTRY(dol_sect_info_t)
- SIZEOF_INFO_ENTRY(dol_sect_select_t)
- SIZEOF_INFO_ENTRY(dol_sect_addr_t)
- SIZEOF_INFO_ENTRY(gch_header_t)
- SIZEOF_INFO_ENTRY(wch_segment_t)
- SIZEOF_INFO_ENTRY(wch_header_t)
- SIZEOF_INFO_ENTRY(wch_control_t)
- SIZEOF_INFO_TERM()
- };
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// E N D ///////////////
- ///////////////////////////////////////////////////////////////////////////////
|