1 /*
2 * \file ss_to_dcdtree.cpp
3 * \brief OpenCSD :
4 *
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
6 */
7
8 /*
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "ss_to_dcdtree.h"
36 #include "ss_key_value_names.h"
37
38
CreateDcdTreeFromSnapShot()39 CreateDcdTreeFromSnapShot::CreateDcdTreeFromSnapShot() :
40 m_bInit(false),
41 m_pDecodeTree(0),
42 m_pReader(0),
43 m_pErrLogInterface(0),
44 m_bPacketProcOnly(false),
45 m_BufferFileName("")
46 {
47 m_errlog_handle = 0;
48 }
49
~CreateDcdTreeFromSnapShot()50 CreateDcdTreeFromSnapShot::~CreateDcdTreeFromSnapShot()
51 {
52 destroyDecodeTree();
53 }
54
initialise(SnapShotReader * pReader,ITraceErrorLog * pErrLogInterface)55 void CreateDcdTreeFromSnapShot::initialise(SnapShotReader *pReader, ITraceErrorLog *pErrLogInterface)
56 {
57 if((pErrLogInterface != 0) && (pReader != 0))
58 {
59 m_pReader = pReader;
60 m_pErrLogInterface = pErrLogInterface;
61 m_errlog_handle = m_pErrLogInterface->RegisterErrorSource("ss2_dcdtree");
62 m_bInit = true;
63 }
64 }
65
createDecodeTree(const std::string & SourceName,bool bPacketProcOnly)66 bool CreateDcdTreeFromSnapShot::createDecodeTree(const std::string &SourceName, bool bPacketProcOnly)
67 {
68 if(m_bInit)
69 {
70 if(!m_pReader->snapshotReadOK())
71 {
72 LogError("Supplied snapshot reader has not correctly read the snapshot.\n");
73 return false;
74 }
75
76 m_bPacketProcOnly = bPacketProcOnly;
77 Parser::TraceBufferSourceTree tree;
78
79 if(m_pReader->getTraceBufferSourceTree(SourceName, tree))
80 {
81 int numDecodersCreated = 0; // count how many we create - if none then give up.
82 uint32_t formatter_flags = OCSD_DFRMTR_FRAME_MEM_ALIGN;
83
84 /* make a note of the trace binary file name + path to ss directory */
85 m_BufferFileName = m_pReader->getSnapShotDir() + tree.buffer_info.dataFileName;
86
87 ocsd_dcd_tree_src_t src_format = tree.buffer_info.dataFormat == "source_data" ? OCSD_TRC_SRC_SINGLE : OCSD_TRC_SRC_FRAME_FORMATTED;
88
89 if (tree.buffer_info.dataFormat == "dstream_coresight")
90 formatter_flags = OCSD_DFRMTR_HAS_FSYNCS;
91
92 /* create the initial device tree */
93 // TBD: handle syncs / hsyncs data from TPIU
94 m_pDecodeTree = DecodeTree::CreateDecodeTree(src_format, formatter_flags);
95 if(m_pDecodeTree == 0)
96 {
97 LogError("Failed to create decode tree object\n");
98 return false;
99 }
100
101 // use our error logger - don't use the tree default.
102 m_pDecodeTree->setAlternateErrorLogger(m_pErrLogInterface);
103
104 if(!bPacketProcOnly)
105 {
106 m_pDecodeTree->createMemAccMapper();
107 }
108
109 /* run through each protocol source to this buffer... */
110 std::map<std::string, std::string>::iterator it = tree.source_core_assoc.begin();
111
112 while(it != tree.source_core_assoc.end())
113 {
114 Parser::Parsed *etm_dev, *core_dev;
115 if(m_pReader->getDeviceData(it->first,&etm_dev))
116 {
117 // found the device data for this device.
118
119 // see if we have a core name (STM / ITM not associated with a core);
120 std::string coreDevName = it->second;
121 if(coreDevName.size() > 0)
122 {
123 if(m_pReader->getDeviceData(coreDevName,&core_dev))
124 {
125 if(createPEDecoder(core_dev->deviceTypeName,etm_dev))
126 {
127 numDecodersCreated++;
128 if(!bPacketProcOnly &&(core_dev->dumpDefs.size() > 0))
129 {
130 processDumpfiles(core_dev->dumpDefs);
131 }
132 }
133 else
134 {
135 std::ostringstream oss;
136 oss << "Failed to create decoder for source " << it->first << ".\n";
137 LogError(oss.str());
138 }
139 }
140 else
141 {
142 // Could not find the device data for the core.
143 // unexpected - since we created the associations.
144 std::ostringstream oss;
145 oss << "Failed to get device data for source " << it->first << ".\n";
146 LogError(oss.str());
147 }
148 }
149 else
150 {
151 // none-core source
152 if(createSTDecoder(etm_dev))
153 {
154 numDecodersCreated++;
155 }
156 else
157 {
158 std::ostringstream oss;
159 oss << "Failed to create decoder for none core source " << it->first << ".\n";
160 LogError(oss.str());
161 }
162 }
163 }
164 else
165 {
166 // TBD: could not find the device data for the source.
167 // again unexpected - suggests ss format error.
168 std::ostringstream oss;
169 oss << "Failed to find device data for source " << it->first << ".\n";
170 LogError(oss.str());
171 }
172 if(src_format == OCSD_TRC_SRC_SINGLE)
173 it = tree.source_core_assoc.end();
174 else
175 it++;
176 }
177
178 if(numDecodersCreated == 0)
179 {
180 // nothing useful found
181 destroyDecodeTree();
182 }
183 }
184 else
185 {
186 std::ostringstream oss;
187 oss << "Failed to get parsed source tree for buffer " << SourceName << ".\n";
188 LogError(oss.str());
189 }
190 }
191 return (bool)(m_pDecodeTree != 0);
192 }
193
destroyDecodeTree()194 void CreateDcdTreeFromSnapShot::destroyDecodeTree()
195 {
196 if(m_pDecodeTree)
197 DecodeTree::DestroyDecodeTree(m_pDecodeTree);
198 m_pDecodeTree = 0;
199 m_pReader = 0;
200 m_pErrLogInterface = 0;
201 m_errlog_handle = 0;
202 m_BufferFileName = "";
203 }
204
LogError(const std::string & msg)205 void CreateDcdTreeFromSnapShot::LogError(const std::string &msg)
206 {
207 ocsdError err(OCSD_ERR_SEV_ERROR,OCSD_ERR_TEST_SS_TO_DECODER,msg);
208 m_pErrLogInterface->LogError(m_errlog_handle,&err);
209 }
210
LogError(const ocsdError & err)211 void CreateDcdTreeFromSnapShot::LogError(const ocsdError &err)
212 {
213 m_pErrLogInterface->LogError(m_errlog_handle,&err);
214 }
215
createPEDecoder(const std::string & coreName,Parser::Parsed * devSrc)216 bool CreateDcdTreeFromSnapShot::createPEDecoder(const std::string &coreName, Parser::Parsed *devSrc)
217 {
218 bool bCreatedDecoder = false;
219 std::string devTypeName = devSrc->deviceTypeName;
220
221 // split off .x from type name.
222 std::string::size_type pos = devTypeName.find_first_of('.');
223 if(pos != std::string::npos)
224 devTypeName = devTypeName.substr(0,pos);
225
226 // split according to protocol
227 if(devTypeName == ETMv4Protocol)
228 {
229 bCreatedDecoder = createETMv4Decoder(coreName,devSrc);
230 }
231 else if(devTypeName == ETMv3Protocol)
232 {
233 bCreatedDecoder = createETMv3Decoder(coreName,devSrc);
234 }
235 else if(devTypeName == PTMProtocol || devTypeName == PFTProtocol)
236 {
237 bCreatedDecoder = createPTMDecoder(coreName,devSrc);
238 }
239
240 return bCreatedDecoder;
241 }
242
243 // create an ETMv4 decoder based on the deviceN.ini file.
createETMv4Decoder(const std::string & coreName,Parser::Parsed * devSrc,const bool bDataChannel)244 bool CreateDcdTreeFromSnapShot::createETMv4Decoder(const std::string &coreName, Parser::Parsed *devSrc, const bool bDataChannel /* = false*/)
245 {
246 bool createdDecoder = false;
247 bool configOK = true;
248
249 // generate the config data from the device data.
250 ocsd_etmv4_cfg config;
251
252 regs_to_access_t regs_to_access[] = {
253 { ETMv4RegCfg, true, &config.reg_configr, 0 },
254 { ETMv4RegIDR, true, &config.reg_traceidr, 0 },
255 { ETMv4RegIDR0, true, &config.reg_idr0, 0 },
256 { ETMv4RegIDR1, false, &config.reg_idr1, 0x4100F403 },
257 { ETMv4RegIDR2, true, &config.reg_idr2, 0 },
258 { ETMv4RegIDR8, false, &config.reg_idr8, 0 },
259 { ETMv4RegIDR9, false, &config.reg_idr9, 0 },
260 { ETMv4RegIDR10, false, &config.reg_idr10, 0 },
261 { ETMv4RegIDR11, false, &config.reg_idr11, 0 },
262 { ETMv4RegIDR12, false, &config.reg_idr12, 0 },
263 { ETMv4RegIDR13,false, &config.reg_idr13, 0 },
264 };
265
266 // extract registers
267 configOK = getRegisters(devSrc->regDefs,sizeof(regs_to_access)/sizeof(regs_to_access_t), regs_to_access);
268
269 // extract core profile
270 if(configOK)
271 configOK = getCoreProfile(coreName,config.arch_ver,config.core_prof);
272
273 // good config - generate the decoder on the tree.
274 if(configOK)
275 {
276 ocsd_err_t err = OCSD_OK;
277 EtmV4Config configObj(&config);
278 const char *decoderName = bDataChannel ? OCSD_BUILTIN_DCD_ETMV4D : OCSD_BUILTIN_DCD_ETMV4I;
279
280 err = m_pDecodeTree->createDecoder(decoderName, m_bPacketProcOnly ? OCSD_CREATE_FLG_PACKET_PROC : OCSD_CREATE_FLG_FULL_DECODER,&configObj);
281
282 if(err == OCSD_OK)
283 createdDecoder = true;
284 else
285 {
286 std::string msg = "Snapshot processor : failed to create " + (std::string)decoderName + " decoder on decode tree.";
287 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,msg));
288 }
289 }
290
291 return createdDecoder;
292 }
293
294 // create an ETMv3 decoder based on the register values in the deviceN.ini file.
createETMv3Decoder(const std::string & coreName,Parser::Parsed * devSrc)295 bool CreateDcdTreeFromSnapShot::createETMv3Decoder(const std::string &coreName, Parser::Parsed *devSrc)
296 {
297 bool createdDecoder = false;
298 bool configOK = true;
299
300 // generate the config data from the device data.
301 ocsd_etmv3_cfg cfg_regs;
302
303 regs_to_access_t regs_to_access[] = {
304 { ETMv3PTMRegIDR, true, &cfg_regs.reg_idr, 0 },
305 { ETMv3PTMRegCR, true, &cfg_regs.reg_ctrl, 0 },
306 { ETMv3PTMRegCCER, true, &cfg_regs.reg_ccer, 0 },
307 { ETMv3PTMRegTraceIDR, true, &cfg_regs.reg_trc_id, 0}
308 };
309
310 // extract registers
311 configOK = getRegisters(devSrc->regDefs,sizeof(regs_to_access)/sizeof(regs_to_access_t), regs_to_access);
312
313 // extract core profile
314 if(configOK)
315 configOK = getCoreProfile(coreName,cfg_regs.arch_ver,cfg_regs.core_prof);
316
317 // good config - generate the decoder on the tree.
318 if(configOK)
319 {
320 EtmV3Config config(&cfg_regs);
321 ocsd_err_t err = OCSD_OK;
322 err = m_pDecodeTree->createDecoder(OCSD_BUILTIN_DCD_ETMV3, m_bPacketProcOnly ? OCSD_CREATE_FLG_PACKET_PROC : OCSD_CREATE_FLG_FULL_DECODER,&config);
323
324 if(err == OCSD_OK)
325 createdDecoder = true;
326 else
327 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,"Snapshot processor : failed to create ETMV3 decoder on decode tree."));
328 }
329 return createdDecoder;
330 }
331
createPTMDecoder(const std::string & coreName,Parser::Parsed * devSrc)332 bool CreateDcdTreeFromSnapShot::createPTMDecoder(const std::string &coreName, Parser::Parsed *devSrc)
333 {
334 bool createdDecoder = false;
335 bool configOK = true;
336
337 // generate the config data from the device data.
338
339 ocsd_ptm_cfg config;
340
341 regs_to_access_t regs_to_access[] = {
342 { ETMv3PTMRegIDR, true, &config.reg_idr, 0 },
343 { ETMv3PTMRegCR, true, &config.reg_ctrl, 0 },
344 { ETMv3PTMRegCCER, true, &config.reg_ccer, 0 },
345 { ETMv3PTMRegTraceIDR, true, &config.reg_trc_id, 0}
346 };
347
348 // extract registers
349 configOK = getRegisters(devSrc->regDefs,sizeof(regs_to_access)/sizeof(regs_to_access_t), regs_to_access);
350
351 // extract core profile
352 if(configOK)
353 configOK = getCoreProfile(coreName,config.arch_ver,config.core_prof);
354
355 // good config - generate the decoder on the tree.
356 if(configOK)
357 {
358 PtmConfig configObj(&config);
359 ocsd_err_t err = OCSD_OK;
360 err = m_pDecodeTree->createDecoder(OCSD_BUILTIN_DCD_PTM, m_bPacketProcOnly ? OCSD_CREATE_FLG_PACKET_PROC : OCSD_CREATE_FLG_FULL_DECODER,&configObj);
361
362 if(err == OCSD_OK)
363 createdDecoder = true;
364 else
365 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,"Snapshot processor : failed to create PTM decoder on decode tree."));
366 }
367 return createdDecoder;
368 }
369
createSTDecoder(Parser::Parsed * devSrc)370 bool CreateDcdTreeFromSnapShot::createSTDecoder(Parser::Parsed *devSrc)
371 {
372 bool bCreatedDecoder = false;
373 std::string devTypeName = devSrc->deviceTypeName;
374
375 // split off .x from type name.
376 std::string::size_type pos = devTypeName.find_first_of('.');
377 if(pos != std::string::npos)
378 devTypeName = devTypeName.substr(0,pos);
379
380 if(devTypeName == STMProtocol)
381 {
382 bCreatedDecoder = createSTMDecoder(devSrc);
383 }
384
385 return bCreatedDecoder;
386 }
387
createSTMDecoder(Parser::Parsed * devSrc)388 bool CreateDcdTreeFromSnapShot::createSTMDecoder(Parser::Parsed *devSrc)
389 {
390 bool createdDecoder = false;
391 bool configOK = true;
392
393 // generate the config data from the device data.
394
395 ocsd_stm_cfg config;
396
397 regs_to_access_t regs_to_access[] = {
398 { STMRegTCSR, true, &config.reg_tcsr, 0 }
399 };
400
401 configOK = getRegisters(devSrc->regDefs,sizeof(regs_to_access)/sizeof(regs_to_access_t), regs_to_access);
402 if(configOK)
403 {
404 ocsd_err_t err = OCSD_OK;
405 STMConfig configObj(&config);
406
407 err = m_pDecodeTree->createDecoder(OCSD_BUILTIN_DCD_STM, m_bPacketProcOnly ? OCSD_CREATE_FLG_PACKET_PROC : OCSD_CREATE_FLG_FULL_DECODER,&configObj);
408
409 if(err == OCSD_OK)
410 createdDecoder = true;
411 else
412 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,"Snapshot processor : failed to create STM decoder on decode tree."));
413 }
414
415 return createdDecoder;
416 }
417
418
419
420 // get a set of register values.
getRegisters(std::map<std::string,std::string,Util::CaseInsensitiveLess> & regDefs,int numRegs,regs_to_access_t * reg_access_array)421 bool CreateDcdTreeFromSnapShot::getRegisters(std::map<std::string, std::string, Util::CaseInsensitiveLess> ®Defs, int numRegs, regs_to_access_t *reg_access_array)
422 {
423 bool regsOK = true;
424
425 for(int rv = 0; rv < numRegs; rv++)
426 {
427 if(!getRegByPrefix( regDefs,reg_access_array[rv]))
428 regsOK = false;
429 }
430 return regsOK;
431 }
432
433 // strip out any parts with brackets
getRegByPrefix(std::map<std::string,std::string,Util::CaseInsensitiveLess> & regDefs,regs_to_access_t & reg_accessor)434 bool CreateDcdTreeFromSnapShot::getRegByPrefix(std::map<std::string, std::string, Util::CaseInsensitiveLess> ®Defs,
435 regs_to_access_t ®_accessor)
436 {
437 std::ostringstream oss;
438 bool bFound = false;
439 std::map<std::string, std::string, Util::CaseInsensitiveLess>::iterator it;
440 std::string prefix_cmp;
441 std::string::size_type pos;
442 std::string strval;
443
444 *reg_accessor.value = 0;
445
446 it = regDefs.begin();
447 while((it != regDefs.end()) && !bFound)
448 {
449 prefix_cmp = it->first;
450 pos = prefix_cmp.find_first_of('(');
451 if(pos != std::string::npos)
452 {
453 prefix_cmp = prefix_cmp.substr(0, pos);
454 }
455 if(prefix_cmp == reg_accessor.pszName)
456 {
457 strval = it->second;
458 bFound = true;
459 }
460 it++;
461 }
462
463 if(bFound)
464 *reg_accessor.value = strtoul(strval.c_str(),0,0);
465 else
466 {
467 ocsd_err_severity_t sev = OCSD_ERR_SEV_ERROR;
468 if(reg_accessor.failIfMissing)
469 {
470 oss << "Error:";
471 }
472 else
473 {
474 // no fail if missing - set any default and just warn.
475 bFound = true;
476 oss << "Warning: Default set for register. ";
477 sev = OCSD_ERR_SEV_WARN;
478 *reg_accessor.value = reg_accessor.val_default;
479 }
480 oss << "Missing " << reg_accessor.pszName << "\n";
481 m_pErrLogInterface->LogMessage(m_errlog_handle, sev, oss.str());
482 }
483 return bFound;
484 }
485
getCoreProfile(const std::string & coreName,ocsd_arch_version_t & arch_ver,ocsd_core_profile_t & core_prof)486 bool CreateDcdTreeFromSnapShot::getCoreProfile(const std::string &coreName, ocsd_arch_version_t &arch_ver, ocsd_core_profile_t &core_prof)
487 {
488 bool profileOK = true;
489 ocsd_arch_profile_t ap = m_arch_profiles.getArchProfile(coreName);
490 if(ap.arch != ARCH_UNKNOWN)
491 {
492 arch_ver = ap.arch;
493 core_prof = ap.profile;
494 }
495 else
496 {
497 std::ostringstream oss;
498 oss << "Unrecognized Core name " << coreName << ". Cannot evaluate profile or architecture.";
499 LogError(oss.str());
500 profileOK = false;
501 }
502 return profileOK;
503 }
504
processDumpfiles(std::vector<Parser::DumpDef> & dumps)505 void CreateDcdTreeFromSnapShot::processDumpfiles(std::vector<Parser::DumpDef> &dumps)
506 {
507 std::string dumpFilePathName;
508 std::vector<Parser::DumpDef>::const_iterator it;
509
510 it = dumps.begin();
511 while(it != dumps.end())
512 {
513 dumpFilePathName = m_pReader->getSnapShotDir() + it->path;
514 ocsd_file_mem_region_t region;
515 ocsd_err_t err = OCSD_OK;
516
517 region.start_address = it->address;
518 region.file_offset = it->offset;
519 region.region_size = it->length;
520
521 // ensure we respect optional length and offset parameter and
522 // allow multiple dump entries with same file name to define regions
523 if (!TrcMemAccessorFile::isExistingFileAccessor(dumpFilePathName))
524 err = m_pDecodeTree->addBinFileRegionMemAcc(®ion, 1, OCSD_MEM_SPACE_ANY, dumpFilePathName);
525 else
526 err = m_pDecodeTree->updateBinFileRegionMemAcc(®ion, 1, OCSD_MEM_SPACE_ANY, dumpFilePathName);
527 if(err != OCSD_OK)
528 {
529 std::ostringstream oss;
530 oss << "Failed to create memory accessor for file " << dumpFilePathName << ".";
531 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,oss.str()));
532 }
533 it++;
534 }
535 }
536
537 /* End of File ss_to_dcdtree.cpp */
538