/[pcsx2_0.9.7]/trunk/pcsx2/Elfheader.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/Elfheader.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 283 - (hide annotations) (download)
Thu Dec 23 12:39:52 2010 UTC (9 years, 6 months ago) by william
File size: 14522 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4132 local: v0.9.7.282-latest) in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16     #include "PrecompiledHeader.h"
17     #include "Common.h"
18    
19     #include "GS.h" // for sending game crc to mtgs
20     #include "Elfheader.h"
21    
22     using namespace std;
23    
24     u32 ElfCRC;
25     u32 ElfEntry;
26     wxString LastELF;
27    
28     #if 0
29     // fixme: ELF command line option system.
30     // It parses a command line and pastes it into PS2 memory, and then points the a0 register at it.
31     // A user-written ELF can then load the data and respond accordingly. Needs a rewrite using modern
32     // string parsing utils. :)
33    
34     //2002-09-19 (Florin)
35     char args[256]="ez.m2v"; //to be accessed by other files
36     uptr args_ptr; //a big value; in fact, it is an address
37    
38     static bool isEmpty(int addr)
39     {
40 william 62 return ((eeMem->Main[addr] == 0) || (eeMem->Main[addr] == 32));
41 william 31 }
42    
43     //in a0 is passed the address of the command line args,
44     //i.e. a pointer to an area like this:
45     //+00 unknown/unused
46     //+04 argc; number of arguments
47     //+08 argv[0]; address of the first parameter - program name (char*) -
48     //+08 argv[1]; address of the second parameter (char*) |
49     //+0C argv[2]; and so on |
50     //........ |
51     //+08+4*argc the program name(first param) <--
52     //+08+4*argc+strlen(argv[0]+1) the rest of params; i.e. a copy of 'args'
53     // see above 'char args[256];'
54    
55     // The results of this function will normally be that it finds an arg at 13 chars, and another at 0.
56     // It'd probably be easier to 0 out all 256 chars, split args, copy all the arguments in, and note
57     // the locations of each split... --arcum42
58    
59     static uint parseCommandLine( const wxString& filename )
60     {
61     if ( ( args_ptr != 0xFFFFFFFF ) && ( args_ptr > (4 + 4 + 256) ) )
62     {
63     const char *p;
64     int argc, i, ret = 0;
65     u32 args_end;
66    
67     args_ptr -= 256;
68    
69     args[ 255 ] = 0;
70    
71     // Copy the parameters into the section of memory at args_ptr,
72     // then zero out anything past the end of args till 256 chars is reached.
73 william 62 memcpy( &eeMem->Main[ args_ptr ], args, 256 );
74     memset( &eeMem->Main[ args_ptr + strlen( args ) ], 0, 256 - strlen( args ) );
75 william 31 args_end = args_ptr + strlen( args );
76    
77     // Set p to just the filename, no path.
78     #ifdef _WIN32
79     p = strrchr( filename, '\\' );
80     #else //linux
81     p = strrchr( filename, '/' );
82     if( p == NULL ) p = strchr(filename, '\\');
83     #endif
84     if (p)
85     p++;
86     else
87     p = filename;
88    
89    
90     args_ptr -= strlen( p ) + 1;
91    
92     //fill param 0; i.e. name of the program
93 william 62 strcpy( (char*)&eeMem->Main[ args_ptr ], p );
94 william 31
95     // Start from the end of where we wrote to, not including all the zero'd out area.
96     for ( i = args_end - args_ptr + 1, argc = 0; i > 0; i-- )
97     {
98     while (i && isEmpty(args_ptr + i )) { i--; }
99    
100     // If the last char is a space, set it to 0.
101 william 62 if ( eeMem->Main[ args_ptr + i + 1 ] == ' ') eeMem->Main[ args_ptr + i + 1 ] = 0;
102 william 31
103     while (i && !isEmpty(args_ptr + i )) { i--; }
104    
105     // Now that we've gone back a word, increase the number of arguments,
106     // and mark the location of the argument.
107     if (!isEmpty(args_ptr + i )) // i <= 0
108     {
109     // If the spot we are on is not a space or null , use it.
110     argc++;
111     ret = args_ptr - 4 - 4 - argc * 4;
112    
113     if (ret < 0 ) return 0;
114 william 62 ((u32*)eeMem->Main)[ args_ptr / 4 - argc ] = args_ptr + i;
115 william 31 }
116     else
117     {
118     if (!isEmpty(args_ptr + i + 1))
119     {
120     // Otherwise, use the next character .
121     argc++;
122     ret = args_ptr - 4 - 4 - argc * 4;
123    
124     if (ret < 0 ) return 0;
125 william 62 ((u32*)eeMem->Main)[ args_ptr / 4 - argc ] = args_ptr + i + 1;
126 william 31 }
127     }
128     }
129    
130     // Pass the number of arguments, and if we have arguments.
131 william 62 ((u32*)eeMem->Main)[ args_ptr /4 - argc - 1 ] = argc; //how many args
132     ((u32*)eeMem->Main)[ args_ptr /4 - argc - 2 ] = ( argc > 0); //have args? //not used, cannot be filled at all
133 william 31
134     return ret;
135     }
136    
137     return 0;
138     }
139     #endif
140     //---------------
141    
142     // All of ElfObjects functions.
143     ElfObject::ElfObject(const wxString& srcfile, IsoFile isofile)
144     : filename( srcfile )
145    
146     , data( wxULongLong(isofile.getLength()).GetLo(), L"ELF headers" )
147     , header( *(ELF_HEADER*)data.GetPtr() )
148     , proghead( NULL )
149     , secthead( NULL )
150     {
151     isCdvd = true;
152     checkElfSize(data.GetSizeInBytes());
153     readIso(isofile);
154     initElfHeaders();
155     }
156    
157     ElfObject::ElfObject( const wxString& srcfile, uint hdrsize )
158     : filename( srcfile )
159     , data( wxULongLong(hdrsize).GetLo(), L"ELF headers" )
160     , header( *(ELF_HEADER*)data.GetPtr() )
161     , proghead( NULL )
162     , secthead( NULL )
163     {
164     isCdvd = false;
165     checkElfSize(data.GetSizeInBytes());
166     readFile();
167     initElfHeaders();
168     }
169    
170     void ElfObject::initElfHeaders()
171     {
172     Console.WriteLn( L"Initializing Elf: %d bytes", data.GetSizeInBytes());
173    
174     if ( header.e_phnum > 0 )
175     proghead = (ELF_PHR*)&data[header.e_phoff];
176    
177     if ( header.e_shnum > 0 )
178     secthead = (ELF_SHR*)&data[header.e_shoff];
179    
180     if ( ( header.e_shnum > 0 ) && ( header.e_shentsize != sizeof(ELF_SHR) ) )
181     Console.Error( "(ELF) Size of section headers is not standard" );
182    
183     if ( ( header.e_phnum > 0 ) && ( header.e_phentsize != sizeof(ELF_PHR) ) )
184     Console.Error( "(ELF) Size of program headers is not standard" );
185    
186     //getCRC();
187    
188     const char* elftype = NULL;
189     switch( header.e_type )
190     {
191     default:
192     ELF_LOG( "type: unknown = %x", header.e_type );
193     break;
194    
195     case 0x0: elftype = "no file type"; break;
196     case 0x1: elftype = "relocatable"; break;
197     case 0x2: elftype = "executable"; break;
198     }
199    
200     if (elftype != NULL) ELF_LOG( "type: %s", elftype );
201    
202     const char* machine = NULL;
203    
204     switch(header.e_machine)
205     {
206     case 1: machine = "AT&T WE 32100"; break;
207     case 2: machine = "SPARC"; break;
208     case 3: machine = "Intel 80386"; break;
209     case 4: machine = "Motorola 68000"; break;
210     case 5: machine = "Motorola 88000"; break;
211     case 7: machine = "Intel 80860"; break;
212     case 8: machine = "mips_rs3000"; break;
213    
214     default:
215     ELF_LOG( "machine: unknown = %x", header.e_machine );
216     break;
217     }
218    
219     if (machine != NULL) ELF_LOG( "machine: %s", machine );
220    
221     ELF_LOG("version: %d",header.e_version);
222 william 62 ELF_LOG("entry: %08x",header.e_entry);
223 william 31 ELF_LOG("flags: %08x",header.e_flags);
224     ELF_LOG("eh size: %08x",header.e_ehsize);
225     ELF_LOG("ph off: %08x",header.e_phoff);
226     ELF_LOG("ph entsiz: %08x",header.e_phentsize);
227     ELF_LOG("ph num: %08x",header.e_phnum);
228     ELF_LOG("sh off: %08x",header.e_shoff);
229     ELF_LOG("sh entsiz: %08x",header.e_shentsize);
230     ELF_LOG("sh num: %08x",header.e_shnum);
231     ELF_LOG("sh strndx: %08x",header.e_shstrndx);
232    
233     ELF_LOG("\n");
234    
235     //applyPatches();
236     }
237    
238     bool ElfObject::hasProgramHeaders() { return (proghead != NULL); }
239     bool ElfObject::hasSectionHeaders() { return (secthead != NULL); }
240     bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders()); }
241    
242     void ElfObject::readIso(IsoFile file)
243     {
244     int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());
245 william 62 if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
246 william 31 }
247    
248     void ElfObject::readFile()
249     {
250     int rsize = 0;
251     FILE *f;
252    
253     f = fopen( filename.ToUTF8(), "rb" );
254     if (f == NULL) Exception::FileNotFound( filename );
255    
256     fseek(f, 0, SEEK_SET);
257     rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
258     fclose( f );
259    
260 william 62 if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
261 william 31 }
262    
263 william 283 static wxString GetMsg_InvalidELF()
264     {
265     return
266     _("Cannot load ELF binary image. The file may be corrupt or incomplete.") +
267     wxString(L"\n\n") +
268     _("If loading from an ISO image, this error may be caused by an unsupported ISO image type or bug in PCSX2 ISO image support.");
269     }
270    
271    
272 william 31 void ElfObject::checkElfSize(s64 elfsize)
273     {
274 william 283 const wxChar* diagMsg = NULL;
275     if (elfsize > 0xfffffff) diagMsg = L"Illegal ELF file size over 2GB!";
276     else if (elfsize == -1) diagMsg = L"ELF file does not exist!";
277     else if (elfsize == 0) diagMsg = L"Unexpected end of ELF file.";
278 william 31
279 william 283 if (diagMsg)
280     throw Exception::BadStream(filename)
281     .SetDiagMsg(diagMsg)
282     .SetUserMsg(GetMsg_InvalidELF());
283 william 31 }
284    
285     u32 ElfObject::getCRC()
286     {
287     u32 CRC = 0;
288    
289     const u32* srcdata = (u32*)data.GetPtr();
290     for(u32 i=data.GetSizeInBytes()/4; i; --i, ++srcdata)
291     CRC ^= *srcdata;
292    
293     return CRC;
294     }
295    
296     void ElfObject::loadProgramHeaders()
297     {
298     if (proghead == NULL) return;
299    
300     for( int i = 0 ; i < header.e_phnum ; i++ )
301     {
302     ELF_LOG( "Elf32 Program Header" );
303     ELF_LOG( "type: " );
304    
305     switch(proghead[ i ].p_type)
306     {
307     default:
308     ELF_LOG( "unknown %x", (int)proghead[ i ].p_type );
309     break;
310    
311     case 0x1:
312     {
313     ELF_LOG("load");
314     const uint elfsize = data.GetLength();
315    
316     if (proghead[ i ].p_offset < elfsize)
317     {
318     int size;
319    
320     if ((proghead[ i ].p_filesz + proghead[ i ].p_offset) > elfsize)
321     size = elfsize - proghead[ i ].p_offset;
322     else
323     size = proghead[ i ].p_filesz;
324    
325     if (proghead[ i ].p_vaddr != proghead[ i ].p_paddr)
326     Console.Warning( "ElfProgram different load addrs: paddr=0x%8.8x, vaddr=0x%8.8x",
327     proghead[ i ].p_paddr, proghead[ i ].p_vaddr);
328    
329     // used to be paddr
330     memcpy_fast(
331 william 62 &eeMem->Main[proghead[ i ].p_vaddr & 0x1ffffff],
332 william 31 data.GetPtr(proghead[ i ].p_offset), size
333     );
334    
335     ELF_LOG("\t*LOADED*");
336     }
337     }
338     break;
339     }
340    
341     ELF_LOG("\n");
342     ELF_LOG("offset: %08x",proghead[i].p_offset);
343     ELF_LOG("vaddr: %08x",proghead[i].p_vaddr);
344     ELF_LOG("paddr: %08x",proghead[i].p_paddr);
345     ELF_LOG("file size: %08x",proghead[i].p_filesz);
346     ELF_LOG("mem size: %08x",proghead[i].p_memsz);
347     ELF_LOG("flags: %08x",proghead[i].p_flags);
348     ELF_LOG("palign: %08x",proghead[i].p_align);
349     ELF_LOG("\n");
350     }
351     }
352    
353     void ElfObject::loadSectionHeaders()
354     {
355     if (secthead == NULL || header.e_shoff > (u32)data.GetLength()) return;
356    
357     const u8* sections_names = data.GetPtr( secthead[ (header.e_shstrndx == 0xffff ? 0 : header.e_shstrndx) ].sh_offset );
358    
359     int i_st = -1, i_dt = -1;
360    
361     for( int i = 0 ; i < header.e_shnum ; i++ )
362     {
363     ELF_LOG( "ELF32 Section Header [%x] %s", i, &sections_names[ secthead[ i ].sh_name ] );
364    
365     // used by parseCommandLine
366     //if ( secthead[i].sh_flags & 0x2 )
367     // args_ptr = min( args_ptr, secthead[ i ].sh_addr & 0x1ffffff );
368    
369     ELF_LOG("\n");
370    
371     const char* sectype = NULL;
372     switch(secthead[ i ].sh_type)
373     {
374     case 0x0: sectype = "null"; break;
375     case 0x1: sectype = "progbits"; break;
376     case 0x2: sectype = "symtab"; break;
377     case 0x3: sectype = "strtab"; break;
378     case 0x4: sectype = "rela"; break;
379     case 0x8: sectype = "no bits"; break;
380     case 0x9: sectype = "rel"; break;
381    
382     default:
383     ELF_LOG("type: unknown %08x",secthead[i].sh_type);
384     break;
385     }
386    
387     ELF_LOG("type: %s", sectype);
388     ELF_LOG("flags: %08x", secthead[i].sh_flags);
389     ELF_LOG("addr: %08x", secthead[i].sh_addr);
390     ELF_LOG("offset: %08x", secthead[i].sh_offset);
391     ELF_LOG("size: %08x", secthead[i].sh_size);
392     ELF_LOG("link: %08x", secthead[i].sh_link);
393     ELF_LOG("info: %08x", secthead[i].sh_info);
394     ELF_LOG("addralign: %08x", secthead[i].sh_addralign);
395     ELF_LOG("entsize: %08x", secthead[i].sh_entsize);
396     // dump symbol table
397    
398     if (secthead[ i ].sh_type == 0x02)
399     {
400     i_st = i;
401     i_dt = secthead[i].sh_link;
402     }
403     }
404    
405     if ((i_st >= 0) && (i_dt >= 0))
406     {
407     const char * SymNames;
408     Elf32_Sym * eS;
409    
410     SymNames = (char*)data.GetPtr(secthead[i_dt].sh_offset);
411     eS = (Elf32_Sym*)data.GetPtr(secthead[i_st].sh_offset);
412     Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym));
413    
414     for(uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++) {
415     if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
416     {
417     R5900::disR5900AddSym(eS[i].st_value, &SymNames[eS[i].st_name]);
418     }
419     }
420     }
421     }
422    
423     void ElfObject::loadHeaders()
424     {
425     loadProgramHeaders();
426     loadSectionHeaders();
427     }
428    
429     // return value:
430     // 0 - Invalid or unknown disc.
431     // 1 - PS1 CD
432     // 2 - PS2 CD
433     int GetPS2ElfName( wxString& name )
434     {
435     int retype = 0;
436    
437     try {
438     IsoFSCDVD isofs;
439     IsoFile file( isofs, L"SYSTEM.CNF;1");
440    
441     int size = file.getLength();
442     if( size == 0 ) return 0;
443    
444     while( !file.eof() )
445     {
446 william 62 const wxString original( fromUTF8(file.readLine().c_str()) );
447     const ParsedAssignmentString parts( original );
448 william 31
449     if( parts.lvalue.IsEmpty() && parts.rvalue.IsEmpty() ) continue;
450     if( parts.rvalue.IsEmpty() )
451     {
452 william 62 Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
453 william 31 Console.Indent().WriteLn( original );
454     continue;
455     }
456    
457     if( parts.lvalue == L"BOOT2" )
458     {
459     name = parts.rvalue;
460 william 62 Console.WriteLn( Color_StrongBlue, L"(SYSTEM.CNF) Detected PS2 Disc = " + name );
461 william 31 retype = 2;
462     }
463     else if( parts.lvalue == L"BOOT" )
464     {
465     name = parts.rvalue;
466 william 62 Console.WriteLn( Color_StrongBlue, L"(SYSTEM.CNF) Detected PSX/PSone Disc = " + name );
467 william 31 retype = 1;
468     }
469     else if( parts.lvalue == L"VMODE" )
470     {
471 william 62 Console.WriteLn( Color_Blue, L"(SYSTEM.CNF) Disc region type = " + parts.rvalue );
472 william 31 }
473     else if( parts.lvalue == L"VER" )
474     {
475 william 62 Console.WriteLn( Color_Blue, L"(SYSTEM.CNF) Software version = " + parts.rvalue );
476 william 31 }
477     }
478    
479     if( retype == 0 )
480     {
481     Console.Error("(GetElfName) Disc image is *not* a Playstation or PS2 game!");
482     return 0;
483     }
484     }
485 william 280 catch( Exception::FileNotFound& )
486     {
487     //Console.Warning(ex.FormatDiagnosticMessage());
488     return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
489     }
490 william 62 catch (Exception::BadStream& ex)
491 william 31 {
492 william 62 Console.Error(ex.FormatDiagnosticMessage());
493 william 31 return 0; // ISO error
494     }
495    
496     #ifdef PCSX2_DEVBUILD
497     FILE *fp;
498     int i;
499     char buffer[512];
500    
501     fp = fopen("System.map", "r");
502     if( fp == NULL ) return 2;
503    
504     u32 addr;
505    
506     Console.WriteLn("Loading System.map...");
507     while (!feof(fp)) {
508     fseek(fp, 8, SEEK_CUR);
509     buffer[0] = '0'; buffer[1] = 'x';
510     for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0;
511     addr = strtoul(buffer, (char**)NULL, 0);
512     fseek(fp, 3, SEEK_CUR);
513     for (i=0; i<512; i++) {
514     buffer[i] = fgetc(fp);
515     if (buffer[i] == '\n' || buffer[i] == 0) break;
516     }
517     if (buffer[i] == 0) break;
518     buffer[i] = 0;
519    
520     R5900::disR5900AddSym(addr, buffer);
521     }
522     fclose(fp);
523     #endif
524    
525     return retype;
526     }

  ViewVC Help
Powered by ViewVC 1.1.22