1/* 2 * File: ConversionController.cpp 3 * 4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. 5 * See included license file for license details. 6 */ 7 8#include "ConversionController.h" 9#include <stdexcept> 10#include "EvalContext.h" 11#include "ElftosbErrors.h" 12#include "GlobMatcher.h" 13#include "ExcludesListMatcher.h" 14#include "BootImageGenerator.h" 15#include "EncoreBootImageGenerator.h" 16#include "Logging.h" 17#include "OptionDictionary.h" 18#include "format_string.h" 19#include "SearchPath.h" 20#include "DataSourceImager.h" 21#include "IVTDataSource.h" 22#include <algorithm> 23 24//! Set to 1 to cause the ConversionController to print information about 25//! the values that it processes (options, constants, etc.). 26#define PRINT_VALUES 1 27 28using namespace elftosb; 29 30// Define the parser function prototype; 31extern int yyparse(ElftosbLexer * lexer, CommandFileASTNode ** resultAST); 32 33bool elftosb::g_enableHABSupport = false; 34 35ConversionController::ConversionController() 36: OptionDictionary(), 37 m_commandFilePath(), 38 m_ast(), 39 m_defaultSource(0) 40{ 41 m_context.setSourceFileManager(this); 42} 43 44ConversionController::~ConversionController() 45{ 46 // clean up sources 47 source_map_t::iterator it = m_sources.begin(); 48 for (; it != m_sources.end(); ++it) 49 { 50 if (it->second) 51 { 52 delete it->second; 53 } 54 } 55} 56 57void ConversionController::setCommandFilePath(const std::string & path) 58{ 59 m_commandFilePath = new std::string(path); 60} 61 62//! The paths provided to this method are added to an array and accessed with the 63//! "extern(N)" notation in the command file. So the path provided in the third 64//! call to addExternalFilePath() will be found with N=2 in the source definition. 65void ConversionController::addExternalFilePath(const std::string & path) 66{ 67 m_externPaths.push_back(path); 68} 69 70bool ConversionController::hasSourceFile(const std::string & name) 71{ 72 return m_sources.find(name) != m_sources.end(); 73} 74 75SourceFile * ConversionController::getSourceFile(const std::string & name) 76{ 77 if (!hasSourceFile(name)) 78 { 79 return NULL; 80 } 81 82 return m_sources[name]; 83} 84 85SourceFile * ConversionController::getDefaultSourceFile() 86{ 87 return m_defaultSource; 88} 89 90//! These steps are executed while running this method: 91//! - The command file is parsed into an abstract syntax tree. 92//! - The list of options is extracted. 93//! - Constant expressions are evaluated. 94//! - The list of source files is extracted and source file objects created. 95//! - Section definitions are extracted. 96//! 97//! This method does not produce any output. It processes the input files and 98//! builds a representation of the output in memory. Use the generateOutput() method 99//! to produce a BootImage object after this method returns. 100//! 101//! \note This method is \e not reentrant. And in fact, the whole class is not designed 102//! to be reentrant. 103//! 104//! \exception std::runtime_error Any number of problems will cause this exception to 105//! be thrown. 106//! 107//! \see parseCommandFile() 108//! \see processOptions() 109//! \see processConstants() 110//! \see processSources() 111//! \see processSections() 112void ConversionController::run() 113{ 114#if PRINT_VALUES 115 Log::SetOutputLevel debugLevel(Logger::DEBUG2); 116#endif 117 118 parseCommandFile(); 119 assert(m_ast); 120 121 ListASTNode * blocks = m_ast->getBlocks(); 122 if (!blocks) 123 { 124 throw std::runtime_error("command file has no blocks"); 125 } 126 127 ListASTNode::iterator it = blocks->begin(); 128 for (; it != blocks->end(); ++it) 129 { 130 ASTNode * node = *it; 131 132 // Handle an options block. 133 OptionsBlockASTNode * options = dynamic_cast<OptionsBlockASTNode *>(node); 134 if (options) 135 { 136 processOptions(options->getOptions()); 137 continue; 138 } 139 140 // Handle a constants block. 141 ConstantsBlockASTNode * constants = dynamic_cast<ConstantsBlockASTNode *>(node); 142 if (constants) 143 { 144 processConstants(constants->getConstants()); 145 continue; 146 } 147 148 // Handle a sources block. 149 SourcesBlockASTNode * sources = dynamic_cast<SourcesBlockASTNode *>(node); 150 if (sources) 151 { 152 processSources(sources->getSources()); 153 } 154 } 155 156 processSections(m_ast->getSections()); 157} 158 159//! Opens the command file and runs it through the lexer and parser. The resulting 160//! abstract syntax tree is held in the m_ast member variable. After parsing, the 161//! command file is closed. 162//! 163//! \exception std::runtime_error Several problems will cause this exception to be 164//! raised, including an unspecified command file path or an error opening the 165//! file. 166void ConversionController::parseCommandFile() 167{ 168 if (!m_commandFilePath) 169 { 170 throw std::runtime_error("no command file path was provided"); 171 } 172 173 // Search for command file 174 std::string actualPath; 175 bool found = PathSearcher::getGlobalSearcher().search(*m_commandFilePath, PathSearcher::kFindFile, true, actualPath); 176 if (!found) 177 { 178 throw runtime_error(format_string("unable to find command file %s\n", m_commandFilePath->c_str())); 179 } 180 181 // open command file 182 std::ifstream commandFile(actualPath.c_str(), ios_base::in | ios_base::binary); 183 if (!commandFile.is_open()) 184 { 185 throw std::runtime_error("could not open command file"); 186 } 187 188 try 189 { 190 // create lexer instance 191 ElftosbLexer lexer(commandFile); 192// testLexer(lexer); 193 194 CommandFileASTNode * ast = NULL; 195 int result = yyparse(&lexer, &ast); 196 m_ast = ast; 197 198 // check results 199 if (result || !m_ast) 200 { 201 throw std::runtime_error("failed to parse command file"); 202 } 203 204 // dump AST 205// m_ast->printTree(0); 206 207 // close command file 208 commandFile.close(); 209 } 210 catch (...) 211 { 212 // close command file 213 commandFile.close(); 214 215 // rethrow exception 216 throw; 217 } 218} 219 220//! Iterates over the option definition AST nodes. elftosb::Value objects are created for 221//! each option value and added to the option dictionary. 222//! 223//! \exception std::runtime_error Various errors will cause this exception to be thrown. These 224//! include AST nodes being an unexpected type or expression not evaluating to integers. 225void ConversionController::processOptions(ListASTNode * options) 226{ 227 if (!options) 228 { 229 return; 230 } 231 232 ListASTNode::iterator it = options->begin(); 233 for (; it != options->end(); ++it) 234 { 235 std::string ident; 236 Value * value = convertAssignmentNodeToValue(*it, ident); 237 238 // check if this option has already been set 239 if (hasOption(ident)) 240 { 241 throw semantic_error(format_string("line %d: option already set", (*it)->getFirstLine())); 242 } 243 244 // now save the option value in our map 245 if (value) 246 { 247 setOption(ident, value); 248 } 249 } 250} 251 252//! Scans the constant definition AST nodes, evaluates expression nodes by calling their 253//! elftosb::ExprASTNode::reduce() method, and updates the evaluation context member so 254//! those constant values can be used in other expressions. 255//! 256//! \exception std::runtime_error Various errors will cause this exception to be thrown. These 257//! include AST nodes being an unexpected type or expression not evaluating to integers. 258void ConversionController::processConstants(ListASTNode * constants) 259{ 260 if (!constants) 261 { 262 return; 263 } 264 265 ListASTNode::iterator it = constants->begin(); 266 for (; it != constants->end(); ++it) 267 { 268 std::string ident; 269 Value * value = convertAssignmentNodeToValue(*it, ident); 270 271 SizedIntegerValue * intValue = dynamic_cast<SizedIntegerValue*>(value); 272 if (!intValue) 273 { 274 throw semantic_error(format_string("line %d: constant value is an invalid type", (*it)->getFirstLine())); 275 } 276 277//#if PRINT_VALUES 278// Log::log("constant "); 279// printIntConstExpr(ident, intValue); 280//#endif 281 282 // record this constant's value in the evaluation context 283 m_context.setVariable(ident, intValue->getValue(), intValue->getWordSize()); 284 } 285} 286 287//! \exception std::runtime_error Various errors will cause this exception to be thrown. These 288//! include AST nodes being an unexpected type or expression not evaluating to integers. 289//! 290//! \todo Handle freeing of dict if an exception occurs. 291void ConversionController::processSources(ListASTNode * sources) 292{ 293 if (!sources) 294 { 295 return; 296 } 297 298 ListASTNode::iterator it = sources->begin(); 299 for (; it != sources->end(); ++it) 300 { 301 SourceDefASTNode * node = dynamic_cast<SourceDefASTNode*>(*it); 302 if (!node) 303 { 304 throw semantic_error(format_string("line %d: source definition node is an unexpected type", node->getFirstLine())); 305 } 306 307 // get source name and check if it has already been defined 308 std::string * name = node->getName(); 309 if (m_sources.find(*name) != m_sources.end()) 310 { 311 // can't define a source multiple times 312 throw semantic_error(format_string("line %d: source already defined", node->getFirstLine())); 313 } 314 315 // convert attributes into an option dict 316 OptionDictionary * dict = new OptionDictionary(this); 317 ListASTNode * attrsNode = node->getAttributes(); 318 if (attrsNode) 319 { 320 ListASTNode::iterator attrIt = attrsNode->begin(); 321 for (; attrIt != attrsNode->end(); ++attrIt) 322 { 323 std::string ident; 324 Value * value = convertAssignmentNodeToValue(*attrIt, ident); 325 dict->setOption(ident, value); 326 } 327 } 328 329 // figure out which type of source definition this is 330 PathSourceDefASTNode * pathNode = dynamic_cast<PathSourceDefASTNode*>(node); 331 ExternSourceDefASTNode * externNode = dynamic_cast<ExternSourceDefASTNode*>(node); 332 SourceFile * file = NULL; 333 334 if (pathNode) 335 { 336 // explicit path 337 std::string * path = pathNode->getPath(); 338 339#if PRINT_VALUES 340 Log::log("source %s => path(%s)\n", name->c_str(), path->c_str()); 341#endif 342 343 try 344 { 345 file = SourceFile::openFile(*path); 346 } 347 catch (...) 348 { 349 // file doesn't exist 350 Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", path->c_str()); 351 m_failedSources.push_back(*name); 352 } 353 } 354 else if (externNode) 355 { 356 // externally provided path 357 ExprASTNode * expr = externNode->getSourceNumberExpr()->reduce(m_context); 358 IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(expr); 359 if (!intConst) 360 { 361 throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine())); 362 } 363 364 uint32_t externalFileNumber = static_cast<uint32_t>(intConst->getValue()); 365 366 // make sure the extern number is valid 367 if (externalFileNumber >= 0 && externalFileNumber < m_externPaths.size()) 368 { 369 370#if PRINT_VALUES 371 Log::log("source %s => extern(%d=%s)\n", name->c_str(), externalFileNumber, m_externPaths[externalFileNumber].c_str()); 372#endif 373 374 try 375 { 376 file = SourceFile::openFile(m_externPaths[externalFileNumber]); 377 } 378 catch (...) 379 { 380 Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", m_externPaths[externalFileNumber].c_str()); 381 m_failedSources.push_back(*name); 382 } 383 } 384 } 385 else 386 { 387 throw semantic_error(format_string("line %d: unexpected source definition node type", node->getFirstLine())); 388 } 389 390 if (file) 391 { 392 // set options 393 file->setOptions(dict); 394 395 // stick the file object in the source map 396 m_sources[*name] = file; 397 } 398 } 399} 400 401void ConversionController::processSections(ListASTNode * sections) 402{ 403 if (!sections) 404 { 405 Log::log(Logger::WARNING, "warning: no sections were defined in command file"); 406 return; 407 } 408 409 ListASTNode::iterator it = sections->begin(); 410 for (; it != sections->end(); ++it) 411 { 412 SectionContentsASTNode * node = dynamic_cast<SectionContentsASTNode*>(*it); 413 if (!node) 414 { 415 throw semantic_error(format_string("line %d: section definition is unexpected type", node->getFirstLine())); 416 } 417 418 // evaluate section number 419 ExprASTNode * idExpr = node->getSectionNumberExpr()->reduce(m_context); 420 IntConstExprASTNode * idConst = dynamic_cast<IntConstExprASTNode*>(idExpr); 421 if (!idConst) 422 { 423 throw semantic_error(format_string("line %d: section number did not evaluate to an integer", idExpr->getFirstLine())); 424 } 425 uint32_t sectionID = idConst->getValue(); 426 427 // Create options context for this section. The options context has the 428 // conversion controller as its parent context so it will inherit global options. 429 // The context will be set in the section after the section is created below. 430 OptionDictionary * optionsDict = new OptionDictionary(this); 431 ListASTNode * attrsNode = node->getOptions(); 432 if (attrsNode) 433 { 434 ListASTNode::iterator attrIt = attrsNode->begin(); 435 for (; attrIt != attrsNode->end(); ++attrIt) 436 { 437 std::string ident; 438 Value * value = convertAssignmentNodeToValue(*attrIt, ident); 439 optionsDict->setOption(ident, value); 440 } 441 } 442 443 // Now create the actual section object based on its type. 444 OutputSection * outputSection = NULL; 445 BootableSectionContentsASTNode * bootableSection; 446 DataSectionContentsASTNode * dataSection; 447 if (bootableSection = dynamic_cast<BootableSectionContentsASTNode*>(node)) 448 { 449 // process statements into a sequence of operations 450 ListASTNode * statements = bootableSection->getStatements(); 451 OperationSequence * sequence = convertStatementList(statements); 452 453#if 0 454 Log::log("section ID = %d\n", sectionID); 455 statements->printTree(0); 456 457 Log::log("sequence has %d operations\n", sequence->getCount()); 458 OperationSequence::iterator_t it = sequence->begin(); 459 for (; it != sequence->end(); ++it) 460 { 461 Operation * op = *it; 462 Log::log("op = %p\n", op); 463 } 464#endif 465 466 // create the output section and add it to the list 467 OperationSequenceSection * opSection = new OperationSequenceSection(sectionID); 468 opSection->setOptions(optionsDict); 469 opSection->getSequence() += sequence; 470 outputSection = opSection; 471 } 472 else if (dataSection = dynamic_cast<DataSectionContentsASTNode*>(node)) 473 { 474 outputSection = convertDataSection(dataSection, sectionID, optionsDict); 475 } 476 else 477 { 478 throw semantic_error(format_string("line %d: unexpected section contents type", node->getFirstLine())); 479 } 480 481 if (outputSection) 482 { 483 m_outputSections.push_back(outputSection); 484 } 485 } 486} 487 488//! Creates an instance of BinaryDataSection from the AST node passed in the 489//! \a dataSection parameter. The section-specific options for this node will 490//! have already been converted into an OptionDictionary, the one passed in 491//! the \a optionsDict parameter. 492//! 493//! The \a dataSection node will have as its contents one of the AST node 494//! classes that represents a source of data. The member function 495//! createSourceFromNode() is used to convert this AST node into an 496//! instance of a DataSource subclass. Then the method imageDataSource() 497//! converts the segments of the DataSource into a raw binary buffer that 498//! becomes the contents of the BinaryDataSection this is returned. 499//! 500//! \param dataSection The AST node for the data section. 501//! \param sectionID Unique tag value the user has assigned to this section. 502//! \param optionsDict Options that apply only to this section. This dictionary 503//! will be assigned as the options dictionary for the resulting section 504//! object. Its parent is the conversion controller itself. 505//! \return An instance of BinaryDataSection. Its contents are a contiguous 506//! binary representation of the contents of \a dataSection. 507OutputSection * ConversionController::convertDataSection(DataSectionContentsASTNode * dataSection, uint32_t sectionID, OptionDictionary * optionsDict) 508{ 509 // Create a data source from the section contents AST node. 510 ASTNode * contents = dataSection->getContents(); 511 DataSource * dataSource = createSourceFromNode(contents); 512 513 // Convert the data source to a raw buffer. 514 DataSourceImager imager; 515 imager.addDataSource(dataSource); 516 517 // Then make a data section from the buffer. 518 BinaryDataSection * resultSection = new BinaryDataSection(sectionID); 519 resultSection->setOptions(optionsDict); 520 if (imager.getLength()) 521 { 522 resultSection->setData(imager.getData(), imager.getLength()); 523 } 524 525 return resultSection; 526} 527 528//! @param node The AST node instance for the assignment expression. 529//! @param[out] ident Upon exit this string will be set the the left hand side of the 530//! assignment expression, the identifier name. 531//! 532//! @return An object that is a subclass of Value is returned. The specific subclass will 533//! depend on the type of the right hand side of the assignment expression whose AST 534//! node was provided in the @a node argument. 535//! 536//! @exception semantic_error Thrown for any error where an AST node is an unexpected type. 537//! This may be the @a node argument itself, if it is not an AssignmentASTNode. Or it 538//! may be an unexpected type for either the right or left hand side of the assignment. 539//! The message for the exception will contain a description of the error. 540Value * ConversionController::convertAssignmentNodeToValue(ASTNode * node, std::string & ident) 541{ 542 Value * resultValue = NULL; 543 544 // each item of the options list should be an assignment node 545 AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(node); 546 if (!node) 547 { 548 throw semantic_error(format_string("line %d: node is wrong type", assignmentNode->getFirstLine())); 549 } 550 551 // save the left hand side (the identifier) into ident 552 ident = *assignmentNode->getIdent(); 553 554 // get the right hand side and convert it to a Value instance 555 ASTNode * valueNode = assignmentNode->getValue(); 556 StringConstASTNode * str; 557 ExprASTNode * expr; 558 if (str = dynamic_cast<StringConstASTNode*>(valueNode)) 559 { 560 // the option value is a string constant 561 resultValue = new StringValue(str->getString()); 562 563//#if PRINT_VALUES 564// Log::log("option %s => \'%s\'\n", ident->c_str(), str->getString()->c_str()); 565//#endif 566 } 567 else if (expr = dynamic_cast<ExprASTNode*>(valueNode)) 568 { 569 ExprASTNode * reducedExpr = expr->reduce(m_context); 570 IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(reducedExpr); 571 if (!intConst) 572 { 573 throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine())); 574 } 575 576//#if PRINT_VALUES 577// Log::log("option "); 578// printIntConstExpr(*ident, intConst); 579//#endif 580 581 resultValue = new SizedIntegerValue(intConst->getValue(), intConst->getSize()); 582 } 583 else 584 { 585 throw semantic_error(format_string("line %d: right hand side node is an unexpected type", valueNode->getFirstLine())); 586 } 587 588 return resultValue; 589} 590 591//! Builds up a sequence of Operation objects that are equivalent to the 592//! statements in the \a statements list. The statement list is simply iterated 593//! over and the results of convertOneStatement() are used to build up 594//! the final result sequence. 595//! 596//! \see convertOneStatement() 597OperationSequence * ConversionController::convertStatementList(ListASTNode * statements) 598{ 599 OperationSequence * resultSequence = new OperationSequence(); 600 ListASTNode::iterator it = statements->begin(); 601 for (; it != statements->end(); ++it) 602 { 603 StatementASTNode * statement = dynamic_cast<StatementASTNode*>(*it); 604 if (!statement) 605 { 606 throw semantic_error(format_string("line %d: statement node is unexpected type", (*it)->getFirstLine())); 607 } 608 609 // convert this statement and append it to the result 610 OperationSequence * sequence = convertOneStatement(statement); 611 if (sequence) 612 { 613 *resultSequence += sequence; 614 } 615 } 616 617 return resultSequence; 618} 619 620//! Uses C++ RTTI to identify the particular subclass of StatementASTNode that 621//! the \a statement argument matches. Then the appropriate conversion method 622//! is called. 623//! 624//! \see convertLoadStatement() 625//! \see convertCallStatement() 626//! \see convertFromStatement() 627OperationSequence * ConversionController::convertOneStatement(StatementASTNode * statement) 628{ 629 // see if it's a load statement 630 LoadStatementASTNode * load = dynamic_cast<LoadStatementASTNode*>(statement); 631 if (load) 632 { 633 return convertLoadStatement(load); 634 } 635 636 // see if it's a call statement 637 CallStatementASTNode * call = dynamic_cast<CallStatementASTNode*>(statement); 638 if (call) 639 { 640 return convertCallStatement(call); 641 } 642 643 // see if it's a from statement 644 FromStatementASTNode * from = dynamic_cast<FromStatementASTNode*>(statement); 645 if (from) 646 { 647 return convertFromStatement(from); 648 } 649 650 // see if it's a mode statement 651 ModeStatementASTNode * mode = dynamic_cast<ModeStatementASTNode*>(statement); 652 if (mode) 653 { 654 return convertModeStatement(mode); 655 } 656 657 // see if it's an if statement 658 IfStatementASTNode * ifStmt = dynamic_cast<IfStatementASTNode*>(statement); 659 if (ifStmt) 660 { 661 return convertIfStatement(ifStmt); 662 } 663 664 // see if it's a message statement 665 MessageStatementASTNode * messageStmt = dynamic_cast<MessageStatementASTNode*>(statement); 666 if (messageStmt) 667 { 668 // Message statements don't produce operation sequences. 669 handleMessageStatement(messageStmt); 670 return NULL; 671 } 672 673 // didn't match any of the expected statement types 674 throw semantic_error(format_string("line %d: unexpected statement type", statement->getFirstLine())); 675 return NULL; 676} 677 678//! Possible load data node types: 679//! - StringConstASTNode 680//! - ExprASTNode 681//! - SourceASTNode 682//! - SectionMatchListASTNode 683//! 684//! Possible load target node types: 685//! - SymbolASTNode 686//! - NaturalLocationASTNode 687//! - AddressRangeASTNode 688OperationSequence * ConversionController::convertLoadStatement(LoadStatementASTNode * statement) 689{ 690 LoadOperation * op = NULL; 691 692 try 693 { 694 // build load operation from source and target 695 op = new LoadOperation(); 696 op->setSource(createSourceFromNode(statement->getData())); 697 op->setTarget(createTargetFromNode(statement->getTarget())); 698 op->setDCDLoad(statement->isDCDLoad()); 699 700 return new OperationSequence(op); 701 } 702 catch (...) 703 { 704 if (op) 705 { 706 delete op; 707 } 708 throw; 709 } 710} 711 712//! Possible call target node types: 713//! - SymbolASTNode 714//! - ExprASTNode 715//! 716//! Possible call argument node types: 717//! - ExprASTNode 718//! - NULL 719OperationSequence * ConversionController::convertCallStatement(CallStatementASTNode * statement) 720{ 721 ExecuteOperation * op = NULL; 722 723 try 724 { 725 // create operation from AST nodes 726 op = new ExecuteOperation(); 727 728 bool isHAB = statement->isHAB(); 729 730 op->setTarget(createTargetFromNode(statement->getTarget())); 731 732 // set argument value, which defaults to 0 if no expression was provided 733 uint32_t arg = 0; 734 ASTNode * argNode = statement->getArgument(); 735 if (argNode) 736 { 737 ExprASTNode * argExprNode = dynamic_cast<ExprASTNode*>(argNode); 738 if (!argExprNode) 739 { 740 throw semantic_error(format_string("line %d: call argument is unexpected type", argNode->getFirstLine())); 741 } 742 argExprNode = argExprNode->reduce(m_context); 743 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(argExprNode); 744 if (!intNode) 745 { 746 throw semantic_error(format_string("line %d: call argument did not evaluate to an integer", argExprNode->getFirstLine())); 747 } 748 749 arg = intNode->getValue(); 750 } 751 op->setArgument(arg); 752 753 // set call type 754 switch (statement->getCallType()) 755 { 756 case CallStatementASTNode::kCallType: 757 op->setExecuteType(ExecuteOperation::kCall); 758 break; 759 case CallStatementASTNode::kJumpType: 760 op->setExecuteType(ExecuteOperation::kJump); 761 break; 762 } 763 764 // Set the HAB mode flag. 765 op->setIsHAB(isHAB); 766 767 return new OperationSequence(op); 768 } 769 catch (...) 770 { 771 // delete op and rethrow exception 772 if (op) 773 { 774 delete op; 775 } 776 throw; 777 } 778} 779 780//! First this method sets the default source to the source identified in 781//! the from statement. Then the statements within the from block are 782//! processed recursively by calling convertStatementList(). The resulting 783//! operation sequence is returned. 784OperationSequence * ConversionController::convertFromStatement(FromStatementASTNode * statement) 785{ 786 if (m_defaultSource) 787 { 788 throw semantic_error(format_string("line %d: from statements cannot be nested", statement->getFirstLine())); 789 } 790 791 // look up source file instance 792 std::string * fromSourceName = statement->getSourceName(); 793 assert(fromSourceName); 794 795 // make sure it's a valid source name 796 source_map_t::iterator sourceIt = m_sources.find(*fromSourceName); 797 if (sourceIt == m_sources.end()) 798 { 799 throw semantic_error(format_string("line %d: bad source name", statement->getFirstLine())); 800 } 801 802 // set default source 803 m_defaultSource = sourceIt->second; 804 assert(m_defaultSource); 805 806 // get statements inside the from block 807 ListASTNode * fromStatements = statement->getStatements(); 808 assert(fromStatements); 809 810 // produce resulting operation sequence 811 OperationSequence * result = convertStatementList(fromStatements); 812 813 // restore default source to NULL 814 m_defaultSource = NULL; 815 816 return result; 817} 818 819//! Evaluates the expression to get the new boot mode value. Then creates a 820//! BootModeOperation object and returns an OperationSequence containing it. 821//! 822//! \exception elftosb::semantic_error Thrown if a semantic problem is found with 823//! the boot mode expression. 824OperationSequence * ConversionController::convertModeStatement(ModeStatementASTNode * statement) 825{ 826 BootModeOperation * op = NULL; 827 828 try 829 { 830 op = new BootModeOperation(); 831 832 // evaluate the boot mode expression 833 ExprASTNode * modeExprNode = statement->getModeExpr(); 834 if (!modeExprNode) 835 { 836 throw semantic_error(format_string("line %d: mode statement has invalid boot mode expression", statement->getFirstLine())); 837 } 838 modeExprNode = modeExprNode->reduce(m_context); 839 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(modeExprNode); 840 if (!intNode) 841 { 842 throw semantic_error(format_string("line %d: boot mode did not evaluate to an integer", statement->getFirstLine())); 843 } 844 845 op->setBootMode(intNode->getValue()); 846 847 return new OperationSequence(op); 848 } 849 catch (...) 850 { 851 if (op) 852 { 853 delete op; 854 } 855 856 // rethrow exception 857 throw; 858 } 859} 860 861//! Else branches, including else-if, are handled recursively, so there is a limit 862//! on the number of them based on the stack size. 863//! 864//! \return Returns the operation sequence for the branch of the if statement that 865//! evaluated to true. If the statement did not have an else branch and the 866//! condition expression evaluated to false, then NULL will be returned. 867//! 868//! \todo Handle else branches without recursion. 869OperationSequence * ConversionController::convertIfStatement(IfStatementASTNode * statement) 870{ 871 // Get the if's conditional expression. 872 ExprASTNode * conditionalExpr = statement->getConditionExpr(); 873 if (!conditionalExpr) 874 { 875 throw semantic_error(format_string("line %d: missing or invalid conditional expression", statement->getFirstLine())); 876 } 877 878 // Reduce the conditional to a single integer. 879 conditionalExpr = conditionalExpr->reduce(m_context); 880 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(conditionalExpr); 881 if (!intNode) 882 { 883 throw semantic_error(format_string("line %d: if statement conditional expression did not evaluate to an integer", statement->getFirstLine())); 884 } 885 886 // Decide which statements to further process by the conditional's boolean value. 887 if (intNode->getValue() && statement->getIfStatements()) 888 { 889 return convertStatementList(statement->getIfStatements()); 890 } 891 else if (statement->getElseStatements()) 892 { 893 return convertStatementList(statement->getElseStatements()); 894 } 895 else 896 { 897 // No else branch and the conditional was false, so there are no operations to return. 898 return NULL; 899 } 900} 901 902//! Message statements are executed immediately, by this method. They are 903//! not converted into an abstract operation. All messages are passed through 904//! substituteVariables() before being output. 905//! 906//! \param statement The message statement AST node object. 907void ConversionController::handleMessageStatement(MessageStatementASTNode * statement) 908{ 909 string * message = statement->getMessage(); 910 if (!message) 911 { 912 throw runtime_error("message statement had no message"); 913 } 914 915 smart_ptr<string> finalMessage = substituteVariables(message); 916 917 switch (statement->getType()) 918 { 919 case MessageStatementASTNode::kInfo: 920 Log::log(Logger::INFO, "%s\n", finalMessage->c_str()); 921 break; 922 923 case MessageStatementASTNode::kWarning: 924 Log::log(Logger::WARNING, "warning: %s\n", finalMessage->c_str()); 925 break; 926 927 case MessageStatementASTNode::kError: 928 throw runtime_error(*finalMessage); 929 break; 930 } 931} 932 933//! Performs shell-like variable substitution on the string passed into it. 934//! Both sources and constants can be substituted. Sources will be replaced 935//! with their path and constants with their integer value. The syntax allows 936//! for some simple formatting for constants. 937//! 938//! The syntax is mostly standard. A substitution begins with a dollar-sign 939//! and is followed by the source or constant name in parentheses. For instance, 940//! "$(mysource)" or "$(myconst)". The parentheses are always required. 941//! 942//! Constant names can be prefixed by a single formatting character followed 943//! by a colon. The only formatting characters currently supported are 'd' for 944//! decimal and 'x' for hex. For example, "$(x:myconst)" will be replaced with 945//! the value of the constant named "myconst" formatted as hexadecimal. The 946//! default is decimal, so the 'd' formatting character isn't really ever 947//! needed. 948//! 949//! \param message The string to perform substitution on. 950//! \return Returns a newly allocated std::string object that has all 951//! substitutions replaced with the associated value. The caller is 952//! responsible for freeing the string object using the delete operator. 953std::string * ConversionController::substituteVariables(const std::string * message) 954{ 955 string * result = new string(); 956 int i; 957 int state = 0; 958 string name; 959 960 for (i=0; i < message->size(); ++i) 961 { 962 char c = (*message)[i]; 963 switch (state) 964 { 965 case 0: 966 if (c == '$') 967 { 968 state = 1; 969 } 970 else 971 { 972 (*result) += c; 973 } 974 break; 975 976 case 1: 977 if (c == '(') 978 { 979 state = 2; 980 } 981 else 982 { 983 // Wasn't a variable substitution, so revert to initial state after 984 // inserting the original characters. 985 (*result) += '$'; 986 (*result) += c; 987 state = 0; 988 } 989 break; 990 991 case 2: 992 if (c == ')') 993 { 994 // Try the name as a source name first. 995 if (m_sources.find(name) != m_sources.end()) 996 { 997 (*result) += m_sources[name]->getPath(); 998 } 999 // Otherwise try it as a variable. 1000 else 1001 { 1002 // Select format. 1003 const char * fmt = "%d"; 1004 if (name[1] == ':' && (name[0] == 'd' || name[0] == 'x')) 1005 { 1006 if (name[0] == 'x') 1007 { 1008 fmt = "0x%x"; 1009 } 1010 1011 // Delete the format characters. 1012 name.erase(0, 2); 1013 } 1014 1015 // Now insert the formatted variable if it exists. 1016 if (m_context.isVariableDefined(name)) 1017 { 1018 (*result) += format_string(fmt, m_context.getVariableValue(name)); 1019 } 1020 } 1021 1022 // Switch back to initial state and clear name. 1023 state = 0; 1024 name.clear(); 1025 } 1026 else 1027 { 1028 // Just keep building up the variable name. 1029 name += c; 1030 } 1031 break; 1032 } 1033 } 1034 1035 return result; 1036} 1037 1038//! 1039//! \param generator The generator to use. 1040BootImage * ConversionController::generateOutput(BootImageGenerator * generator) 1041{ 1042 // set the generator's option context 1043 generator->setOptionContext(this); 1044 1045 // add output sections to the generator in sequence 1046 section_vector_t::iterator it = m_outputSections.begin(); 1047 for (; it != m_outputSections.end(); ++it) 1048 { 1049 generator->addOutputSection(*it); 1050 } 1051 1052 // and produce the output 1053 BootImage * image = generator->generate(); 1054// Log::log("boot image = %p\n", image); 1055 return image; 1056} 1057 1058//! Takes an AST node that is one of the following subclasses and creates the corresponding 1059//! type of DataSource object from it. 1060//! - StringConstASTNode 1061//! - ExprASTNode 1062//! - SourceASTNode 1063//! - SectionASTNode 1064//! - SectionMatchListASTNode 1065//! - BlobConstASTNode 1066//! - IVTConstASTNode 1067//! 1068//! \exception elftosb::semantic_error Thrown if a semantic problem is found with 1069//! the data node. 1070//! \exception std::runtime_error Thrown if an error occurs that shouldn't be possible 1071//! based on the grammar. 1072DataSource * ConversionController::createSourceFromNode(ASTNode * dataNode) 1073{ 1074 assert(dataNode); 1075 1076 DataSource * source = NULL; 1077 StringConstASTNode * stringNode; 1078 BlobConstASTNode * blobNode; 1079 ExprASTNode * exprNode; 1080 SourceASTNode * sourceNode; 1081 SectionASTNode * sectionNode; 1082 SectionMatchListASTNode * matchListNode; 1083 IVTConstASTNode * ivtNode; 1084 1085 if (stringNode = dynamic_cast<StringConstASTNode*>(dataNode)) 1086 { 1087 // create a data source with the string contents 1088 std::string * stringData = stringNode->getString(); 1089 const uint8_t * stringContents = reinterpret_cast<const uint8_t *>(stringData->c_str()); 1090 source = new UnmappedDataSource(stringContents, static_cast<unsigned>(stringData->size())); 1091 } 1092 else if (blobNode = dynamic_cast<BlobConstASTNode*>(dataNode)) 1093 { 1094 // create a data source with the raw binary data 1095 Blob * blob = blobNode->getBlob(); 1096 source = new UnmappedDataSource(blob->getData(), blob->getLength()); 1097 } 1098 else if (exprNode = dynamic_cast<ExprASTNode*>(dataNode)) 1099 { 1100 // reduce the expression first 1101 exprNode = exprNode->reduce(m_context); 1102 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(exprNode); 1103 if (!intNode) 1104 { 1105 throw semantic_error("load pattern expression did not evaluate to an integer"); 1106 } 1107 1108 SizedIntegerValue intValue(intNode->getValue(), intNode->getSize()); 1109 source = new PatternSource(intValue); 1110 } 1111 else if (sourceNode = dynamic_cast<SourceASTNode*>(dataNode)) 1112 { 1113 // load the entire source contents 1114 SourceFile * sourceFile = getSourceFromName(sourceNode->getSourceName(), sourceNode->getFirstLine()); 1115 source = sourceFile->createDataSource(); 1116 } 1117 else if (sectionNode = dynamic_cast<SectionASTNode*>(dataNode)) 1118 { 1119 // load some subset of the source 1120 SourceFile * sourceFile = getSourceFromName(sectionNode->getSourceName(), sectionNode->getFirstLine()); 1121 if (!sourceFile->supportsNamedSections()) 1122 { 1123 throw semantic_error(format_string("line %d: source does not support sections", sectionNode->getFirstLine())); 1124 } 1125 1126 // create data source from the section name 1127 std::string * sectionName = sectionNode->getSectionName(); 1128 GlobMatcher globber(*sectionName); 1129 source = sourceFile->createDataSource(globber); 1130 if (!source) 1131 { 1132 throw semantic_error(format_string("line %d: no sections match the pattern", sectionNode->getFirstLine())); 1133 } 1134 } 1135 else if (matchListNode = dynamic_cast<SectionMatchListASTNode*>(dataNode)) 1136 { 1137 SourceFile * sourceFile = getSourceFromName(matchListNode->getSourceName(), matchListNode->getFirstLine()); 1138 if (!sourceFile->supportsNamedSections()) 1139 { 1140 throw semantic_error(format_string("line %d: source type does not support sections", matchListNode->getFirstLine())); 1141 } 1142 1143 // create string matcher 1144 ExcludesListMatcher matcher; 1145 1146 // add each pattern to the matcher 1147 ListASTNode * matchList = matchListNode->getSections(); 1148 ListASTNode::iterator it = matchList->begin(); 1149 for (; it != matchList->end(); ++it) 1150 { 1151 ASTNode * node = *it; 1152 sectionNode = dynamic_cast<SectionASTNode*>(node); 1153 if (!sectionNode) 1154 { 1155 throw std::runtime_error(format_string("line %d: unexpected node type in section pattern list", (*it)->getFirstLine())); 1156 } 1157 bool isInclude = sectionNode->getAction() == SectionASTNode::kInclude; 1158 matcher.addPattern(isInclude, *(sectionNode->getSectionName())); 1159 } 1160 1161 // create data source from the section match list 1162 source = sourceFile->createDataSource(matcher); 1163 if (!source) 1164 { 1165 throw semantic_error(format_string("line %d: no sections match the section pattern list", matchListNode->getFirstLine())); 1166 } 1167 } 1168 else if (ivtNode = dynamic_cast<IVTConstASTNode*>(dataNode)) 1169 { 1170 source = createIVTDataSource(ivtNode); 1171 } 1172 else 1173 { 1174 throw semantic_error(format_string("line %d: unexpected load data node type", dataNode->getFirstLine())); 1175 } 1176 1177 return source; 1178} 1179 1180DataSource * ConversionController::createIVTDataSource(IVTConstASTNode * ivtNode) 1181{ 1182 IVTDataSource * source = new IVTDataSource; 1183 1184 // Iterate over the assignment statements in the IVT definition. 1185 ListASTNode * fieldList = ivtNode->getFieldAssignments(); 1186 1187 if (fieldList) 1188 { 1189 ListASTNode::iterator it = fieldList->begin(); 1190 for (; it != fieldList->end(); ++it) 1191 { 1192 AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(*it); 1193 if (!assignmentNode) 1194 { 1195 throw std::runtime_error(format_string("line %d: unexpected node type in IVT definition", (*it)->getFirstLine())); 1196 } 1197 1198 // Get the IVT field name. 1199 std::string * fieldName = assignmentNode->getIdent(); 1200 1201 // Reduce the field expression and get the integer result. 1202 ASTNode * valueNode = assignmentNode->getValue(); 1203 ExprASTNode * valueExpr = dynamic_cast<ExprASTNode*>(valueNode); 1204 if (!valueExpr) 1205 { 1206 throw semantic_error("IVT field must have a valid expression"); 1207 } 1208 IntConstExprASTNode * valueIntExpr = dynamic_cast<IntConstExprASTNode*>(valueExpr->reduce(m_context)); 1209 if (!valueIntExpr) 1210 { 1211 throw semantic_error(format_string("line %d: IVT field '%s' does not evaluate to an integer", valueNode->getFirstLine(), fieldName->c_str())); 1212 } 1213 uint32_t value = static_cast<uint32_t>(valueIntExpr->getValue()); 1214 1215 // Set the field in the IVT data source. 1216 if (!source->setFieldByName(*fieldName, value)) 1217 { 1218 throw semantic_error(format_string("line %d: unknown IVT field '%s'", assignmentNode->getFirstLine(), fieldName->c_str())); 1219 } 1220 } 1221 } 1222 1223 return source; 1224} 1225 1226//! Takes an AST node subclass and returns an appropriate DataTarget object that contains 1227//! the same information. Supported AST node types are: 1228//! - SymbolASTNode 1229//! - NaturalLocationASTNode 1230//! - AddressRangeASTNode 1231//! 1232//! \exception elftosb::semantic_error Thrown if a semantic problem is found with 1233//! the target node. 1234DataTarget * ConversionController::createTargetFromNode(ASTNode * targetNode) 1235{ 1236 assert(targetNode); 1237 1238 DataTarget * target = NULL; 1239 SymbolASTNode * symbolNode; 1240 NaturalLocationASTNode * naturalNode; 1241 AddressRangeASTNode * addressNode; 1242 1243 if (symbolNode = dynamic_cast<SymbolASTNode*>(targetNode)) 1244 { 1245 SourceFile * sourceFile = getSourceFromName(symbolNode->getSource(), symbolNode->getFirstLine()); 1246 std::string * symbolName = symbolNode->getSymbolName(); 1247 1248 // symbol name is optional 1249 if (symbolName) 1250 { 1251 if (!sourceFile->supportsNamedSymbols()) 1252 { 1253 throw std::runtime_error(format_string("line %d: source does not support symbols", symbolNode->getFirstLine())); 1254 } 1255 1256 target = sourceFile->createDataTargetForSymbol(*symbolName); 1257 if (!target) 1258 { 1259 throw std::runtime_error(format_string("line %d: source does not have a symbol with that name", symbolNode->getFirstLine())); 1260 } 1261 } 1262 else 1263 { 1264 // no symbol name was specified so use entry point 1265 target = sourceFile->createDataTargetForEntryPoint(); 1266 if (!target) 1267 { 1268 throw std::runtime_error(format_string("line %d: source does not have an entry point", symbolNode->getFirstLine())); 1269 } 1270 } 1271 } 1272 else if (naturalNode = dynamic_cast<NaturalLocationASTNode*>(targetNode)) 1273 { 1274 // the target is the source's natural location 1275 target = new NaturalDataTarget(); 1276 } 1277 else if (addressNode = dynamic_cast<AddressRangeASTNode*>(targetNode)) 1278 { 1279 // evaluate begin address 1280 ExprASTNode * beginExpr = dynamic_cast<ExprASTNode*>(addressNode->getBegin()); 1281 if (!beginExpr) 1282 { 1283 throw semantic_error("address range must always have a beginning expression"); 1284 } 1285 IntConstExprASTNode * beginIntExpr = dynamic_cast<IntConstExprASTNode*>(beginExpr->reduce(m_context)); 1286 if (!beginIntExpr) 1287 { 1288 throw semantic_error("address range begin did not evaluate to an integer"); 1289 } 1290 uint32_t beginAddress = static_cast<uint32_t>(beginIntExpr->getValue()); 1291 1292 // evaluate end address 1293 ExprASTNode * endExpr = dynamic_cast<ExprASTNode*>(addressNode->getEnd()); 1294 uint32_t endAddress = 0; 1295 bool hasEndAddress = false; 1296 if (endExpr) 1297 { 1298 IntConstExprASTNode * endIntExpr = dynamic_cast<IntConstExprASTNode*>(endExpr->reduce(m_context)); 1299 if (!endIntExpr) 1300 { 1301 throw semantic_error("address range end did not evaluate to an integer"); 1302 } 1303 endAddress = static_cast<uint32_t>(endIntExpr->getValue()); 1304 hasEndAddress = true; 1305 } 1306 1307 // create target 1308 if (hasEndAddress) 1309 { 1310 target = new ConstantDataTarget(beginAddress, endAddress); 1311 } 1312 else 1313 { 1314 target = new ConstantDataTarget(beginAddress); 1315 } 1316 } 1317 else 1318 { 1319 throw semantic_error("unexpected load target node type"); 1320 } 1321 1322 return target; 1323} 1324 1325//! \param sourceName Pointer to string containing the name of the source to look up. 1326//! May be NULL, in which case the default source is used. 1327//! \param line The line number on which the source name was located. 1328//! 1329//! \result A source file object that was previously created in the processSources() 1330//! stage. 1331//! 1332//! \exception std::runtime_error Thrown if the source name is invalid, or if it 1333//! was NULL and there is no default source (i.e., we're not inside a from 1334//! statement). 1335SourceFile * ConversionController::getSourceFromName(std::string * sourceName, int line) 1336{ 1337 SourceFile * sourceFile = NULL; 1338 if (sourceName) 1339 { 1340 // look up source in map 1341 source_map_t::iterator it = m_sources.find(*sourceName); 1342 if (it == m_sources.end()) 1343 { 1344 source_name_vector_t::const_iterator findIt = std::find<source_name_vector_t::const_iterator, std::string>(m_failedSources.begin(), m_failedSources.end(), *sourceName); 1345 if (findIt != m_failedSources.end()) 1346 { 1347 throw semantic_error(format_string("line %d: error opening source '%s'", line, sourceName->c_str())); 1348 } 1349 else 1350 { 1351 throw semantic_error(format_string("line %d: invalid source name '%s'", line, sourceName->c_str())); 1352 } 1353 } 1354 sourceFile = it->second; 1355 } 1356 else 1357 { 1358 // no name provided - use default source 1359 sourceFile = m_defaultSource; 1360 if (!sourceFile) 1361 { 1362 throw semantic_error(format_string("line %d: source required but no default source is available", line)); 1363 } 1364 } 1365 1366 // open the file if it hasn't already been 1367 if (!sourceFile->isOpen()) 1368 { 1369 sourceFile->open(); 1370 } 1371 return sourceFile; 1372} 1373 1374//! Exercises the lexer by printing out the value of every token produced by the 1375//! lexer. It is assumed that the lexer object has already be configured to read 1376//! from some input file. The method will return when the lexer has exhausted all 1377//! tokens, or an error occurs. 1378void ConversionController::testLexer(ElftosbLexer & lexer) 1379{ 1380 // test lexer 1381 while (1) 1382 { 1383 YYSTYPE value; 1384 int lexresult = lexer.yylex(); 1385 if (lexresult == 0) 1386 break; 1387 lexer.getSymbolValue(&value); 1388 Log::log("%d -> int:%d, ast:%p", lexresult, value.m_int, value.m_str, value.m_ast); 1389 if (lexresult == TOK_IDENT || lexresult == TOK_SOURCE_NAME || lexresult == TOK_STRING_LITERAL) 1390 { 1391 if (value.m_str) 1392 { 1393 Log::log(", str:%s\n", value.m_str->c_str()); 1394 } 1395 else 1396 { 1397 Log::log("str:NULL\n"); 1398 } 1399 } 1400 else 1401 { 1402 Log::log("\n"); 1403 } 1404 } 1405} 1406 1407//! Prints out the value of an integer constant expression AST node. Also prints 1408//! the name of the identifier associated with that node, as well as the integer 1409//! size. 1410void ConversionController::printIntConstExpr(const std::string & ident, IntConstExprASTNode * expr) 1411{ 1412 // print constant value 1413 char sizeChar; 1414 switch (expr->getSize()) 1415 { 1416 case kWordSize: 1417 sizeChar = 'w'; 1418 break; 1419 case kHalfWordSize: 1420 sizeChar = 'h'; 1421 break; 1422 case kByteSize: 1423 sizeChar = 'b'; 1424 break; 1425 } 1426 Log::log("%s => %d:%c\n", ident.c_str(), expr->getValue(), sizeChar); 1427} 1428 1429