commands/patchdata/patchdata.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // patchdata.cpp
       
     2 // 
       
     3 // Copyright (c) 2008 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/ioutils.h>
       
    14 #include <f32image.h>
       
    15 #include "sf_deflate.h"
       
    16 #include <e32rom.h>
       
    17 #include <fshell/memoryaccesscmd.h>
       
    18 
       
    19 using namespace IoUtils;
       
    20 
       
    21 IMPORT_C extern const TInt KHeapMinCellSize;
       
    22 
       
    23 class CCmdPatchdata : public CMemoryAccessCommandBase
       
    24 	{
       
    25 public:
       
    26 	static CCommandBase* NewLC();
       
    27 	~CCmdPatchdata();
       
    28 private:
       
    29 	CCmdPatchdata();
       
    30 	void HandleXipL();
       
    31 
       
    32 private: // From CCommandBase.
       
    33 	virtual const TDesC& Name() const;
       
    34 	virtual void DoRunL();
       
    35 	virtual void ArgumentsL(RCommandArgumentList& aArguments);
       
    36 	virtual void OptionsL(RCommandOptionList& aOptions);
       
    37 private:
       
    38 	// The stuff from elsewhere
       
    39 	void LoadFileInflateL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize);
       
    40 	void LoadFileNoCompressL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize);
       
    41 	TInt LoadFile(TUint32 aCompression,E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 iRestOfFileSize);	
       
    42 
       
    43 private:
       
    44 	HBufC* iDll;
       
    45 	TInt iOrdinal;
       
    46 	TInt iNewValue;
       
    47 	TFileName iPath;
       
    48 	TFileName iNewPath;
       
    49 	RFile iFile;
       
    50 	TBool iVerbose;
       
    51 	};
       
    52 
       
    53 
       
    54 CCommandBase* CCmdPatchdata::NewLC()
       
    55 	{
       
    56 	CCmdPatchdata* self = new(ELeave) CCmdPatchdata();
       
    57 	CleanupStack::PushL(self);
       
    58 	self->BaseConstructL();
       
    59 	return self;
       
    60 	}
       
    61 
       
    62 CCmdPatchdata::~CCmdPatchdata()
       
    63 	{
       
    64 	delete iDll;
       
    65 	iFile.Close();
       
    66 	}
       
    67 
       
    68 CCmdPatchdata::CCmdPatchdata()
       
    69 	{
       
    70 	}
       
    71 
       
    72 const TDesC& CCmdPatchdata::Name() const
       
    73 	{
       
    74 	_LIT(KName, "patchdata");	
       
    75 	return KName;
       
    76 	}
       
    77 
       
    78 void CCmdPatchdata::ArgumentsL(RCommandArgumentList& aArguments)
       
    79 	{
       
    80 	aArguments.AppendStringL(iDll, _L("dll-name"));
       
    81 	aArguments.AppendIntL(iOrdinal, _L("ordinal"));
       
    82 	aArguments.AppendUintL((TUint&)iNewValue, _L("value"));
       
    83 	}
       
    84 
       
    85 void CCmdPatchdata::OptionsL(RCommandOptionList& aOptions)
       
    86 	{
       
    87 	aOptions.AppendBoolL(iVerbose, _L("verbose"));
       
    88 	}
       
    89 
       
    90 EXE_BOILER_PLATE(CCmdPatchdata)
       
    91 
       
    92 void CCmdPatchdata::DoRunL()
       
    93 	{
       
    94 	if (!iDll)
       
    95 		{
       
    96 		// Just print some standard ones
       
    97 		Printf(_L("KHeapMinCellSize: %d\r\n"), KHeapMinCellSize);
       
    98 		return;
       
    99 		}
       
   100 
       
   101 	TBool scan = !iArguments.IsPresent(1);
       
   102 	TBool change = iArguments.IsPresent(2);
       
   103 
       
   104 	// First figure out where the dll is - easiest way is to load it
       
   105 #ifdef __WINS__
       
   106 	PrintWarning(_L("On WINS, exe-name must be a complete path to a E32 DLL"));
       
   107 	iPath = *iDll;
       
   108 #else
       
   109 	// Can't use RLibrary because we have all caps and the DLL won't
       
   110 	TFindFile find(FsL());
       
   111 	TInt found = find.FindByDir(*iDll, _L("Y:\\sys\\bin\\"));
       
   112 	LeaveIfErr(found, _L("Couldn't find DLL %S"), iDll);
       
   113 	iPath = find.File();
       
   114 
       
   115 	if (FsL().IsFileInRom(iPath) != NULL)
       
   116 		{
       
   117 		HandleXipL();
       
   118 		return;
       
   119 		}
       
   120 #endif
       
   121 
       
   122 	iNewPath = iPath;
       
   123 	TUint fileopenmode = EFileRead|EFileStream|EFileShareAny;
       
   124 
       
   125 	if (change) fileopenmode = EFileWrite|EFileStream|EFileShareAny;
       
   126 
       
   127 	if (change && iPath[0] != 'c')
       
   128 		{
       
   129 		// If file is already on c then we just patch in place
       
   130 
       
   131 		// We have a new value to set - so copy the DLL to C in preparation for patching it
       
   132 		iNewPath[0] = 'c';
       
   133 
       
   134 		//CleanupStack::PushL(TCleanupItem(&DeleteModifiedBinary, this));
       
   135 
       
   136 		TInt err = FsL().MkDirAll(iNewPath); // In case C:\sys\bin doesn't exist yet
       
   137 		if (err && err != KErrAlreadyExists)
       
   138 			{
       
   139 			PrintError(err, _L("Couldn't create C:\\sys\\bin"));
       
   140 			User::Leave(err);
       
   141 			}
       
   142 
       
   143 		CFileMan* fm = CFileMan::NewL(Fs());
       
   144 		CleanupStack::PushL(fm);
       
   145 
       
   146 		LeaveIfErr(fm->Copy(iPath, iNewPath), _L("Couldn't copy file from %S to %S"), &iPath, &iNewPath);
       
   147 		// Clear the read-only bit in the case where we've copied from ROM
       
   148 		LeaveIfErr(Fs().SetAtt(iNewPath, 0, KEntryAttReadOnly), _L("Couldn't unset read-only flag"));
       
   149 		CleanupStack::PopAndDestroy(fm);
       
   150 		}
       
   151 
       
   152 	// Now start fiddling
       
   153 	LeaveIfErr(iFile.Open(FsL(), iNewPath, fileopenmode), _L("Couldn't open file %S"), &iNewPath);
       
   154 
       
   155 	///// Begin code lifted from chkdeps
       
   156 	E32ImageHeaderV* imageHeader=new(ELeave)E32ImageHeaderV;
       
   157 	CleanupStack::PushL(imageHeader);
       
   158 	TPckg<E32ImageHeaderV> ptr(*imageHeader);
       
   159 	LeaveIfErr(iFile.Read(ptr, sizeof(E32ImageHeaderV)), _L("Couldn't read E32ImageHeader"));
       
   160 
       
   161 	if (!scan && (iOrdinal <= 0 || iOrdinal-1 >= imageHeader->iExportDirCount)) // -1 because ordinals are 1-based in DEF files
       
   162 		{
       
   163 		LeaveIfErr(KErrArgument, _L("ordinal out of range: only %d exports in file"), imageHeader->iExportDirCount);
       
   164 		}
       
   165 	if (imageHeader->HeaderFormat() >= KImageHdrFmt_V && imageHeader->iExportDescType != KImageHdr_ExpD_NoHoles)
       
   166 		{
       
   167 		LeaveIfErr(KErrNotSupported, _L("Don't understand files whose export table format isn't KImageHdr_ExpD_NoHoles (format is %d)"), imageHeader->iExportDescType);
       
   168 		}
       
   169 
       
   170 	TInt exportOffset = imageHeader->iExportDirOffset;
       
   171 
       
   172 	// Decompress rest of image
       
   173 	TUint32 compression = imageHeader->CompressionType();
       
   174 	TInt restOfFileSize=0;
       
   175 	TUint8* restOfFileData=NULL;
       
   176 	//detect the size of import information
       
   177 	if (compression != KFormatNotCompressed)
       
   178 		{
       
   179 		// Compressed executable
       
   180 		// iCodeOffset	= header size for format V or above
       
   181 		//				= sizeof(E32ImageHeader) for format J
       
   182 		restOfFileSize = imageHeader->UncompressedFileSize() - imageHeader->iCodeOffset;
       
   183 		}
       
   184 	else
       
   185 		{
       
   186 		TInt FileSize;
       
   187 		iFile.Size(FileSize); 		
       
   188 		restOfFileSize = FileSize-imageHeader->TotalSize();
       
   189 		}	
       
   190 	//restOfFileSize -= imageHeader->iCodeSize; // the size of the exe less header & code
       
   191 	
       
   192 	//allocate memory for rest of file
       
   193 	if (restOfFileSize >0)
       
   194 		{
       
   195 		restOfFileData = (TUint8*)User::AllocLC(restOfFileSize );		
       
   196 		}
       
   197 
       
   198 	LeaveIfErr(LoadFile(compression,imageHeader,restOfFileData,restOfFileSize), _L("Failed to load file data")); // Read import information in
       
   199 
       
   200 	///// End code lifted from chkdeps
       
   201 
       
   202 	const TInt headerSize = imageHeader->iCodeOffset;
       
   203 	exportOffset -= headerSize; // we are indexing into restoffile which doesn't have the header
       
   204 
       
   205 	TInt* exports = (TInt*)(restOfFileData + exportOffset);
       
   206 
       
   207 	if (scan)
       
   208 		{
       
   209 		//Printf(_L("TextSize = %d\r\n"), imageHeader->iTextSize);
       
   210 		//Printf(_L("CodeSize = %d\r\n"), imageHeader->iCodeSize);
       
   211 		//Printf(_L("dataoffset = %d\r\n"), imageHeader->iDataOffset);
       
   212 		//Printf(_L("importoffset= %d\r\n"), imageHeader->iImportOffset);
       
   213 		//Printf(_L("exportdiroffset= %d\r\n"), imageHeader->iExportDirOffset);
       
   214 		for (TInt i = 0; i < imageHeader->iExportDirCount; i++)
       
   215 			{
       
   216 			// No direct way of figuring out where code stops and const data starts. Export table sits between them though
       
   217 			// so use this to distiguish. (Don't know if my logic here is right but it seems to mainly work...)
       
   218 			TInt valoffset = exports[i] - imageHeader->iCodeBase;
       
   219 			if (iVerbose)
       
   220 				{
       
   221 				Printf(_L("export[%d] = %d\r\n"), i, valoffset + headerSize);
       
   222 				}
       
   223 			if (valoffset >= (TInt)imageHeader->iExportDirOffset-headerSize)
       
   224 				{
       
   225 				TInt val = *(TInt*)(restOfFileData + valoffset);
       
   226 				Printf(_L("Ordinal %d: 0x%08x (%d)\r\n"), i+1, val, val);
       
   227 				}
       
   228 			}
       
   229 		}
       
   230 	else
       
   231 		{
       
   232 		TInt valoffset = exports[iOrdinal-1] - imageHeader->iCodeBase; // Subtract one from ordinal as they're 1-based in DEF files
       
   233 		TInt& val = *(TInt*)(restOfFileData + valoffset);
       
   234 
       
   235 		if (change)
       
   236 			{
       
   237 			TInt oldVal = val;
       
   238 			val = iNewValue; // This updates restOfFileData
       
   239 			// Now write everything back to file. The data has to be written uncompressed as there is no compression
       
   240 			// code we can easily rip off. We have to update the header irrespective to increment the version
       
   241  			iFile.SetSize(headerSize);
       
   242 			
       
   243 			imageHeader->iCompressionType = KFormatNotCompressed;
       
   244 			// Update the version to sort out linking bug (probably not an issue for most uses of patchable data, but it could be in theory)
       
   245 			if ((imageHeader->iModuleVersion & 0x0000ffffu) == 0x0000ffffu)
       
   246 				{
       
   247 				// Don't update if version is XXXXffff as incrementing it would raise the major version - which is considered incompatible
       
   248 				PrintWarning(_L("Couldn't update DLL's minor version as it is already at its maximum value"));
       
   249 				}
       
   250 			else
       
   251 				{
       
   252 				imageHeader->iModuleVersion++;
       
   253 				}
       
   254 
       
   255 			// Update e32 checksum
       
   256 			imageHeader->iHeaderCrc = KImageCrcInitialiser;
       
   257 			TUint32 crc = 0;
       
   258 			Mem::Crc32(crc, imageHeader, imageHeader->TotalSize());
       
   259 			imageHeader->iHeaderCrc = crc;
       
   260 			LeaveIfErr(iFile.Write(0, ptr), _L("Couldn't write updated header back to file"));
       
   261 
       
   262 			TPtrC8 data(restOfFileData, restOfFileSize);
       
   263 			LeaveIfErr(iFile.Write(headerSize, data), _L("Couldn't write patched DLL code back to file"));
       
   264 
       
   265 			Printf(_L("Ordinal %d: old value was 0x%08x, new value is 0x%08x"), iOrdinal, oldVal, iNewValue);
       
   266 			}
       
   267 		else
       
   268 			{
       
   269 			Printf(_L("Ordinal %d: 0x%08x (%d)\r\n"), iOrdinal, val, val);
       
   270 			}
       
   271 		}
       
   272 
       
   273 	CleanupStack::PopAndDestroy(2, imageHeader); // imageHeader, restOfFileData
       
   274 	}
       
   275 
       
   276 void FileCleanup(TAny* aPtr)
       
   277 	{
       
   278 	TFileInput* f=(TFileInput*)aPtr;
       
   279 	f->Cancel();
       
   280 	delete f;
       
   281 	}
       
   282 
       
   283 void CCmdPatchdata::LoadFileInflateL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
       
   284 	{
       
   285 	TInt pos = aHeader->TotalSize();
       
   286 	User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
       
   287 
       
   288 	TFileInput* file = new (ELeave) TFileInput(iFile);
       
   289 	CleanupStack::PushL(TCleanupItem(&FileCleanup,file));
       
   290 	CInflater* inflater=CInflater::NewLC(*file);
       
   291 	
       
   292 	/*if (aHeader->iCodeSize)
       
   293 		{
       
   294 		TUint8* CodeData = (TUint8*)User::AllocLC(aHeader->iCodeSize );
       
   295 		TInt count=inflater->ReadL((TUint8*)CodeData ,aHeader->iCodeSize,&Mem::Move);
       
   296 		if(count!=aHeader->iCodeSize)
       
   297 			User::Leave(KErrCorrupt);
       
   298 		CleanupStack::PopAndDestroy(CodeData);
       
   299 		}*/
       
   300 	
       
   301 	if (aRestOfFileSize)
       
   302 		{
       
   303 		TUint32 count=inflater->ReadL(aRestOfFileData,aRestOfFileSize,&Mem::Move);
       
   304 		if(count!=aRestOfFileSize)
       
   305 			User::Leave(KErrCorrupt);
       
   306 		}
       
   307 	CleanupStack::PopAndDestroy(2,file);
       
   308 	}
       
   309 
       
   310 void CCmdPatchdata::LoadFileNoCompressL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
       
   311 	{
       
   312 	TInt pos = (aHeader->TotalSize() /*+aHeader->iCodeSize*/);
       
   313 	if (aRestOfFileSize)
       
   314 		{
       
   315 		User::LeaveIfError(iFile.Seek(ESeekStart,pos));
       
   316 		TPtr8 ptrToData((TText8*)(aRestOfFileData),aRestOfFileSize,aRestOfFileSize);
       
   317 		User::LeaveIfError(iFile.Read(ptrToData, (TInt)aRestOfFileSize));	
       
   318 		}
       
   319 	}	
       
   320 //function loads file's import information calling decompression routine if needed
       
   321 TInt CCmdPatchdata::LoadFile(TUint32 aCompression,E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
       
   322 	{
       
   323 	TInt r=KErrNone;
       
   324 	if(aCompression==KFormatNotCompressed)
       
   325 		{
       
   326 		TRAP(r,LoadFileNoCompressL(aHeader,aRestOfFileData,aRestOfFileSize));		
       
   327 		}
       
   328 	else if(aCompression==KUidCompressionDeflate)
       
   329 		{
       
   330 		TRAP(r,LoadFileInflateL(aHeader,aRestOfFileData,aRestOfFileSize));
       
   331 		}
       
   332 	else
       
   333 		r=KErrNotSupported;
       
   334 
       
   335 	return r;
       
   336 	}
       
   337 
       
   338 void CCmdPatchdata::HandleXipL()
       
   339 	{
       
   340 	TBool scan = !iArguments.IsPresent(1);
       
   341 	TBool change = iArguments.IsPresent(2);
       
   342 	TRomImageHeader* imageHeader = (TRomImageHeader*)FsL().IsFileInRom(iPath);
       
   343 
       
   344 	if (!scan && (iOrdinal <= 0 || iOrdinal-1 >= imageHeader->iExportDirCount)) // -1 because ordinals are 1-based in DEF files
       
   345 		{
       
   346 		LeaveIfErr(KErrArgument, _L("ordinal out of range: only %d exports in file"), imageHeader->iExportDirCount);
       
   347 		}
       
   348 
       
   349 	TLinAddr* exports = (TLinAddr*)(imageHeader->iExportDir);
       
   350 
       
   351 	if (scan)
       
   352 		{
       
   353 		for (TInt i = 0; i < imageHeader->iExportDirCount; i++)
       
   354 			{
       
   355 			TLinAddr valAddr = exports[i];
       
   356 			if (iVerbose)
       
   357 				{
       
   358 				Printf(_L("export[%d] = 0x%08x\r\n"), i, valAddr);
       
   359 				}
       
   360 			valAddr &= ~3; // Clear thumb bit - code exports can have this set. No idea why some can have bit 1 set...
       
   361 			// There really doesn't seem to be a way to figure out where code stops and const data starts, for core images. It generally looks to come after the export dir but it gives false positives
       
   362 			if (valAddr > (TLinAddr)imageHeader)
       
   363 				{
       
   364 				TInt val = *(TInt*)valAddr;
       
   365 				Printf(_L("Ordinal %d: 0x%08x (%d)\r\n"), i+1, val, val);
       
   366 				}
       
   367 			}
       
   368 		}
       
   369 	else
       
   370 		{
       
   371 		TLinAddr valAddr = exports[iOrdinal-1]; // Subtract one from ordinal as they're 1-based in DEF files
       
   372 		TInt val = *(TInt*)(valAddr);
       
   373 
       
   374 		if (change)
       
   375 			{
       
   376 			TInt oldVal = val;
       
   377 
       
   378 #ifdef FSHELL_MEMORY_ACCESS_SUPPORT
       
   379 			LoadMemoryAccessL();
       
   380 			TPckg<TInt> valPkg(iNewValue);
       
   381 			LeaveIfErr(iMemAccess.WriteShadowMemory(valAddr, valPkg), _L("Couldn't write shadow for new value"));
       
   382 #else
       
   383 			LeaveIfErr(KErrNotSupported, _L("Can't update patchdata for DLLs in core image without memoryaccess support"));
       
   384 #endif
       
   385 
       
   386 
       
   387 			Printf(_L("Ordinal %d: old value was 0x%08x, new value is 0x%08x"), iOrdinal, oldVal, iNewValue);
       
   388 			}
       
   389 		else
       
   390 			{
       
   391 			Printf(_L("Ordinal %d: 0x%08x (%d)\r\n"), iOrdinal, val, val);
       
   392 			}
       
   393 		}
       
   394 	}
       
   395