|
1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Test wrapper for Symbian ELF testing |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalTechnology |
|
19 */ |
|
20 |
|
21 #include <crashdatasave.h> |
|
22 |
|
23 #include "t_self.h" |
|
24 #include "t_coredumpserver.h" |
|
25 |
|
26 CSymbianElfWrapper::CSymbianElfWrapper() |
|
27 {} |
|
28 |
|
29 CSymbianElfWrapper::~CSymbianElfWrapper() |
|
30 { |
|
31 iCoreDumpSession.Close(); |
|
32 iFsSession.Close(); |
|
33 } |
|
34 |
|
35 /** |
|
36 * Two phase constructor for CSymbianElfWrapper |
|
37 * @return CSymbianElfWrapper object |
|
38 * @leave |
|
39 */ |
|
40 CSymbianElfWrapper* CSymbianElfWrapper::NewL() |
|
41 { |
|
42 RDebug::Printf("\ncreating test oibject"); |
|
43 CSymbianElfWrapper* ret = new (ELeave) CSymbianElfWrapper(); |
|
44 CleanupStack::PushL(ret); |
|
45 ret->ConstructL(); |
|
46 CleanupStack::Pop(ret); |
|
47 return ret; |
|
48 } |
|
49 |
|
50 /** |
|
51 * Safe construction |
|
52 * @leave |
|
53 */ |
|
54 void CSymbianElfWrapper::ConstructL() |
|
55 { |
|
56 User::LeaveIfError(iCoreDumpSession.Connect()); |
|
57 User::LeaveIfError(iFsSession.Connect()); |
|
58 } |
|
59 |
|
60 /** |
|
61 * Handle a command invoked from the script |
|
62 * @param aCommand Is the name of the command for a TBuf |
|
63 * @param aSection Is the .ini file section where parameters to the command are located |
|
64 * @param aAsyncErrorIndex Is used by the TEF Block framework to handle asynchronous commands. |
|
65 * @leaves One of the system wide error codes |
|
66 */ |
|
67 TBool CSymbianElfWrapper::DoCommandL(const TTEFFunction& aCommand, const TTEFSectionName& aSection, const TInt aAsyncErrorIndex) |
|
68 { |
|
69 //First we need to get the parameters from the ini file |
|
70 TInt crashId; |
|
71 TPtrC crashName; |
|
72 TPtrC crashSource; |
|
73 TPtrC section; |
|
74 |
|
75 TBool valsOk = GetIntFromConfig(aSection, KKeyCrashId, crashId) && |
|
76 GetStringFromConfig(aSection, KKeyCrashName, crashName) && |
|
77 GetStringFromConfig(aSection, KKeyCrashSource, crashSource) && |
|
78 GetStringFromConfig(aSection, KKeyElfSection, section); |
|
79 |
|
80 if(!valsOk) |
|
81 { |
|
82 ERR_PRINTF1(_L("Unable to get the proper config option from ini file. Are you sure its valid?")); |
|
83 return EFalse; |
|
84 } |
|
85 |
|
86 //Look at the command to see what we need to do |
|
87 if(KCommandGenerateFile() == aCommand && KSourceSystemCrash() == crashSource) |
|
88 { |
|
89 GenerateFileFromSystemCrashL(crashName, crashId); |
|
90 } |
|
91 else if(KCommandFindSection() == aCommand) |
|
92 { |
|
93 VerifySection(section, crashName, ETrue); |
|
94 } |
|
95 else if(KCommandVerifyNoSection() == aCommand) |
|
96 { |
|
97 VerifySection(section, crashName, EFalse); |
|
98 } |
|
99 else |
|
100 { |
|
101 ERR_PRINTF1(_L("Unable to get the proper command from script file. Are you sure its valid?")); |
|
102 return EFalse; |
|
103 } |
|
104 |
|
105 return ETrue; |
|
106 } |
|
107 |
|
108 /** |
|
109 * Verifies a given section in the elf file |
|
110 * @param aSectionToVerify Section to verify |
|
111 * @param aCrashName ELF file name |
|
112 * @param aExists To check if the section exists and is valid, or not |
|
113 */ |
|
114 void CSymbianElfWrapper::VerifySection(TDesC& aSectionToVerify, TDesC& aCrashName, TBool aExists) |
|
115 { |
|
116 RFile selfFile; |
|
117 |
|
118 TInt err = selfFile.Open(iFsSession, aCrashName, EFileStream|EFileRead); |
|
119 INFO_PRINTF3(_L("Trying to open crash file at [%S] and got back [%d]"), &aCrashName, err); |
|
120 |
|
121 T_SELF_ASSERT_TRUE(err == KErrNone, 0); |
|
122 CleanupClosePushL(selfFile); |
|
123 |
|
124 CacheElfHeader(selfFile); |
|
125 ValidateElfFile(selfFile); |
|
126 |
|
127 if(aSectionToVerify == KSectionsVariantData()) |
|
128 { |
|
129 VerifyVariantData(selfFile, aExists); |
|
130 } |
|
131 |
|
132 CleanupStack::PopAndDestroy(); |
|
133 } |
|
134 |
|
135 /** |
|
136 * Verifies Variant data in the elf file |
|
137 * @param aElfFile File handle to elf file |
|
138 */ |
|
139 void CSymbianElfWrapper::VerifyVariantData(RFile& aElfFile, TBool aExists) |
|
140 { |
|
141 INFO_PRINTF1(_L("Looking at the size of variant data section.")); |
|
142 |
|
143 TUint sectionOffset = GetSectionOffset(aElfFile, ESYM_NOTE_VARIANT_DATA); |
|
144 T_SELF_ASSERT_TRUE(sectionOffset > 0, 0); |
|
145 |
|
146 TUint sectionSize = GetSectionSize(aElfFile, ESYM_NOTE_VARIANT_DATA); |
|
147 if(aExists) |
|
148 { |
|
149 T_SELF_ASSERT_TRUE(sectionSize > 0, 0); |
|
150 } |
|
151 else |
|
152 { |
|
153 T_SELF_ASSERT_TRUE(sectionSize == 0, 0); |
|
154 } |
|
155 |
|
156 //Now look at the actual structure |
|
157 Sym32_variant_spec_data varData; |
|
158 TPtr8 varDataDes((TUint8*)&varData, sizeof(Sym32_variant_spec_data)); |
|
159 |
|
160 T_SELF_ASSERT_TRUE(aElfFile.Read(sectionOffset, varDataDes) == KErrNone, 0); |
|
161 |
|
162 INFO_PRINTF1(_L("Looking at the details of variant data structure. Must be > 0")); |
|
163 T_SELF_ASSERT_TRUE(varData.es_data > 0, 0); |
|
164 |
|
165 if(aExists) |
|
166 { |
|
167 T_SELF_ASSERT_TRUE(varData.es_size > 0, 0); |
|
168 } |
|
169 else |
|
170 { |
|
171 T_SELF_ASSERT_TRUE(varData.es_size == 0, 0); |
|
172 } |
|
173 |
|
174 INFO_PRINTF2(_L("Variant data lives in the file at [0x%X]"), varData.es_data); |
|
175 INFO_PRINTF2(_L("Variant data is [0x%X] in size"), varData.es_size); |
|
176 } |
|
177 |
|
178 /** |
|
179 * Looks at elf signature to see if its ok |
|
180 * @param aElfFile File to check |
|
181 */ |
|
182 void CSymbianElfWrapper::ValidateElfFile(RFile& aElfFile) |
|
183 { |
|
184 INFO_PRINTF1(_L("Verifying Elf Header...")); |
|
185 T_SELF_ASSERT_TRUE(iElfHeader.e_ident[EI_MAG0] == 0x7f, 1); |
|
186 T_SELF_ASSERT_TRUE(iElfHeader.e_ident[EI_MAG1] == 0x45, 1); |
|
187 T_SELF_ASSERT_TRUE(iElfHeader.e_ident[EI_MAG2] == 0x4c, 1); |
|
188 T_SELF_ASSERT_TRUE(iElfHeader.e_ident[EI_MAG3] == 0x46, 1); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Caches the ELF header in the object |
|
193 * @param aElfFile file to look at |
|
194 */ |
|
195 void CSymbianElfWrapper::CacheElfHeader(RFile& aElfFile) |
|
196 { |
|
197 INFO_PRINTF1(_L("Reading Elf Header...")); |
|
198 TUint fileLocation = 0; |
|
199 TPtr8 hdrDes((TUint8*)&iElfHeader, sizeof(Elf32_Ehdr)); |
|
200 T_SELF_ASSERT_TRUE(aElfFile.Read(fileLocation, hdrDes) == KErrNone, 0); |
|
201 } |
|
202 |
|
203 /** |
|
204 * Gets the size of a given section in the elf file. |
|
205 * @param aElfFile File to look at |
|
206 * @param aNoteType Note of interest |
|
207 * @return Section size, 0 if not found |
|
208 */ |
|
209 TUint CSymbianElfWrapper::GetSectionSize(RFile& aElfFile, ESYM_NOTE_TYPE aNoteType) |
|
210 { |
|
211 INFO_PRINTF2(_L("Getting section size for section [0x%X]..."), aNoteType); |
|
212 TUint32 sectionOffset = GetSectionOffset(aElfFile, aNoteType); |
|
213 |
|
214 T_SELF_ASSERT_TRUE_RET(sectionOffset != 0, 0, 0); |
|
215 |
|
216 Sym32_dhdr dhdr; |
|
217 TPtr8 dhdrDes((TUint8*)&dhdr, sizeof(Sym32_dhdr)); |
|
218 |
|
219 T_SELF_ASSERT_TRUE_RET(aElfFile.Read(sectionOffset, dhdrDes) == KErrNone, 0, 0); |
|
220 |
|
221 return dhdr.d_descrsz; |
|
222 } |
|
223 |
|
224 /** |
|
225 * Searches the elf file for a given section and returns the offset of that section |
|
226 * @return Section offset - 0 if not found |
|
227 */ |
|
228 TUint CSymbianElfWrapper::GetSectionOffset(RFile& aElfFile, ESYM_NOTE_TYPE aNoteType) |
|
229 { |
|
230 INFO_PRINTF2(_L("Getting section offset for section [0x%X]..."), aNoteType); |
|
231 |
|
232 //Look through descriptor notes for this type |
|
233 for(TUint j = 0; j < iElfHeader.e_phnum; j++) |
|
234 { |
|
235 Elf32_Phdr phdr; |
|
236 TPtr8 phdrDes((TUint8*)&phdr, sizeof(Elf32_Phdr)); |
|
237 T_SELF_ASSERT_TRUE_RET(aElfFile.Read(iElfHeader.e_phoff + j*sizeof(Elf32_Phdr), phdrDes) == KErrNone, 0, 0); |
|
238 |
|
239 if(phdr.p_type == PT_NOTE) |
|
240 { |
|
241 Sym32_dhdr dhdr; |
|
242 TPtr8 dhdrDes((TUint8*)&dhdr, sizeof(Sym32_dhdr)); |
|
243 T_SELF_ASSERT_TRUE_RET(aElfFile.Read(phdr.p_offset, dhdrDes) == KErrNone, 0, 0); |
|
244 |
|
245 if(dhdr.d_type == aNoteType) |
|
246 { |
|
247 return phdr.p_offset + sizeof(Sym32_dhdr); |
|
248 } |
|
249 } |
|
250 } |
|
251 |
|
252 return 0; |
|
253 } |
|
254 |
|
255 /** |
|
256 * Looks at a given system crash and generates a symbian elf file describing it at |
|
257 * specified file |
|
258 * @param aCrashName Name of ELF file to generate |
|
259 * @param aCrashId ID of crash to analyse |
|
260 */ |
|
261 void CSymbianElfWrapper::GenerateFileFromSystemCrashL(TDesC& aCrashName, TInt aCrashId) |
|
262 { |
|
263 INFO_PRINTF1(_L("Generating ELF file from System crash")); |
|
264 |
|
265 //Load SELF and filewriter and configure them to dump where required |
|
266 TPluginRequest loadSELFReq; |
|
267 loadSELFReq.iPluginType = TPluginRequest::EFormatter; |
|
268 loadSELFReq.iLoad = ETrue; |
|
269 loadSELFReq.iUid = KUidELFFormatterV2; |
|
270 |
|
271 TPluginRequest loadWriterReq; |
|
272 loadWriterReq.iPluginType = TPluginRequest::EWriter; |
|
273 loadWriterReq.iLoad = ETrue; |
|
274 loadWriterReq.iUid = KUidFileWriter; |
|
275 |
|
276 INFO_PRINTF1(_L("Loading the file writer and symbian elf...")); |
|
277 iCoreDumpSession.PluginRequestL(loadWriterReq); |
|
278 iCoreDumpSession.PluginRequestL(loadSELFReq); |
|
279 |
|
280 COptionConfig * config = COptionConfig::NewL((TInt)(CCrashDataSave::ECoreFilePath), |
|
281 KUidFileWriter.iUid, COptionConfig::EWriterPlugin, COptionConfig::ETFileName, KFilePathPrompt, |
|
282 1, KNullDesC, 0, aCrashName); |
|
283 |
|
284 CleanupStack::PushL(config); |
|
285 config->Instance(0); |
|
286 |
|
287 INFO_PRINTF2(_L("Configuring the file writer to dump file at [%S]..."), &aCrashName); |
|
288 iCoreDumpSession.SetConfigParameterL(*config); |
|
289 CleanupStack::PopAndDestroy(config); |
|
290 |
|
291 //Get the crashes from the flash partition |
|
292 RCrashInfoPointerList* crashList = new(ELeave)RCrashInfoPointerList; |
|
293 TCleanupItem listCleanup(CCoreDumpServerWrapper::CleanupCrashList, (TAny*)crashList); |
|
294 CleanupStack::PushL(listCleanup); |
|
295 |
|
296 INFO_PRINTF1(_L("Looking at crashes in flash to find ours...")); |
|
297 iCoreDumpSession.ListCrashesInFlashL(*crashList); |
|
298 T_SELF_ASSERT_TRUE(crashList->Count() != 0, 1); |
|
299 T_SELF_ASSERT_TRUE((*crashList)[0]->iCrashId == 0, 1); |
|
300 |
|
301 CleanupStack::PopAndDestroy(1); |
|
302 |
|
303 TRequestStatus status; |
|
304 iCoreDumpSession.ProcessCrashLog(aCrashId, status); |
|
305 User::WaitForRequest(status); |
|
306 |
|
307 T_SELF_ASSERT_TRUE(KErrNone == status.Int(), 0); |
|
308 } |
|
309 |
|
310 //eof |