00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <assert.h>
00024 #if defined(_MSC_VER) && _MSC_VER <= 1200
00025 #pragma warning(disable:4786)
00026 #endif
00027
00028 #include "PalmBinaryFile.h"
00029 #include "palmsystraps.h"
00030
00031
00032 #define UC(p) ((unsigned char*)p)
00033 #define UINT4(p) ((UC(p)[0] << 24) + (UC(p)[1] << 16) + (UC(p)[2] << 8) + \
00034 UC(p)[3])
00035
00036 PalmBinaryFile::PalmBinaryFile()
00037 : m_pImage(0), m_pData(0)
00038 {
00039 }
00040
00041 PalmBinaryFile::~PalmBinaryFile()
00042 {
00043 for (int i=0; i < m_iNumSections; i++)
00044 if (m_pSections[i].pSectionName != 0)
00045 delete [] m_pSections[i].pSectionName;
00046 if (m_pImage) {
00047 delete [] m_pImage;
00048 }
00049 if (m_pData) {
00050 delete [] m_pData;
00051 }
00052 }
00053
00054 bool PalmBinaryFile::RealLoad(const char* sName)
00055 {
00056 FILE *fp;
00057 char buf[32];
00058
00059 m_pFileName = sName;
00060
00061 if ((fp = fopen(sName, "rb")) == NULL) {
00062 fprintf(stderr, "Could not open binary file %s\n", sName);
00063 return false;
00064 }
00065
00066 fseek(fp, 0, SEEK_END);
00067 long size = ftell(fp);
00068
00069
00070 m_pImage = new unsigned char[size];
00071 if (m_pImage == 0) {
00072 fprintf(stderr, "Could not allocate %ld bytes for image\n", size);
00073 return false;
00074 }
00075 memset(m_pImage, size, 0);
00076
00077 fseek(fp, 0, SEEK_SET);
00078 if (fread(m_pImage, 1, size, fp) != (unsigned)size) {
00079 fprintf(stderr, "Error reading binary file %s\n", sName);
00080 return false;
00081 }
00082
00083
00084 if ((strncmp((char*)(m_pImage+0x3C), "appl", 4) != 0) &&
00085 (strncmp((char*)(m_pImage+0x3C), "panl", 4) != 0) &&
00086 (strncmp((char*)(m_pImage+0x3C), "libr", 4) != 0)) {
00087 fprintf(stderr, "%s is not a standard .prc file\n", sName);
00088 return false;
00089 }
00090
00091
00092 m_iNumSections = (m_pImage[0x4C] << 8) + m_pImage[0x4D];
00093
00094
00095 m_pSections = new SectionInfo[m_iNumSections];
00096 if (m_pSections == 0) {
00097 fprintf(stderr, "Could not allocate section info array of %d items\n",
00098 m_iNumSections);
00099 if (m_pImage) {
00100 delete m_pImage;
00101 m_pImage = 0;
00102 }
00103 }
00104
00105
00106 unsigned char* p = m_pImage + 0x4E;
00107 unsigned off = 0;
00108 for (int i=0; i < m_iNumSections; i++) {
00109
00110 strncpy(buf, (char*)p, 4);
00111 buf[4] = '\0';
00112 std::string name(buf);
00113
00114 unsigned id = (p[4] << 8) + p[5];
00115 sprintf(buf, "%d", id);
00116
00117 name += buf;
00118 m_pSections[i].pSectionName = new char[name.size()+1];
00119 strcpy(m_pSections[i].pSectionName, name.c_str());
00120 p += 4+2;
00121 off = UINT4(p);
00122 p += 4;
00123 m_pSections[i].uNativeAddr = off;
00124 m_pSections[i].uHostAddr = off + (ADDRESS)m_pImage;
00125
00126
00127 if (i > 0) {
00128 m_pSections[i-1].uSectionSize = off - m_pSections[i-1].uNativeAddr;
00129 m_pSections[i].uSectionEntrySize = 1;
00130 }
00131
00132
00133 m_pSections[i].bCode =
00134 (name != "code0") && (name.substr(0, 4) == "code");
00135 m_pSections[i].bData = name.substr(0, 4) == "data";
00136
00137 }
00138
00139
00140 m_pSections[m_iNumSections-1].uSectionSize = size - off;
00141
00142
00143 SectionInfo* pData = GetSectionInfoByName("data0");
00144 if (pData == 0) {
00145 fprintf(stderr, "No data section!\n");
00146 return false;
00147 }
00148
00149 SectionInfo* pCode0 = GetSectionInfoByName("code0");
00150 if (pCode0 == 0) {
00151 fprintf(stderr, "No code 0 section!\n");
00152 return false;
00153 }
00154
00155
00156
00157
00158 m_SizeBelowA5 = UINT4(pCode0->uHostAddr+4);
00159
00160 unsigned sizeData = m_SizeBelowA5 + UINT4(pCode0->uHostAddr);
00161
00162
00163 m_pData = new unsigned char[sizeData];
00164 if (m_pData == 0) {
00165 fprintf(stderr, "Could not allocate %u bytes for data section\n",
00166 sizeData);
00167 }
00168
00169
00170 p = (unsigned char*)(pData->uHostAddr+4);
00171 int start = (int) UINT4(p);
00172 p += 4;
00173 unsigned char* q = (m_pData + m_SizeBelowA5 + start);
00174 bool done = false;
00175 while (!done && (p < (unsigned char*)(pData->uHostAddr +
00176 pData->uSectionSize))) {
00177 unsigned char rle = *p++;
00178 if (rle == 0) {
00179 done = true;
00180 break;
00181 }
00182 else if (rle == 1) {
00183
00184
00185 *q++ = 0; *q++ = 0; *q++ = 0; *q++ = 0;
00186 *q++ = 0xFF; *q++ = 0xFF; *q++ = *p++; *q++ = *p++;
00187 }
00188 else if (rle == 2) {
00189
00190
00191 *q++ = 0; *q++ = 0; *q++ = 0; *q++ = 0;
00192 *q++ = 0xFF; *q++ = *p++; *q++ = *p++; *q++ = *p++;
00193 }
00194 else if (rle == 3) {
00195
00196
00197 *q++ = 0xA9; *q++ = 0xF0; *q++ = 0; *q++ = 0;
00198 *q++ = *p++; *q++ = *p++; *q++ = 0; *q++ = *p++;
00199 }
00200 else if (rle == 4) {
00201
00202
00203 *q++ = 0xA9; *q++ = 0xF0; *q++ = 0; *q++ = *p++;
00204 *q++ = *p++; *q++ = *p++; *q++ = 0; *q++ = *p++;
00205 }
00206 else if (rle < 0x10) {
00207
00208 assert(0);
00209 }
00210 else if (rle >= 0x80) {
00211
00212 for (int k=0; k <= (rle-0x80); k++)
00213 *q++ = *p++;
00214 }
00215 else if (rle >= 40) {
00216
00217 for (int k=0; k <= (rle-0x40); k++)
00218 *q++ = 0;
00219 }
00220 else if (rle >= 20) {
00221
00222 unsigned char b = *p++;
00223 for (int k=0; k < (rle-0x20+2); k++)
00224 *q++ = b;
00225 }
00226 else {
00227
00228 for (int k=0; k <= (rle-0x10); k++)
00229 *q++ = 0xFF;
00230 }
00231 }
00232
00233 if (!done)
00234 fprintf(stderr, "Warning! Compressed data section premature end\n");
00235
00236
00237
00238
00239 pData->uHostAddr = (ADDRESS)m_pData;
00240 pData->uSectionSize = sizeData;
00241
00242
00243 pData->uNativeAddr = 0;
00244
00245 return true;
00246 }
00247
00248 void PalmBinaryFile::UnLoad()
00249 {
00250 if (m_pImage) {
00251 delete [] m_pImage;
00252 m_pImage = 0;
00253 }
00254 }
00255
00256
00257 std::list<SectionInfo*>& PalmBinaryFile::GetEntryPoints(const char* pEntry
00258 )
00259 {
00260 std::list<SectionInfo*>* ret = new std::list<SectionInfo*>;
00261 SectionInfo* pSect = GetSectionInfoByName("code1");
00262 if (pSect == 0)
00263 return *ret;
00264 ret->push_back(pSect);
00265 return *ret;
00266 }
00267
00268 ADDRESS PalmBinaryFile::GetEntryPoint()
00269 {
00270 assert(0);
00271 return 0;
00272 }
00273
00274 bool PalmBinaryFile::Open(const char* sName)
00275 {
00276
00277 return false;
00278 }
00279 void PalmBinaryFile::Close()
00280 {
00281
00282 return;
00283 }
00284 bool PalmBinaryFile::PostLoad(void* handle)
00285 {
00286
00287 return false;
00288 }
00289
00290 LOAD_FMT PalmBinaryFile::GetFormat() const
00291 {
00292 return LOADFMT_PALM;
00293 }
00294
00295 MACHINE PalmBinaryFile::GetMachine() const
00296 {
00297 return MACHINE_PALM;
00298 }
00299
00300 bool PalmBinaryFile::isLibrary() const
00301 {
00302 return (strncmp((char*)(m_pImage+0x3C), "libr", 4) == 0);
00303 }
00304 std::list<const char *> PalmBinaryFile::getDependencyList()
00305 {
00306 return std::list<const char *>();
00307 }
00308
00309 ADDRESS PalmBinaryFile::getImageBase()
00310 {
00311 return 0;
00312 }
00313
00314 size_t PalmBinaryFile::getImageSize()
00315 {
00316 return 0;
00317 }
00318
00319
00320 const char* PalmBinaryFile::SymbolByAddress(ADDRESS dwAddr)
00321 {
00322 if ((dwAddr & 0xFFFFF000) == 0xAAAAA000) {
00323
00324 unsigned offset = dwAddr & 0xFFF;
00325 if (offset < numTrapStrings)
00326 return trapNames[offset];
00327 else
00328 return 0;
00329 }
00330 if (dwAddr == GetMainEntryPoint())
00331 return "PilotMain";
00332 else return 0;
00333 }
00334
00335
00336 bool PalmBinaryFile::IsDynamicLinkedProc(ADDRESS uNative)
00337 {
00338 return ((uNative & 0xFFFFF000) == 0xAAAAA000);
00339 }
00340
00341
00342
00343
00344
00345
00346 std::pair<unsigned,unsigned> PalmBinaryFile::GetGlobalPointerInfo()
00347 {
00348 unsigned agp = 0;
00349 const SectionInfo* ps = GetSectionInfoByName("data0");
00350 if (ps) agp = ps->uNativeAddr;
00351 std::pair<unsigned, unsigned> ret(agp, m_SizeBelowA5);
00352 return ret;
00353 }
00354
00355
00356
00357
00358
00359 int PalmBinaryFile::GetAppID() const
00360 {
00361
00362 if (m_pImage == 0)
00363 return 0;
00364
00365 #define OFFSET_ID 0x40
00366 return (m_pImage[OFFSET_ID ] << 24) + (m_pImage[OFFSET_ID+1] << 16) +
00367 (m_pImage[OFFSET_ID+2] << 8) + (m_pImage[OFFSET_ID+3]);
00368 }
00369
00370
00371 #define WILD 0x4AFC
00372 static SWord CWFirstJump[] = {
00373 0x0, 0x1,
00374 0x487a, 0x4,
00375 0x0697, WILD, WILD,
00376 0x4e75};
00377 static SWord CWCallMain[] = {
00378 0x487a, 14,
00379 0x487a, 4,
00380 0x0697, WILD, WILD,
00381 0x4e75};
00382 static SWord GccCallMain[] = {
00383 0x3F04,
00384 0x6100, WILD,
00385 0x3F04,
00386 0x2F05,
00387 0x3F06,
00388 0x6100, WILD};
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 SWord* findPattern(SWord* start, const SWord* patt, int pattSize, int max)
00400 {
00401 const SWord* last = start + max;
00402 for (; start < last; start++) {
00403 bool found = true;
00404 for (int i=0; i < pattSize; i++) {
00405 SWord curr = patt[i];
00406 if ((curr != WILD) && (curr != start[i])) {
00407 found = false;
00408 break;
00409 }
00410 }
00411 if (found)
00412
00413 return start;
00414 }
00415
00416 return 0;
00417 }
00418
00419
00420
00421 ADDRESS PalmBinaryFile::GetMainEntryPoint()
00422 {
00423 SectionInfo* pSect = GetSectionInfoByName("code1");
00424 if (pSect == 0)
00425 return 0;
00426
00427 SWord* startCode = (SWord*) pSect->uHostAddr;
00428 int delta = pSect->uHostAddr - pSect->uNativeAddr;
00429
00430
00431 SWord* res = findPattern(startCode, CWFirstJump,
00432 sizeof(CWFirstJump) / sizeof(SWord), 1);
00433 if (res) {
00434
00435 int addilOp = (startCode[5] << 16) + startCode[6];
00436 SWord* startupCode = (SWord*)((int)startCode + 10 + addilOp);
00437
00438 res = findPattern(startupCode, CWCallMain,
00439 sizeof(CWCallMain) / sizeof(SWord), 60);
00440 if (res) {
00441
00442 addilOp = (res[5] << 16) + res[6];
00443
00444 return (ADDRESS)res + 10 + addilOp - delta;
00445 }
00446 else {
00447 fprintf( stderr, "Could not find call to PilotMain in CW app\n" );
00448 return 0;
00449 }
00450 }
00451
00452 res = findPattern(startCode, GccCallMain,
00453 sizeof(GccCallMain) / sizeof(SWord), 75);
00454 if (res) {
00455
00456 SWord bsrOp = res[7];
00457 return (ADDRESS)res + 14 + bsrOp - delta;
00458 }
00459
00460 fprintf(stderr,"Cannot find call to PilotMain\n");
00461 return 0;
00462 }
00463
00464 void PalmBinaryFile::GenerateBinFiles(const std::string& path) const
00465 {
00466 for (int i=0; i < m_iNumSections; i++) {
00467 SectionInfo* pSect = m_pSections + i;
00468 if ((strncmp(pSect->pSectionName, "code", 4) != 0) &&
00469 (strncmp(pSect->pSectionName, "data", 4) != 0)) {
00470
00471
00472 char name[20];
00473 strncpy(name, pSect->pSectionName, 4);
00474 sprintf(name+4, "%04x.bin", atoi(pSect->pSectionName+4));
00475 std::string fullName(path);
00476 fullName += name;
00477
00478 FILE* f = fopen(fullName.c_str(), "w");
00479 if (f == NULL) {
00480 fprintf( stderr, "Could not open %s for writing binary file\n",
00481 fullName.c_str() );
00482 return;
00483 }
00484 fwrite((void*)pSect->uHostAddr, pSect->uSectionSize, 1, f);
00485 fclose(f);
00486 }
00487 }
00488 }
00489
00490
00491
00492
00493
00494 extern "C" {
00495 #ifdef _WIN32
00496 __declspec(dllexport)
00497 #endif
00498 BinaryFile* construct()
00499 {
00500 return new PalmBinaryFile;
00501 }
00502 }