2 * \file ocsd_dcd_tree.cpp
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * 3. Neither the name of the copyright holder nor the names of its contributors
21 * may be used to endorse or promote products derived from this software without
22 * specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "common/ocsd_dcd_tree.h"
37 #include "common/ocsd_lib_dcd_register.h"
38 #include "mem_acc/trc_mem_acc_mapper.h"
40 /***************************************************************/
41 ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger;
42 std::list<DecodeTree *> DecodeTree::s_trace_dcd_trees; /**< list of pointers to decode tree objects */
43 ocsdDefaultErrorLogger DecodeTree::s_error_logger; /**< The library default error logger */
44 TrcIDecode DecodeTree::s_instruction_decoder; /**< default instruction decode library */
46 DecodeTree *DecodeTree::CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, uint32_t formatterCfgFlags)
48 DecodeTree *dcd_tree = new (std::nothrow) DecodeTree();
51 if(dcd_tree->initialise(src_type, formatterCfgFlags))
53 s_trace_dcd_trees.push_back(dcd_tree);
64 void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree)
66 std::list<DecodeTree *>::iterator it;
67 bool bDestroyed = false;
68 it = s_trace_dcd_trees.begin();
69 while(!bDestroyed && (it != s_trace_dcd_trees.end()))
73 s_trace_dcd_trees.erase(it);
82 void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger)
85 s_i_error_logger = p_error_logger;
87 s_i_error_logger = &s_error_logger;
90 /***************************************************************/
92 DecodeTree::DecodeTree() :
93 m_i_instr_decode(&s_instruction_decoder),
97 m_frame_deformatter_root(0),
98 m_decode_elem_iter(0),
100 m_created_mapper(false)
102 for(int i = 0; i < 0x80; i++)
103 m_decode_elements[i] = 0;
106 DecodeTree::~DecodeTree()
108 destroyMemAccMapper();
109 for(uint8_t i = 0; i < 0x80; i++)
111 destroyDecodeElement(i);
113 PktPrinterFact::destroyAllPrinters(m_printer_list);
118 ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op,
119 const ocsd_trc_index_t index,
120 const uint32_t dataBlockSize,
121 const uint8_t *pDataBlock,
122 uint32_t *numBytesProcessed)
125 return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed);
126 *numBytesProcessed = 0;
127 return OCSD_RESP_FATAL_NOT_INIT;
130 /* set key interfaces - attach / replace on any existing tree components */
131 void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode)
134 DecodeTreeElement *pElem = 0;
136 pElem = getFirstElement(elemID);
139 pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode);
140 pElem = getNextElement(elemID);
144 void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access)
147 DecodeTreeElement *pElem = 0;
149 pElem = getFirstElement(elemID);
152 pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access);
153 pElem = getNextElement(elemID);
155 m_i_mem_access = i_mem_access;
158 void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem)
161 DecodeTreeElement *pElem = 0;
163 pElem = getFirstElement(elemID);
166 pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem);
167 pElem = getNextElement(elemID);
171 ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ )
173 // clean up any old one
174 destroyMemAccMapper();
180 case MEMACC_MAP_GLOBAL:
181 m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace();
185 // set the access interface
188 m_created_mapper = true;
189 setMemAccessI(m_default_mapper);
190 m_default_mapper->setErrorLog(s_i_error_logger);
193 return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM;
196 void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper)
198 destroyMemAccMapper(); // destroy any existing mapper - if decode tree created it.
199 m_default_mapper = pMapper;
202 void DecodeTree::destroyMemAccMapper()
204 if(m_default_mapper && m_created_mapper)
206 m_default_mapper->RemoveAllAccessors();
207 delete m_default_mapper;
208 m_default_mapper = 0;
209 m_created_mapper = false;
213 void DecodeTree::logMappedRanges()
216 m_default_mapper->logMappedRanges();
219 /* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */
220 ocsd_err_t DecodeTree::addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length)
222 if(!hasMemAccMapper())
223 return OCSD_ERR_NOT_INIT;
225 // need a valid memory buffer, and a least enough bytes for one opcode.
226 if((p_mem_buffer == 0) || (mem_length < 4))
227 return OCSD_ERR_INVALID_PARAM_VAL;
229 TrcMemAccessorBase *p_accessor;
230 ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length);
233 TrcMemAccBufPtr *pMBuffAcc = dynamic_cast<TrcMemAccBufPtr *>(p_accessor);
236 pMBuffAcc->setMemSpace(mem_space);
237 err = m_default_mapper->AddAccessor(p_accessor,0);
240 err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
243 TrcMemAccFactory::DestroyAccessor(p_accessor);
248 ocsd_err_t DecodeTree::addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
250 if(!hasMemAccMapper())
251 return OCSD_ERR_NOT_INIT;
253 if(filepath.length() == 0)
254 return OCSD_ERR_INVALID_PARAM_VAL;
256 TrcMemAccessorBase *p_accessor;
257 ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,address);
261 TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor);
264 pAcc->setMemSpace(mem_space);
265 err = m_default_mapper->AddAccessor(pAcc,0);
268 err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
271 TrcMemAccFactory::DestroyAccessor(p_accessor);
277 ocsd_err_t DecodeTree::addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
279 if(!hasMemAccMapper())
280 return OCSD_ERR_NOT_INIT;
282 if((region_array == 0) || (num_regions == 0) || (filepath.length() == 0))
283 return OCSD_ERR_INVALID_PARAM_VAL;
285 TrcMemAccessorBase *p_accessor;
286 int curr_region_idx = 0;
288 // add first region during the creation of the file accessor.
289 ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,region_array[curr_region_idx].start_address,region_array[curr_region_idx].file_offset, region_array[curr_region_idx].region_size);
292 TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor);
295 // add additional regions to the file accessor.
297 while(curr_region_idx < num_regions)
299 pAcc->AddOffsetRange(region_array[curr_region_idx].start_address,
300 region_array[curr_region_idx].region_size,
301 region_array[curr_region_idx].file_offset);
304 pAcc->setMemSpace(mem_space);
306 // add the accessor to the map.
307 err = m_default_mapper->AddAccessor(pAcc,0);
310 err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
313 TrcMemAccFactory::DestroyAccessor(p_accessor);
318 ocsd_err_t DecodeTree::updateBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
320 if (!hasMemAccMapper())
321 return OCSD_ERR_NOT_INIT;
323 if ((region_array == 0) || (num_regions == 0) || (filepath.length() == 0))
324 return OCSD_ERR_INVALID_PARAM_VAL;
326 TrcMemAccessorFile *pAcc = TrcMemAccessorFile::getExistingFileAccessor(filepath);
328 return OCSD_ERR_INVALID_PARAM_VAL;
330 int curr_region_idx = 0;
331 while (curr_region_idx < num_regions)
334 if (!pAcc->addrStartOfRange(region_array[curr_region_idx].start_address))
336 // ensure adds cleanly
337 if (!pAcc->AddOffsetRange(region_array[curr_region_idx].start_address,
338 region_array[curr_region_idx].region_size,
339 region_array[curr_region_idx].file_offset))
340 return OCSD_ERR_INVALID_PARAM_VAL; // otherwise bail out
346 ocsd_err_t DecodeTree::initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address,
347 const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, const void *p_context)
349 if(!hasMemAccMapper())
350 return OCSD_ERR_NOT_INIT;
353 return OCSD_ERR_INVALID_PARAM_VAL;
355 TrcMemAccessorBase *p_accessor;
356 ocsd_err_t err = TrcMemAccFactory::CreateCBAccessor(&p_accessor, st_address, en_address, mem_space);
359 TrcMemAccCB *pCBAcc = dynamic_cast<TrcMemAccCB *>(p_accessor);
363 pCBAcc->setCBIDIfFn((Fn_MemAccID_CB)p_cb_func, p_context);
365 pCBAcc->setCBIfFn((Fn_MemAcc_CB)p_cb_func, p_context);
367 err = m_default_mapper->AddAccessor(p_accessor,0);
370 err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
373 TrcMemAccFactory::DestroyAccessor(p_accessor);
378 ocsd_err_t DecodeTree::addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context)
380 return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, false, p_context);
383 ocsd_err_t DecodeTree::addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_CB p_cb_func, const void *p_context)
385 return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, true, p_context);
388 ocsd_err_t DecodeTree::removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space)
390 if(!hasMemAccMapper())
391 return OCSD_ERR_NOT_INIT;
392 return m_default_mapper->RemoveAccessorByAddress(address,mem_space,0);
395 ocsd_err_t DecodeTree::createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig)
397 ocsd_err_t err = OCSD_OK;
398 IDecoderMngr *pDecoderMngr = 0;
399 TraceComponent *pTraceComp = 0;
400 int crtFlags = createFlags;
402 uint8_t CSID = 0; // default for single stream decoder (no deformatter) - we ignore the ID
405 CSID = pConfig->getTraceID();
406 crtFlags |= OCSD_CREATE_FLG_INST_ID;
409 // create the decode element to attach to the channel.
410 if((err = createDecodeElement(CSID)) != OCSD_OK)
413 // get the libary decoder register.
414 OcsdLibDcdRegister * lib_reg = OcsdLibDcdRegister::getDecoderRegister();
416 return OCSD_ERR_NOT_INIT;
418 // find the named decoder
419 if((err = lib_reg->getDecoderMngrByName(decoderName,&pDecoderMngr)) != OCSD_OK)
422 // got the decoder...
423 if((err = pDecoderMngr->createDecoder(crtFlags,(int)CSID,pConfig,&pTraceComp)) != OCSD_OK)
426 m_decode_elements[CSID]->SetDecoderElement(decoderName, pDecoderMngr, pTraceComp, true);
428 // always attach an error logger
430 err = pDecoderMngr->attachErrorLogger(pTraceComp,DecodeTree::s_i_error_logger);
432 // if we created a packet decoder it may need additional components.
433 if(crtFlags & OCSD_CREATE_FLG_FULL_DECODER)
435 if(m_i_instr_decode && (err == OCSD_OK))
436 err = pDecoderMngr->attachInstrDecoder(pTraceComp,m_i_instr_decode);
438 if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if instruction decoder refused
441 if(m_i_mem_access && (err == OCSD_OK))
442 err = pDecoderMngr->attachMemAccessor(pTraceComp,m_i_mem_access);
444 if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if mem accessor refused
447 if( m_i_gen_elem_out && (err == OCSD_OK))
448 err = pDecoderMngr->attachOutputSink(pTraceComp,m_i_gen_elem_out);
451 // finally attach the packet processor input to the demux output channel
454 ITrcDataIn *pDataIn = 0;
455 if((err = pDecoderMngr->getDataInputI(pTraceComp,&pDataIn)) == OCSD_OK)
457 // got the interface -> attach to demux, or direct to input of decode tree
459 err = m_frame_deformatter_root->getIDStreamAttachPt(CSID)->attach(pDataIn);
461 m_i_decoder_root = pDataIn;
467 destroyDecodeElement(CSID); // will destroy decoder as well.
472 ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID)
474 ocsd_err_t err = OCSD_OK;
475 uint8_t localID = CSID;
476 if(!usingFormatter())
479 if(usingFormatter() && !OCSD_IS_VALID_CS_SRC_ID(CSID))
480 err = OCSD_ERR_INVALID_ID;
483 destroyDecodeElement(localID);
488 DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const
490 DecodeTreeElement *ret_elem = 0;
491 if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID))
493 ret_elem = m_decode_elements[CSID];
496 ret_elem = m_decode_elements[0]; // ID 0 is used if single leaf tree.
500 DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID)
502 m_decode_elem_iter = 0;
503 return getNextElement(elemID);
506 DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID)
508 DecodeTreeElement *ret_elem = 0;
510 if(m_decode_elem_iter < 0x80)
512 // find a none zero entry or end of range
513 while((m_decode_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80))
514 m_decode_elem_iter++;
516 // return entry unless end of range
517 if(m_decode_elem_iter < 0x80)
519 ret_elem = m_decode_elements[m_decode_elem_iter];
520 elemID = m_decode_elem_iter;
521 m_decode_elem_iter++;
527 bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags)
530 m_dcd_tree_type = type;
531 if(type == OCSD_TRC_SRC_FRAME_FORMATTED)
533 // frame formatted - we want to create the deformatter and hook it up
534 m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder();
535 if(m_frame_deformatter_root)
537 m_frame_deformatter_root->Configure(formatterCfgFlags);
538 m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger);
539 m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root);
547 void DecodeTree::setSingleRoot(TrcPktProcI *pComp)
549 m_i_decoder_root = static_cast<ITrcDataIn*>(pComp);
552 ocsd_err_t DecodeTree::createDecodeElement(const uint8_t CSID)
554 ocsd_err_t err = OCSD_ERR_INVALID_ID;
557 if(m_decode_elements[CSID] == 0)
559 m_decode_elements[CSID] = new (std::nothrow) DecodeTreeElement();
560 if(m_decode_elements[CSID] == 0)
566 err = OCSD_ERR_ATTACH_TOO_MANY;
571 void DecodeTree::destroyDecodeElement(const uint8_t CSID)
575 if(m_decode_elements[CSID] != 0)
577 m_decode_elements[CSID]->DestroyElem();
578 delete m_decode_elements[CSID];
579 m_decode_elements[CSID] = 0;
584 ocsd_err_t DecodeTree::setIDFilter(std::vector<uint8_t> &ids)
586 ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
589 err = m_frame_deformatter_root->OutputFilterAllIDs(false);
591 err = m_frame_deformatter_root->OutputFilterIDs(ids,true);
596 ocsd_err_t DecodeTree::clearIDFilter()
598 ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
601 err = m_frame_deformatter_root->OutputFilterAllIDs(true);
606 /** add a protocol packet printer */
607 ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter)
609 ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL;
610 DecodeTreeElement *pElement = getDecoderElement(CSID);
613 ocsd_trace_protocol_t protocol = pElement->getProtocol();
614 ItemPrinter *pPrinter;
616 pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID);
619 pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger());
622 case OCSD_PROTOCOL_ETMV4I:
624 PacketPrinter<EtmV4ITrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV4ITrcPacket> *>(pPrinter);
626 err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV4ITrcPacket> *)pTPrinter);
628 err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV4ITrcPacket> *)pTPrinter);
632 case OCSD_PROTOCOL_ETMV3:
634 PacketPrinter<EtmV3TrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV3TrcPacket> *>(pPrinter);
636 err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV3TrcPacket> *)pTPrinter);
638 err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV3TrcPacket> *)pTPrinter);
642 case OCSD_PROTOCOL_PTM:
644 PacketPrinter<PtmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<PtmTrcPacket> *>(pPrinter);
646 err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<PtmTrcPacket> *)pTPrinter);
648 err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<PtmTrcPacket> *)pTPrinter);
652 case OCSD_PROTOCOL_STM:
654 PacketPrinter<StmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<StmTrcPacket> *>(pPrinter);
656 err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<StmTrcPacket> *)pTPrinter);
658 err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<StmTrcPacket> *)pTPrinter);
663 err = OCSD_ERR_NO_PROTOCOL;
670 *ppPrinter = pPrinter;
673 PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter);
679 /** add a raw frame printer */
680 ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags)
682 ocsd_err_t err = OCSD_ERR_MEM;
683 RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList());
686 pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
687 TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter();
688 uint32_t cfgFlags = pFrameDecoder->getConfigFlags();
689 cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT));
690 pFrameDecoder->Configure(cfgFlags);
691 err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter);
692 if (ppPrinter && (err==OCSD_OK))
693 *ppPrinter = pPrinter;
698 /** add a generic element output printer */
699 ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter)
701 ocsd_err_t err = OCSD_ERR_MEM;
702 TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList());
705 pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
706 setGenTraceElemOutI(pPrinter);
709 *ppPrinter = pPrinter;
715 /* End of File ocsd_dcd_tree.cpp */