lib-dol.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. /***************************************************************************
  2. * *
  3. * _____ ____ *
  4. * | __ \ / __ \ _ _ _____ *
  5. * | | \ \ / / \_\ | | | | _ \ *
  6. * | | \ \| | | | | | |_| | *
  7. * | | | || | | | | | ___/ *
  8. * | | / /| | __ | | | | _ \ *
  9. * | |__/ / \ \__/ / | |___| | |_| | *
  10. * |_____/ \____/ |_____|_|_____/ *
  11. * *
  12. * Wiimms source code library *
  13. * *
  14. ***************************************************************************
  15. * *
  16. * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
  17. * *
  18. ***************************************************************************
  19. * *
  20. * This library is free software; you can redistribute it and/or modify *
  21. * it under the terms of the GNU General Public License as published by *
  22. * the Free Software Foundation; either version 2 of the License, or *
  23. * (at your option) any later version. *
  24. * *
  25. * This library is distributed in the hope that it will be useful, *
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  28. * GNU General Public License for more details. *
  29. * *
  30. * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
  31. * *
  32. ***************************************************************************/
  33. #define _GNU_SOURCE 1
  34. #include "lib-dol.h"
  35. //
  36. ///////////////////////////////////////////////////////////////////////////////
  37. /////////////// dol header ///////////////
  38. ///////////////////////////////////////////////////////////////////////////////
  39. void ntoh_dol_header ( dol_header_t * dest, const dol_header_t * src )
  40. {
  41. DASSERT(dest);
  42. if (!src)
  43. src = dest;
  44. else if ( dest != src )
  45. memcpy(dest,src,sizeof(*dest));
  46. const u32 * src_ptr = src->sect_off;
  47. u32 * dest_ptr = dest->sect_off;
  48. u32 * dest_end = (u32*)&dest->padding;
  49. while ( dest_ptr < dest_end )
  50. *dest_ptr++ = ntohl(*src_ptr++);
  51. }
  52. ///////////////////////////////////////////////////////////////////////////////
  53. void hton_dol_header ( dol_header_t * dest, const dol_header_t * src )
  54. {
  55. DASSERT(dest);
  56. if (!src)
  57. src = dest;
  58. else if ( dest != src )
  59. memcpy(dest,src,sizeof(*dest));
  60. const u32 * src_ptr = src->sect_off;
  61. u32 * dest_ptr = dest->sect_off;
  62. u32 * dest_end = (u32*)&dest->padding;
  63. while ( dest_ptr < dest_end )
  64. *dest_ptr++ = htonl(*src_ptr++);
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////
  67. bool IsDolHeader ( const void *data, uint data_size, uint file_size )
  68. {
  69. if ( data_size < DOL_HEADER_SIZE )
  70. return false;
  71. const dol_header_t *dol = data;
  72. u64 total_size = 0;
  73. uint i;
  74. for ( i = 0; i < DOL_N_SECTIONS; i++ )
  75. {
  76. const u32 off = ntohl(dol->sect_off[i]);
  77. const u32 size = ntohl(dol->sect_size[i]);
  78. const u32 addr = ntohl(dol->sect_addr[i]);
  79. noPRINT("DOL: %8x %8x %08x\n",off,size,addr);
  80. if ( off || size || addr )
  81. {
  82. if ( off & 3
  83. || size & 3
  84. || addr & 3
  85. || off < DOL_HEADER_SIZE
  86. || file_size && off + size > file_size )
  87. {
  88. return false;
  89. }
  90. total_size += size;
  91. }
  92. }
  93. return total_size && total_size < 0x7fffffff;
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////
  96. const char dol_section_name[DOL_NN_SECTIONS+1][4] =
  97. {
  98. "T0",
  99. "T1",
  100. "T2",
  101. "T3",
  102. "T4",
  103. "T5",
  104. "T6",
  105. "D0",
  106. "D1",
  107. "D2",
  108. "D3",
  109. "D4",
  110. "D5",
  111. "D6",
  112. "D7",
  113. "D8",
  114. "D9",
  115. "D10",
  116. "BSS",
  117. "ENT",
  118. ""
  119. };
  120. //
  121. ///////////////////////////////////////////////////////////////////////////////
  122. /////////////// advanced interface ///////////////
  123. ///////////////////////////////////////////////////////////////////////////////
  124. bool GetDolSectionInfo
  125. (
  126. dol_sect_info_t * info, // valid pointer: returned data
  127. const dol_header_t *dol_head, // valid DOL header
  128. uint file_size, // (file) size of 'data'
  129. uint section // 0 .. DOL_NN_SECTIONS
  130. // (7*TEXT, 11*DATA, BSS, ENTRY )
  131. )
  132. {
  133. DASSERT(dol_head);
  134. DASSERT(info);
  135. memset(info,0,sizeof(*info));
  136. if ( !dol_head || file_size < sizeof(dol_header_t) || section >= DOL_NN_SECTIONS )
  137. {
  138. info->section = -1;
  139. return false;
  140. }
  141. info->section = section;
  142. StringCopyS(info->name,sizeof(info->name),GetDolSectionName(section));
  143. if ( section < DOL_N_SECTIONS )
  144. {
  145. const u32 size = be32(&dol_head->sect_size[section]);
  146. if (size)
  147. {
  148. info->sect_valid = true;
  149. info->size = size;
  150. const u32 off = info->off = be32(&dol_head->sect_off [section]);
  151. info->addr = be32(&dol_head->sect_addr[section]);
  152. if ( off < file_size && size < file_size && off+size <= file_size )
  153. {
  154. info->data_valid = true;
  155. info->data = (u8*)dol_head + off;
  156. }
  157. }
  158. return true;
  159. }
  160. if ( section == DOL_IDX_BSS )
  161. {
  162. info->sect_valid = true;
  163. info->addr = be32(&dol_head->bss_addr);
  164. info->size = be32(&dol_head->bss_size);
  165. return true;
  166. }
  167. if ( section == DOL_IDX_ENTRY )
  168. {
  169. info->sect_valid = true;
  170. info->addr = be32(&dol_head->entry_addr);
  171. return true;
  172. }
  173. ASSERT(0);
  174. return false;
  175. }
  176. ///////////////////////////////////////////////////////////////////////////////
  177. bool FindFirstFreeDolSection
  178. (
  179. // returns TRUE on found
  180. dol_sect_info_t *info, // result
  181. const dol_header_t *dh, // DOL header to analyse
  182. uint mode // 0: search all sections (TEXT first)
  183. // 1: search only TEXT sections
  184. // 2: search only DATA sections
  185. // 3: search all sections (DATA first)
  186. )
  187. {
  188. DASSERT(info);
  189. DASSERT(dh);
  190. memset(info,0,sizeof(*info));
  191. uint idx, end;
  192. switch (mode)
  193. {
  194. case 0:
  195. idx = 0;
  196. end = DOL_N_SECTIONS;
  197. break;
  198. case 3:
  199. if (FindFirstFreeDolSection(info,dh,2))
  200. return true;
  201. // fall through
  202. case 1:
  203. idx = 0;
  204. end = DOL_N_TEXT_SECTIONS;
  205. break;
  206. case 2:
  207. idx = DOL_N_TEXT_SECTIONS;
  208. end = DOL_N_SECTIONS;
  209. break;
  210. default:
  211. idx = 0;
  212. end = 0;
  213. break;
  214. }
  215. while ( idx < end && ntohl(dh->sect_size[idx]) )
  216. idx++;
  217. if ( idx >= end )
  218. {
  219. info->section = -1;
  220. return false;
  221. }
  222. info->section = idx;
  223. StringCopyS(info->name,sizeof(info->name),GetDolSectionName(idx));
  224. return true;
  225. }
  226. ///////////////////////////////////////////////////////////////////////////////
  227. bool FindDolSectionBySelector
  228. (
  229. // returns TRUE on found
  230. dol_sect_info_t *info, // result
  231. const dol_header_t *dh, // DOL header to analyse
  232. const dol_sect_select_t *dss // DOL section selector
  233. )
  234. {
  235. DASSERT(info);
  236. DASSERT(dh);
  237. DASSERT(dss);
  238. if ( dss->sect_idx >= 0 )
  239. {
  240. memset(info,0,sizeof(*info));
  241. info->section = dss->sect_idx;
  242. memcpy(info->name,dss->name,sizeof(info->name));
  243. return true;
  244. }
  245. return FindFirstFreeDolSection(info,dh,dss->find_mode);
  246. }
  247. ///////////////////////////////////////////////////////////////////////////////
  248. u32 FindFreeSpaceDOL
  249. (
  250. // return address or NULL on not-found
  251. const dol_header_t *dol_head, // valid DOL header
  252. u32 addr_beg, // first possible address
  253. u32 addr_end, // last possible address
  254. u32 size, // minimal size
  255. u32 align, // aligning
  256. u32 *space // not NULL: store available space here
  257. )
  258. {
  259. DASSERT(dol_head);
  260. MemMap_t mm;
  261. InitializeMemMap(&mm);
  262. int i;
  263. for ( i = 0; i < DOL_N_SECTIONS; i++ )
  264. {
  265. const u32 size = ntohl(dol_head->sect_size[i]);
  266. if (size)
  267. {
  268. const u32 addr = ntohl(dol_head->sect_addr[i]);
  269. if ( addr < addr_end && addr + size > addr_beg )
  270. {
  271. MemMapItem_t * mi = InsertMemMap(&mm,addr,size);
  272. if (mi)
  273. {
  274. if ( i < DOL_N_TEXT_SECTIONS )
  275. snprintf(mi->info,sizeof(mi->info),"T%u",i);
  276. else
  277. snprintf(mi->info,sizeof(mi->info),"D%u",
  278. i - DOL_N_TEXT_SECTIONS);
  279. }
  280. }
  281. }
  282. }
  283. //PrintMemMap(&mm,stdout,3,"section");
  284. u64 res_space;
  285. const u32 res = FindFreeSpaceMemMap(&mm,addr_beg,addr_end,size,align,&res_space);
  286. ResetMemMap(&mm);
  287. if (space)
  288. *space = res_space;
  289. return res;
  290. }
  291. ///////////////////////////////////////////////////////////////////////////////
  292. u32 FindFreeBssSpaceDOL
  293. (
  294. // return address or NULL on not-found
  295. const dol_header_t *dol_head, // valid DOL header
  296. u32 size, // min size
  297. u32 align, // aligning
  298. u32 *space // not NULL: store available space here
  299. )
  300. {
  301. DASSERT(dol_head);
  302. const u32 bss_addr = ntohl(dol_head->bss_addr);
  303. const u32 bss_size = ntohl(dol_head->bss_size);
  304. if ( !bss_addr || !bss_size )
  305. {
  306. if (space)
  307. *space = 0;
  308. return 0;
  309. }
  310. return FindFreeSpaceDOL(dol_head,bss_addr,bss_addr+bss_size,size,align,space);
  311. }
  312. ///////////////////////////////////////////////////////////////////////////////
  313. ///////////////////////////////////////////////////////////////////////////////
  314. void DumpDolHeader
  315. (
  316. FILE * f, // dump to this file
  317. int indent, // indention
  318. const dol_header_t *dol_head, // valid DOL header
  319. uint file_size, // NULL or size of file
  320. uint print_mode // bit field:
  321. // 1: print file map
  322. // 2: print virtual mem map
  323. // 4: print delta table
  324. )
  325. {
  326. DASSERT(f);
  327. DASSERT(dol_head);
  328. indent = NormalizeIndent(indent);
  329. dol_header_t dol;
  330. ntoh_dol_header(&dol,dol_head);
  331. MemMap_t mm1, mm2, mm3;
  332. InitializeMemMap(&mm1);
  333. InitializeMemMap(&mm2);
  334. InitializeMemMap(&mm3);
  335. MemMapItem_t * mi = InsertMemMap(&mm1,0,sizeof(dol_header_t));
  336. StringCopyS(mi->info,sizeof(mi->info),"DOL header");
  337. if (file_size)
  338. {
  339. mi = InsertMemMap(&mm1,file_size,0);
  340. StringCopyS(mi->info,sizeof(mi->info),"--- end of file ---");
  341. }
  342. int i;
  343. for ( i = 0; i < DOL_N_SECTIONS; i++ )
  344. {
  345. const u32 size = dol.sect_size[i];
  346. if (size)
  347. {
  348. const u32 off = dol.sect_off[i];
  349. const u32 addr = dol.sect_addr[i];
  350. char buf[sizeof(mi->info)], buf3[sizeof(mi->info)];
  351. if ( i < DOL_N_TEXT_SECTIONS )
  352. {
  353. snprintf(buf,sizeof(buf),"text section T%u",i);
  354. snprintf(buf3,sizeof(buf3),"%8x : T%u",addr-off,i);
  355. }
  356. else
  357. {
  358. const int j = i - DOL_N_TEXT_SECTIONS;
  359. snprintf(buf,sizeof(buf),"data section D%u",j);
  360. snprintf(buf3,sizeof(buf3),"%8x : D%u",addr-off,j);
  361. }
  362. mi = InsertMemMap(&mm1,off,size);
  363. strcpy(mi->info,buf);
  364. mi = InsertMemMap(&mm2,addr,size);
  365. strcpy(mi->info,buf);
  366. mi = InsertMemMap(&mm3,addr,size);
  367. strcpy(mi->info,buf3);
  368. }
  369. }
  370. if ( print_mode & 1 )
  371. {
  372. fprintf(f,"%*sMemory map of DOL file:\n\n",indent,"");
  373. PrintMemMap(&mm1,f,indent+3,"section");
  374. putc('\n',f);
  375. }
  376. if ( print_mode & 2 )
  377. {
  378. mi = InsertMemMap(&mm2,dol.bss_addr,dol.bss_size);
  379. snprintf(mi->info,sizeof(mi->info),"bss section");
  380. mi = InsertMemMap(&mm2,dol.entry_addr,0);
  381. snprintf(mi->info,sizeof(mi->info),"entry point");
  382. fprintf(f,"%*sMemory map of DOL image:\n\n",indent,"");
  383. mm2.begin = 0xffffffff;
  384. PrintMemMap(&mm2,f,indent+3,"section");
  385. putc('\n',f);
  386. }
  387. if ( print_mode & 4 )
  388. {
  389. mm3.begin = 0xffffffff;
  390. fprintf(f,"%*sDelta between file offset and virtual address:\n\n",
  391. indent,"" );
  392. PrintMemMap(&mm3,f,indent+3," delta : section");
  393. putc('\n',f);
  394. }
  395. ResetMemMap(&mm1);
  396. ResetMemMap(&mm2);
  397. ResetMemMap(&mm3);
  398. }
  399. ///////////////////////////////////////////////////////////////////////////////
  400. int GetDolSectionAddr
  401. (
  402. // returns dsa->section
  403. dol_sect_addr_t *dsa, // result: section address info
  404. const dol_header_t *dol_head, // valid DOL header
  405. u32 addr, // address to search
  406. u32 size // >0: wanted size
  407. )
  408. {
  409. DASSERT(dsa);
  410. DASSERT(dol_head);
  411. memset(dsa,0,sizeof(*dsa));
  412. dsa->addr = addr;
  413. dsa->size = size;
  414. int sect;
  415. for ( sect = 0; sect < DOL_N_SECTIONS; sect++ )
  416. {
  417. const u32 sect_addr = ntohl(dol_head->sect_addr[sect]);
  418. const u32 sect_size = ntohl(dol_head->sect_size[sect]);
  419. if ( addr >= sect_addr && addr+size <= sect_addr + sect_size )
  420. {
  421. dsa->sect_addr = sect_addr;
  422. dsa->sect_offset = addr - sect_addr;
  423. dsa->sect_size = sect_size;
  424. StringCopyS(dsa->sect_name,sizeof(dsa->sect_name),GetDolSectionName(sect));
  425. return dsa->section = sect;
  426. }
  427. }
  428. //--- bss?
  429. const u32 bss_addr = ntohl(dol_head->bss_addr);
  430. const u32 bss_size = ntohl(dol_head->bss_size);
  431. if ( addr >= bss_addr && addr+size <= bss_addr + bss_size )
  432. {
  433. dsa->sect_addr = bss_addr;
  434. dsa->sect_offset = addr - bss_addr;
  435. dsa->sect_size = bss_size;
  436. StringCopyS(dsa->sect_name,sizeof(dsa->sect_name),"BSS");
  437. return dsa->section = DOL_IDX_BSS;
  438. }
  439. //--- not found
  440. return dsa->section = -1;
  441. }
  442. ///////////////////////////////////////////////////////////////////////////////
  443. ccp GetDolSectionAddrInfo
  444. (
  445. // returns GetCircBuf() or EmptyString on error
  446. const dol_header_t *dol_head, // valid DOL header
  447. u32 addr, // address to search
  448. u32 size // >0: wanted size
  449. )
  450. {
  451. DASSERT(dol_head);
  452. dol_sect_addr_t dsa;
  453. if ( GetDolSectionAddr(&dsa,dol_head,addr,size) < 0 )
  454. return EmptyString;
  455. return PrintCircBuf(" (%s+%#x)",dsa.sect_name,dsa.sect_offset);
  456. }
  457. ///////////////////////////////////////////////////////////////////////////////
  458. u32 GetDolOffsetByAddr
  459. (
  460. const dol_header_t *dol_head, // valid DOL header
  461. u32 addr, // address to search
  462. u32 size, // >0: wanted size
  463. u32 *valid_size // not NULL: return valid size
  464. )
  465. {
  466. DASSERT(dol_head);
  467. addr &= ~0x40000000; // remove mirror bit
  468. int sect;
  469. for ( sect = 0; sect < DOL_N_SECTIONS; sect++ )
  470. {
  471. const u32 sect_addr = ntohl(dol_head->sect_addr[sect]);
  472. const u32 sect_size = ntohl(dol_head->sect_size[sect]);
  473. if ( addr >= sect_addr && addr < sect_addr + sect_size )
  474. {
  475. u32 max_size = sect_addr + sect_size - addr;
  476. if (!size)
  477. {
  478. if (valid_size)
  479. *valid_size = max_size;
  480. }
  481. else if ( size <= max_size )
  482. {
  483. if (valid_size)
  484. *valid_size = size;
  485. }
  486. else if (valid_size)
  487. *valid_size = max_size;
  488. else
  489. return 0;
  490. return ntohl(dol_head->sect_off[sect]) + addr - sect_addr;
  491. }
  492. }
  493. if (valid_size)
  494. *valid_size = 0;
  495. return 0;
  496. }
  497. ///////////////////////////////////////////////////////////////////////////////
  498. u32 GetDolAddrByOffset
  499. (
  500. const dol_header_t *dol_head, // valid DOL header
  501. u32 off, // offset to search
  502. u32 size, // >0: wanted size
  503. u32 *valid_size // not NULL: return valid size
  504. )
  505. {
  506. DASSERT(dol_head);
  507. int sect;
  508. for ( sect = 0; sect < DOL_N_SECTIONS; sect++ )
  509. {
  510. const u32 sect_off = ntohl(dol_head->sect_off[sect]);
  511. const u32 sect_size = ntohl(dol_head->sect_size[sect]);
  512. if ( off >= sect_off && off < sect_off + sect_size )
  513. {
  514. u32 max_size = sect_off + sect_size - off;
  515. if (!size)
  516. {
  517. if (valid_size)
  518. *valid_size = max_size;
  519. }
  520. else if ( size <= max_size )
  521. {
  522. if (valid_size)
  523. *valid_size = size;
  524. }
  525. else if (valid_size)
  526. *valid_size = max_size;
  527. else
  528. return 0;
  529. return ntohl(dol_head->sect_addr[sect]) + off - sect_off;
  530. }
  531. }
  532. if (valid_size)
  533. *valid_size = 0;
  534. return 0;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. uint AddDolAddrByOffset
  538. (
  539. const dol_header_t *dol_head, // valid DOL header
  540. MemMap_t *mm, // valid destination mem map, not cleared
  541. bool use_tie, // TRUE: use InsertMemMapTie()
  542. u32 off, // offset to search
  543. u32 size // size, may overlay multiple sections
  544. )
  545. {
  546. DASSERT(dol_head);
  547. DASSERT(mm);
  548. uint count = 0;
  549. while ( size > 0 )
  550. {
  551. u32 valid_size;
  552. u32 addr = GetDolAddrByOffset(dol_head,off,size,&valid_size);
  553. if ( !addr || !valid_size )
  554. break;
  555. if (use_tie)
  556. InsertMemMapTie(mm,addr,valid_size);
  557. else
  558. InsertMemMap(mm,addr,valid_size);
  559. off += valid_size;
  560. size -= valid_size;
  561. }
  562. return count;
  563. }
  564. ///////////////////////////////////////////////////////////////////////////////
  565. uint TranslateDolOffsets
  566. (
  567. const dol_header_t *dol_head, // valid DOL header
  568. MemMap_t *mm, // valid destination mem map, not cleared
  569. bool use_tie, // TRUE: use InsertMemMapTie()
  570. const MemMap_t *mm_off // NULL or mem map with offsets
  571. )
  572. {
  573. DASSERT(dol_head);
  574. DASSERT(mm);
  575. if (!mm_off)
  576. return 0;
  577. uint mi, count = 0;
  578. for ( mi = 0; mi < mm_off->used; mi++ )
  579. {
  580. const MemMapItem_t *src = mm_off->field[mi];
  581. AddDolAddrByOffset(dol_head,mm,use_tie,src->off,src->size);
  582. }
  583. return count;
  584. }
  585. ///////////////////////////////////////////////////////////////////////////////
  586. uint TranslateAllDolOffsets
  587. (
  588. const dol_header_t *dol_head, // valid DOL header
  589. MemMap_t *mm, // valid destination mem map, not cleared
  590. bool use_tie // TRUE: use InsertMemMapTie()
  591. )
  592. {
  593. DASSERT(dol_head);
  594. DASSERT(mm);
  595. uint count = 0;
  596. int i;
  597. for ( i = 0; i < DOL_N_SECTIONS; i++ )
  598. {
  599. const u32 size = ntohl(dol_head->sect_size[i]);
  600. if (size)
  601. {
  602. count++;
  603. const u32 addr = ntohl(dol_head->sect_addr[i]);
  604. MemMapItem_t *mi = use_tie
  605. ? InsertMemMapTie(mm,addr,size)
  606. : InsertMemMap(mm,addr,size);
  607. if (*mi->info)
  608. StringCopyS(mi->info,sizeof(mi->info),"...");
  609. else if ( i < DOL_N_TEXT_SECTIONS )
  610. snprintf(mi->info,sizeof(mi->info),"text section T%u",i);
  611. else
  612. {
  613. const int j = i - DOL_N_TEXT_SECTIONS;
  614. snprintf(mi->info,sizeof(mi->info),"data section D%u",j);
  615. }
  616. }
  617. }
  618. return count;
  619. }
  620. ///////////////////////////////////////////////////////////////////////////////
  621. uint TranslateDolSections
  622. (
  623. const dol_header_t *dol_head, // valid DOL header
  624. MemMap_t *mm, // valid destination mem map, not cleared
  625. bool use_tie, // TRUE: use InsertMemMapTie()
  626. uint dol_sections // bitfield of sections
  627. )
  628. {
  629. DASSERT(dol_head);
  630. DASSERT(mm);
  631. dol_sect_info_t sinfo;
  632. uint sect, count = 0;
  633. for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ )
  634. {
  635. if ( dol_sections & 1 << sect
  636. && GetDolSectionInfo(&sinfo,dol_head,sizeof(*dol_head),sect) )
  637. {
  638. count++;
  639. uint size = sect == DOL_IDX_ENTRY ? 16 : sinfo.size;
  640. MemMapItem_t *mi = use_tie
  641. ? InsertMemMapTie(mm,sinfo.addr,size)
  642. : InsertMemMap(mm,sinfo.addr,size);
  643. if (*mi->info)
  644. StringCopyS(mi->info,sizeof(mi->info),"...");
  645. else
  646. snprintf(mi->info,sizeof(mi->info),
  647. "section %s",dol_section_name[sect]);
  648. }
  649. }
  650. return count;
  651. }
  652. ///////////////////////////////////////////////////////////////////////////////
  653. uint CountOverlappedDolSections
  654. (
  655. // returns the number of overlapped section by [addr,size]
  656. const dol_header_t *dol_head, // valid DOL header
  657. u32 addr, // address to search
  658. u32 size // size of addr to verify
  659. )
  660. {
  661. DASSERT(dol_head);
  662. u32 end = addr + size;
  663. if ( end < addr ) // overflow
  664. end = M1(end);
  665. uint sect, count = 0;
  666. for ( sect = 0; sect < DOL_N_SECTIONS; sect++ )
  667. {
  668. const u32 sect_addr = ntohl(dol_head->sect_addr[sect]);
  669. const u32 sect_size = ntohl(dol_head->sect_size[sect]);
  670. if ( addr < sect_addr + sect_size && end > sect_addr )
  671. count++;
  672. noPRINT("%8x..%8x / %8x..%8x => %d/%u\n",
  673. addr, end, sect_addr, sect_addr + sect_size,
  674. addr < sect_addr + sect_size && end > sect_addr, count );
  675. }
  676. return count;
  677. }
  678. ///////////////////////////////////////////////////////////////////////////////
  679. #ifdef __APPLE__
  680. void * memmem ( const void *l, size_t l_len, const void *s, size_t s_len );
  681. #endif // __APPLE__
  682. ///////////////////////////////////////////////////////////////////////////////
  683. static u32 FindDolAddress
  684. (
  685. const u8 *data, // DOL data beginning with dol_header_t
  686. uint off_begin, // begin search here
  687. uint off_end, // end search here
  688. const u8 *search, // data to search
  689. uint search_size // size of 'search'
  690. )
  691. {
  692. while ( off_begin < off_end )
  693. {
  694. const u8 *res
  695. = memmem( data+off_begin, off_end-off_begin, search, search_size );
  696. if (!res)
  697. return 0;
  698. off_begin = res - data;
  699. if (!(off_begin&3)) // check alignment
  700. return off_begin;
  701. off_begin++;
  702. }
  703. return 0;
  704. }
  705. //-----------------------------------------------------------------------------
  706. u32 FindDolAddressOfVBI
  707. (
  708. // search in available data and return NULL if not found
  709. cvp data, // DOL data beginning with dol_header_t
  710. uint data_size // size of 'data'
  711. )
  712. {
  713. if ( data_size < sizeof(dol_header_t) )
  714. return 0;
  715. const dol_header_t *dh = (dol_header_t*)data;
  716. static const u8 search1[] = { 0x7C,0xE3,0x3B,0x78, 0x38,0x87,0x00,0x34,
  717. 0x38,0xA7,0x00,0x38, 0x38,0xC7,0x00,0x4C };
  718. static const u8 search2[] = { 0x4E,0x80,0x00,0x20 };
  719. int sect;
  720. for ( sect = 0; sect < DOL_N_SECTIONS; sect++ )
  721. {
  722. const u32 off1 = ntohl(dh->sect_off[sect]);
  723. const u32 size = ntohl(dh->sect_size[sect]);
  724. if ( !size || off1 >= data_size )
  725. continue;
  726. u32 off_end = off1 + size;
  727. if ( off_end > data_size )
  728. off_end = data_size;
  729. u32 off2 = FindDolAddress( data, off1, off_end, search1, sizeof(search1) );
  730. if (off2)
  731. {
  732. off2 = FindDolAddress( data, off2+sizeof(search1), off_end,
  733. search2, sizeof(search2) );
  734. if (off2)
  735. return ntohl(dh->sect_addr[sect]) + off2 - off1;
  736. }
  737. }
  738. return 0;
  739. }
  740. //
  741. ///////////////////////////////////////////////////////////////////////////////
  742. ///////////////////////////////////////////////////////////////////////////////
  743. char * ScanDolSectionName
  744. (
  745. // returns the first uninterpreted character
  746. ccp arg, // comma/space separated names
  747. int *ret_section, // not NULL: return section index
  748. // <0: error / >=0: section index
  749. enumError *ret_err // not NULL: return error code
  750. )
  751. {
  752. int section = -1;
  753. enumError err = ERR_OK;
  754. if (!arg)
  755. err = ERR_MISSING_PARAM;
  756. else
  757. {
  758. while ( *arg && !isalnum((int)*arg) )
  759. arg++;
  760. ccp ptr = arg;
  761. char namebuf[10], *np = namebuf;
  762. for(;;)
  763. {
  764. char ch = toupper((int)*ptr);
  765. if ( ch < 'A' || ch > 'Z' )
  766. break;
  767. if ( np < namebuf + sizeof(namebuf) - 1 )
  768. *np++ = ch;
  769. ptr++;
  770. }
  771. int index = -1;
  772. if (!memcmp(namebuf,"TEXT",np-namebuf))
  773. index = 0;
  774. else if (!memcmp(namebuf,"DATA",np-namebuf))
  775. index = DOL_N_TEXT_SECTIONS;
  776. else
  777. {
  778. if (!memcmp(namebuf,"BSS",np-namebuf))
  779. {
  780. section = DOL_IDX_BSS;
  781. arg = ptr;
  782. }
  783. else if (!memcmp(namebuf,"ENTRY",np-namebuf))
  784. {
  785. section = DOL_IDX_ENTRY;
  786. arg = ptr;
  787. }
  788. else
  789. err = ERR_INVALID_DATA;
  790. goto abort;
  791. }
  792. char *end;
  793. uint num = str2ul(ptr,&end,10);
  794. if ( end > ptr )
  795. {
  796. arg = end;
  797. index += num;
  798. if ( index < DOL_N_SECTIONS )
  799. section = index;
  800. else
  801. err = ERR_INVALID_DATA;
  802. }
  803. }
  804. abort:;
  805. if (ret_section)
  806. *ret_section = section;
  807. if (ret_err)
  808. *ret_err = err;
  809. return (char*)arg;
  810. }
  811. //-----------------------------------------------------------------------------
  812. uint ScanDolSectionList
  813. (
  814. // return a bitfield as section list
  815. ccp arg, // comma/space separated names
  816. enumError *ret_err // not NULL: return status
  817. )
  818. {
  819. enumError err = ERR_OK;
  820. uint sect_list = 0;
  821. while ( arg && *arg )
  822. {
  823. int section;
  824. enumError scan_err;
  825. arg = ScanDolSectionName(arg,&section,&scan_err);
  826. if (scan_err)
  827. {
  828. if ( err < scan_err )
  829. err = scan_err;
  830. break;
  831. }
  832. if ( section >= 0 )
  833. sect_list |= 1 << section;
  834. }
  835. if (ret_err)
  836. *ret_err = !sect_list && err < ERR_MISSING_PARAM ? ERR_MISSING_PARAM : err;
  837. return sect_list;
  838. }
  839. //-----------------------------------------------------------------------------
  840. ccp DolSectionList2Text ( uint sect_list )
  841. {
  842. char buf[100], *dest = buf;
  843. uint sect;
  844. for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ )
  845. if ( sect_list & 1 << sect )
  846. dest = snprintfE(dest,buf+sizeof(buf),",%s",dol_section_name[sect]);
  847. char *res = GetCircBuf(dest-buf);
  848. memcpy(res,buf+1,dest-buf);
  849. return res;
  850. }
  851. //
  852. ///////////////////////////////////////////////////////////////////////////////
  853. /////////////// add/remove DOL sections ///////////////
  854. ///////////////////////////////////////////////////////////////////////////////
  855. uint CompressDOL
  856. (
  857. // return: size of compressed DOL (inline replaced)
  858. dol_header_t *dol, // valid dol header
  859. FILE *log // not NULL: print memmap to this file
  860. )
  861. {
  862. DASSERT(dol);
  863. MemMap_t mm;
  864. InitializeMemMap(&mm);
  865. uint max_off = 0, total_data_size = 0;
  866. uint s;
  867. for ( s = 0; s < DOL_N_SECTIONS; s++ )
  868. {
  869. const u32 off = ntohl(dol->sect_off[s]);
  870. const u32 size = ntohl(dol->sect_size[s]);
  871. if ( off && size )
  872. {
  873. MemMapItem_t *mi = InsertMemMap(&mm,off,size);
  874. snprintf(mi->info,sizeof(mi->info),"%u",s);
  875. total_data_size += size;
  876. if ( max_off < off + size )
  877. max_off = off + size;
  878. }
  879. }
  880. if (log)
  881. PrintMemMap(&mm,log,5,"DOL sections");
  882. u8 *temp = MALLOC(total_data_size);
  883. uint i, new_off = 0;
  884. for ( i = 0; i < mm.used; i++ )
  885. {
  886. MemMapItem_t *mi = mm.field[i];
  887. uint sect = strtoul(mi->info,0,10);
  888. DASSERT( sect < DOL_N_SECTIONS );
  889. const u32 off = ntohl(dol->sect_off[sect]);
  890. const u32 size = ntohl(dol->sect_size[sect]);
  891. memcpy( temp + new_off, (u8*)dol + off, size );
  892. dol->sect_off[sect] = htonl( sizeof(dol_header_t) + new_off );
  893. new_off += size;
  894. }
  895. DASSERT( total_data_size == new_off );
  896. memcpy(dol+1,temp,new_off);
  897. FREE(temp);
  898. return new_off + sizeof(dol_header_t);
  899. }
  900. ///////////////////////////////////////////////////////////////////////////////
  901. uint RemoveDolSections
  902. (
  903. // return: 0:if not modifed, >0:size of compressed DOL
  904. dol_header_t *dol, // valid dol header
  905. uint stay, // bit field of sections (0..17): SET => don't remove
  906. uint *res_stay, // not NULL: store bit field of vlaid sections here
  907. FILE *log // not NULL: print memmap to this file
  908. )
  909. {
  910. uint s, m, count = 0;
  911. for ( s = 0, m = 1; s < DOL_N_SECTIONS; s++, m <<= 1 )
  912. {
  913. const u32 off = ntohl(dol->sect_off[s]);
  914. const u32 size = ntohl(dol->sect_size[s]);
  915. if ( !off || !size )
  916. stay &= ~m;
  917. if ( !(stay&m) && off )
  918. {
  919. dol->sect_off[s] = dol->sect_size[s] = dol->sect_addr[s] = 0;
  920. count++;
  921. }
  922. }
  923. if (res_stay)
  924. *res_stay = stay;
  925. return count ? CompressDOL(dol,log) : 0;
  926. }
  927. //
  928. ///////////////////////////////////////////////////////////////////////////////
  929. /////////////// Gecko Code Handler ///////////////
  930. ///////////////////////////////////////////////////////////////////////////////
  931. bool IsValidGCH
  932. (
  933. const gch_header_t *gh, // valid header
  934. uint file_size // size of file
  935. )
  936. {
  937. DASSERT(gh);
  938. if ( file_size < sizeof(*gh) || ntohl(gh->magic) != GCH_MAGIC_NUM )
  939. return false;
  940. const u32 addr = ntohl(gh->addr);
  941. const u32 size = ntohl(gh->size);
  942. const u32 entry = ntohl(gh->vbi_entry);
  943. if ( addr < 0x80000000 || sizeof(*gh) + size > file_size )
  944. return false;
  945. if ( entry && ( entry < addr || entry >= addr + size - 4 ))
  946. return false;
  947. return true;
  948. }
  949. ///////////////////////////////////////////////////////////////////////////////
  950. ccp DecodeWCH
  951. (
  952. // returns NULL on success, or a short error message
  953. wch_control_t *wc, // store only, (initialized)
  954. void *data, // source data, modified if type != 0
  955. uint size, // size of 'data'
  956. DecompressWCH_func decompress // NULL or decompression function
  957. )
  958. {
  959. DASSERT(wc);
  960. DASSERT( data || !size );
  961. memset(wc,0,sizeof(*wc));
  962. if ( !data || size < sizeof(wch_header_t) + sizeof(wch_segment_t) )
  963. return "To small for a WCH file";
  964. const wch_header_t *wh = data;
  965. wc->wh.magic = ntohl(wh->magic);
  966. wc->wh.version = ntohl(wh->version);
  967. wc->wh.size = ntohl(wh->size);
  968. if ( wc->wh.magic != WCH_MAGIC_NUM || wc->wh.version > 1 )
  969. return "Invalid WCH header";
  970. const wch_segment_t *ptr = wh->segment;
  971. if ( wc->wh.version == 1 && decompress )
  972. {
  973. wc->temp_size = wc->wh.size;
  974. wc->temp_data = MALLOC(wc->temp_size);
  975. DASSERT(wc->temp_data);
  976. uint data_size = size - sizeof(wch_header_t);
  977. if ( decompress(wc,(void*)ptr,data_size) != ERR_OK )
  978. return "Decompression of WCH failed.";
  979. ptr = (wch_segment_t*)wc->temp_data;
  980. }
  981. const wch_segment_t *end = (wch_segment_t*)( (u8*)ptr + wc->wh.size );
  982. noPRINT("%p %p [%zd]\n",ptr,end,(u8*)end-(u8*)ptr);
  983. uint iseg;
  984. wch_segment_t *dseg = wc->seg;
  985. for ( iseg = 0; iseg < WCH_MAX_SEG; iseg++, dseg++ )
  986. {
  987. if (!ptr->type)
  988. break;
  989. dseg->type = ntohl(ptr->type);
  990. dseg->addr = ntohl(ptr->addr);
  991. dseg->size = ntohl(ptr->size);
  992. dseg->main_entry = ntohl(ptr->main_entry);
  993. dseg->main_entry_old = ntohl(ptr->main_entry_old);
  994. dseg->vbi_entry = ntohl(ptr->vbi_entry);
  995. dseg->vbi_entry_old = ntohl(ptr->vbi_entry_old);
  996. u8 *src_data = (u8*)ptr->data;
  997. wc->seg_data[iseg] = src_data;
  998. ptr = (wch_segment_t*)(ptr->data + ALIGN32(dseg->size,4));
  999. if ( ptr > end )
  1000. {
  1001. wc->is_valid = false;
  1002. return "Damaged WCH data";
  1003. }
  1004. }
  1005. wc->n_seg = iseg;
  1006. memset(dseg,0,sizeof(*dseg));
  1007. wc->is_valid = true;
  1008. return 0;
  1009. }
  1010. ///////////////////////////////////////////////////////////////////////////////
  1011. void ResetWCH ( wch_control_t * wc )
  1012. {
  1013. if ( wc && wc->temp_data )
  1014. {
  1015. FREE(wc->temp_data);
  1016. wc->temp_data = 0;
  1017. wc->temp_size = 0;
  1018. }
  1019. }
  1020. //
  1021. ///////////////////////////////////////////////////////////////////////////////
  1022. /////////////// sizeof_info_t: dol ///////////////
  1023. ///////////////////////////////////////////////////////////////////////////////
  1024. // [[sizeof_info_dol]]
  1025. const sizeof_info_t sizeof_info_dol[] =
  1026. {
  1027. SIZEOF_INFO_TITLE("DOL")
  1028. SIZEOF_INFO_ENTRY(dol_header_t)
  1029. SIZEOF_INFO_ENTRY(dol_sect_info_t)
  1030. SIZEOF_INFO_ENTRY(dol_sect_select_t)
  1031. SIZEOF_INFO_ENTRY(dol_sect_addr_t)
  1032. SIZEOF_INFO_ENTRY(gch_header_t)
  1033. SIZEOF_INFO_ENTRY(wch_segment_t)
  1034. SIZEOF_INFO_ENTRY(wch_header_t)
  1035. SIZEOF_INFO_ENTRY(wch_control_t)
  1036. SIZEOF_INFO_TERM()
  1037. };
  1038. //
  1039. ///////////////////////////////////////////////////////////////////////////////
  1040. /////////////// E N D ///////////////
  1041. ///////////////////////////////////////////////////////////////////////////////