summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Beisert <jbe@pengutronix.de>2011-06-06 16:57:16 +0200
committerJuergen Beisert <jbe@pengutronix.de>2011-06-06 16:57:16 +0200
commitdd57c62797d2b8d05e224680c7bc6e3d4640dde0 (patch)
tree30046767e14e220ac2b66e2314530565b2117b40
parent3647e131f8f2779d203d737a3c59baf6c061d528 (diff)
downloadmxs-utils-dd57c62797d2b8d05e224680c7bc6e3d4640dde0.tar.gz
mxs-utils-dd57c62797d2b8d05e224680c7bc6e3d4640dde0.tar.xz
Import FSL's release 10.11.01
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
-rw-r--r--COPYING28
-rw-r--r--ReadMe.txt45
-rw-r--r--bdfiles/basic_test_cmd.e192
-rw-r--r--bdfiles/complex.bd260
-rw-r--r--bdfiles/habtest.bd36
-rw-r--r--bdfiles/simple.e8
-rw-r--r--bdfiles/test_cmd.e120
-rw-r--r--common/AESKey.cpp78
-rw-r--r--common/AESKey.h144
-rw-r--r--common/Blob.cpp123
-rw-r--r--common/Blob.h70
-rw-r--r--common/BootImage.h54
-rw-r--r--common/DataSource.cpp224
-rw-r--r--common/DataSource.h299
-rw-r--r--common/DataSourceImager.cpp143
-rw-r--r--common/DataSourceImager.h54
-rw-r--r--common/DataTarget.cpp59
-rw-r--r--common/DataTarget.h122
-rw-r--r--common/ELF.h332
-rw-r--r--common/ELFSourceFile.cpp529
-rw-r--r--common/ELFSourceFile.h224
-rw-r--r--common/EncoreBootImage.cpp1372
-rw-r--r--common/EncoreBootImage.h967
-rw-r--r--common/EndianUtilities.h141
-rw-r--r--common/EvalContext.cpp111
-rw-r--r--common/EvalContext.h99
-rw-r--r--common/ExcludesListMatcher.cpp88
-rw-r--r--common/ExcludesListMatcher.h67
-rw-r--r--common/GHSSecInfo.cpp100
-rw-r--r--common/GHSSecInfo.h72
-rw-r--r--common/GlobMatcher.cpp129
-rw-r--r--common/GlobMatcher.h59
-rw-r--r--common/HexValues.cpp34
-rw-r--r--common/HexValues.h21
-rw-r--r--common/IVTDataSource.cpp113
-rw-r--r--common/IVTDataSource.h296
-rw-r--r--common/Logging.cpp91
-rw-r--r--common/Logging.h226
-rw-r--r--common/Operation.cpp63
-rw-r--r--common/Operation.h168
-rw-r--r--common/OptionContext.h50
-rw-r--r--common/OptionDictionary.cpp170
-rw-r--r--common/OptionDictionary.h107
-rw-r--r--common/OutputSection.cpp9
-rw-r--r--common/OutputSection.h72
-rw-r--r--common/Random.cpp85
-rw-r--r--common/Random.h57
-rw-r--r--common/RijndaelCBCMAC.cpp86
-rw-r--r--common/RijndaelCBCMAC.h62
-rw-r--r--common/SHA1.cpp274
-rw-r--r--common/SHA1.h149
-rw-r--r--common/SRecordSourceFile.cpp176
-rw-r--r--common/SRecordSourceFile.h83
-rw-r--r--common/SearchPath.cpp121
-rw-r--r--common/SearchPath.h58
-rw-r--r--common/SourceFile.cpp178
-rw-r--r--common/SourceFile.h156
-rw-r--r--common/StELFFile.cpp531
-rw-r--r--common/StELFFile.h196
-rw-r--r--common/StExecutableImage.cpp463
-rw-r--r--common/StExecutableImage.h251
-rw-r--r--common/StSRecordFile.cpp235
-rw-r--r--common/StSRecordFile.h119
-rw-r--r--common/StringMatcher.h62
-rw-r--r--common/Value.cpp43
-rw-r--r--common/Value.h138
-rw-r--r--common/Version.cpp143
-rw-r--r--common/Version.h51
-rw-r--r--common/crc.cpp292
-rw-r--r--common/crc.h48
-rw-r--r--common/format_string.cpp79
-rw-r--r--common/format_string.h20
-rw-r--r--common/int_size.h22
-rw-r--r--common/options.cpp1140
-rw-r--r--common/options.h488
-rw-r--r--common/rijndael.cpp1604
-rw-r--r--common/rijndael.h159
-rw-r--r--common/smart_ptr.h232
-rw-r--r--common/stdafx.cpp8
-rw-r--r--common/stdafx.h83
-rw-r--r--elftosb2/BootImageGenerator.cpp80
-rw-r--r--elftosb2/BootImageGenerator.h69
-rw-r--r--elftosb2/ConversionController.cpp1428
-rw-r--r--elftosb2/ConversionController.h153
-rw-r--r--elftosb2/Doxyfile250
-rw-r--r--elftosb2/ElftosbAST.cpp1352
-rw-r--r--elftosb2/ElftosbAST.h1227
-rw-r--r--elftosb2/ElftosbErrors.h29
-rw-r--r--elftosb2/ElftosbLexer.cpp149
-rw-r--r--elftosb2/ElftosbLexer.h97
-rw-r--r--elftosb2/EncoreBootImageGenerator.cpp297
-rw-r--r--elftosb2/EncoreBootImageGenerator.h57
-rw-r--r--elftosb2/FlexLexer.h208
-rw-r--r--elftosb2/elftosb.cpp700
-rw-r--r--elftosb2/elftosb_lexer.cpp2241
-rw-r--r--elftosb2/elftosb_lexer.l299
-rw-r--r--elftosb2/elftosb_parser.tab.cpp2955
-rw-r--r--elftosb2/elftosb_parser.tab.hpp152
-rw-r--r--elftosb2/elftosb_parser.y978
-rw-r--r--encryptgpk/encryptgpk.cpp442
-rw-r--r--keygen/Doxyfile250
-rw-r--r--keygen/keygen.cpp346
-rw-r--r--makefile32
-rw-r--r--makefile.rules178
-rw-r--r--sbtool/Doxyfile250
-rw-r--r--sbtool/EncoreBootImageReader.cpp370
-rw-r--r--sbtool/EncoreBootImageReader.h117
-rw-r--r--sbtool/sbtool.cpp626
-rw-r--r--stdafx.h66
109 files changed, 31059 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f829e09
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,28 @@
+Copyright (c) 2004-2010 Freescale Semiconductor, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list
+ of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+* Neither the name of the Freescale Semiconductor, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ReadMe.txt b/ReadMe.txt
new file mode 100644
index 0000000..b1fe9bd
--- /dev/null
+++ b/ReadMe.txt
@@ -0,0 +1,45 @@
+elftosb 2.x read me
+-------------------
+
+Directories
+
+elftosb2 - elftosb 2.x
+sbtool - sbtool 1.x
+keygen - keygen 1.x
+common - source files common between elftosb2, sbtool, and keygen
+winsupport - files needed only by the windows build
+elftosb - old elftosb 1.x, does not use anything from common
+generatekeys - old key generation tool for elftosb 1.x
+decrypt - old decryption tool for elftosb 1.x
+unittests - old unit tests for elftosb 1.x
+test_files - test ELF and Srecord files
+old - contains old makefiles for elftosb 1.x
+
+Development
+
+The preferred way to work on elftosb and related tools is to use Xcode on Mac OS X. The
+elftosb.xcodeproj directory is an Xcode project "file". It has targets for elftosb,
+keygen, sbtool, and an aggregate target that builds all of the above. The main reason
+to use Xcode is that the project is set up so that the flex and bison input files are
+processed automatically and the output files compiled.
+
+The Windows project and Linux makefile are not configured to build the flex or bison
+source files. They simply use the output files copied into the elftosb2 directory.
+You can run flex or bison manually to generate these files if you don't want to use Xcode.
+If you do use the Xcode project and make changes to the .l or .y files, be sure to copy
+the output .cpp files into the elftosb2 directory before you move the changes to either
+Windows or Linux.
+
+Building
+
+On Windows, open the .sln file in Microsoft Visual Studio. The solution contains projects
+for each of the individual projects, including the old elftosb 1.x and related tools.
+
+For Linux, run 'make all' from within the top level elftosb directory. This will build only
+the new elftosb 2.x, sbtool, and keygen. The old makefile to build elftosb 1.x and its
+tools is located in the "old" directory.
+
+On Mac OS X just open the .xcodeproj project and build the "Everything" target.
+
+
+
diff --git a/bdfiles/basic_test_cmd.e b/bdfiles/basic_test_cmd.e
new file mode 100644
index 0000000..dbdad1f
--- /dev/null
+++ b/bdfiles/basic_test_cmd.e
@@ -0,0 +1,192 @@
+
+# ooh! test input command file for elftosb 2!
+
+options {
+ coalesce = yes;
+
+ # most elf files are GHS produced
+ toolset = "GHS";
+
+ # set versions
+ productVersion = "111.222.333";
+ componentVersion = "999.888.777";
+
+ # set file flags
+ flags = (1 << 0) | (1 << 1);
+}
+
+constants {
+ ocram_start = 0;
+ ocram_size = 256K;
+ ocram_end = ocram_start + ocram_size - 1;
+
+# ocram = ocram_start .. ocram_end;
+#
+# ocram = ocram_start +.. ocram_size;
+
+ string_addr = 0x4500;
+
+ # boot modes
+ USB_BM = 0;
+ JTAG_BM = 7;
+ newBootMode = USB_BM;
+}
+
+sources {
+ hello = extern(0); # elf
+ redboot = extern(1); # srec
+ hostlink = extern(2); # elf
+ sd_player = extern(3) ( toolset="GCC" ); # elf
+ datasrc = "test0.key"; # binary
+}
+
+section (0) {
+ # load dcd
+ load dcd {{ 00 11 22 33 }} > 0;
+
+ # same load without dcd
+ load {{ 00 11 22 33 }} > 0;
+
+ call 0xf000;
+
+ hab call 0xf0000000 (128);
+ hab jump 0;
+
+/*
+ # load a simple IVT to an absolute address
+ # this fills in the IVT self address field from the target address
+ load ivt (entry=hello:_start) > 0x1000;
+
+ # load simple IVT. the IVT self address is set explicitly in the IVT declaration,
+ # giving the IVT a natural address so you don't have to tell where to load it.
+ load ivt (entry=hello:_start, self=0x1000);
+
+ load ivt (entry=hello:_start, self=0x1000, csf=0x2000, dcd=0);
+
+ # Setting IVT entry point to the default entry point of a source file.
+ load ivt (entry=hostlink) > 0;
+
+ load ivt (entry=hello:_start, self=0x1000);
+ hab call 0x1000;
+
+ # Special syntax that combines the load and call into one statement.
+ hab call ivt(entry=hello:_start, self=0x1000);
+
+
+
+ load ivt (
+ entry = hello:_start,
+ csf = 0x2000
+ ) > 0x1000;
+
+ # All supported IVT fields.
+ load ivt (
+ entry = hello:,
+ dcd = 0,
+ boot_data = 0,
+ self = 0,
+ csf = 0
+ );
+
+ hab call ivt; # Call the last loaded IVT. */
+}
+
+section (32) {
+ # load a string to some address
+ load "some string" > string_addr;
+
+ # byte fill a region
+ load 0x55.b > ocram_start..ocram_end;
+
+ from hostlink {
+ load $*;
+ }
+
+ # jump to a symbol
+ jump hostlink:_start (100);
+}
+
+section (100)
+{
+ load redboot;
+ call redboot;
+}
+
+section(0x5a)
+{
+ load datasrc > 0..8;
+
+ from hostlink
+ {
+# load $* ( $.ocram.*, ~$.sdram.* );
+
+# load $.sdram.*;
+# load $.ocram.*;
+
+ call :main;
+ call :_start;
+ }
+
+# goto 0x5b;
+}
+
+section (0x5b)
+{
+# load $* from sd_player;
+
+# load hello$.text @ 64K;
+# load hello$*
+
+ load $.text from hello > 0x10000;
+ call sd_player (0xdeadbeef);
+}
+
+section (0x5c)
+{
+ # these loads should produce fill commands with a
+ # length equal to the pattern word size
+ load 0x55.b > 0x200;
+ load 0x55aa.h > 0x400;
+ load 0x55aa66bb.w > 0x800;
+
+# load 0x55.b to 0x200;
+# load 0x55aa.h to 0x400;
+# load 0x55aa66bb.w to 0x800;
+
+# load 0x55.b @ 0x200;
+# load 0x55aa.h @ 0x400;
+# load 0x55aa66bb.w @ 0x800;
+
+# load $.text from hello @ .;
+# load hello$.text @ .;
+# load hello$* @ .
+
+ # this should produce a fill command with a length
+ # of 0x100
+ load 0x4c8e.h > 0x100..0x200;
+
+# load [ 0a 9b 77 66 55 44 33 22 11 00 ] @ 0x100;
+}
+
+# non-bootable section
+section (0x100) <= datasrc;
+
+#section (1K)
+#{
+# load 0xff.b > hostlink:g_wUsbVID + 4;
+#
+# load "Fred's Auto Service\x00" > hostlink:g_wUsbVendorName;
+#
+# from sd_player
+# {
+# load [ 00 11 22 33 44 55 66 77 ] > :g_data + 16;
+# }
+#
+## (0x10 .. 0x20) + 5 == 0x15 .. 0x25
+#}
+
+# section that switches modes
+section (2K)
+{
+ mode newBootMode;
+}
diff --git a/bdfiles/complex.bd b/bdfiles/complex.bd
new file mode 100644
index 0000000..4038a52
--- /dev/null
+++ b/bdfiles/complex.bd
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2006 SigmaTel, Inc.
+ *
+ * elftosb boot description file that creates some complicated situations for
+ * the loader to handle. of course this is also a good test for elftosb itself.
+ */
+
+/* testing C style comments */
+// testing C++ style comments
+# testing shell style comments
+
+constants {
+ kProgressReportsImageFlag = 0x1;
+
+ kPlayerDriveTag = 0xa0;
+ kHostlinkDriveTag = 0xb0;
+}
+
+options {
+ productVersion = "5.0.999";
+ componentVersion = "5.0.999";
+
+ flags = kProgressReportsImageFlag; // turn on progress reports
+
+ secinfoClear = "ignore";
+}
+
+constants {
+ arg = 0xfeedf00d;
+
+ callArg1 = 2;
+ callArg2 = 3;
+
+ halfword = 10.h;
+
+// flag = 1;
+
+ testboolexpr = 1 > 0;
+
+ mainSizeIsDefined = defined(mainSize);
+}
+
+sources {
+ elffile = extern(0) (toolset="ghs");
+ binfile1 = extern(1);
+ binfile2 = extern(2);
+ foofile = "file.dat";
+ anotherfile = "another.dat";
+ srecfile = "test_files/sd_player_gcc.srec";
+}
+
+options {
+ driveTag = kPlayerDriveTag;
+
+ some_option = defined(testboolexpr);
+}
+
+constants {
+ printMessageAddr = elffile:printMessage;
+ printMessageSize = sizeof(elffile:printMessage);
+
+ // create const with address of main() in elffile
+ mainAddr = elffile:main;
+
+ mainSize = sizeof(elffile:main);
+
+ halfwordSize = sizeof(halfword);
+
+ elf_startAddr = elffile:_start;
+
+// poop = exists(nonexistantfile);
+
+ binfile1size = sizeof(binfile1);
+}
+
+/*
+ * test s-record support
+ */
+section (0)
+{
+ load dcd {{ 00 11 22 33 }} > 0;
+ load srecfile;
+ call srecfile;
+}
+
+section(1; coalesce=true) {
+
+ info "welcome to section 1!";
+ info "elffile path = $(elffile)";
+ info "mainSizeIsDefined = $(d:mainSizeIsDefined)";
+ info "printMessage = $(x:printMessageAddr)";
+
+ info "size of binfile1 = $(binfile1size)";
+
+ // can use symbol refs inside bool expressions in an if stmt
+ if elffile:main == 0
+ {
+ warning "$(elffile) does not seem to have a main() function";
+ }
+ else
+ {
+ info "address of main() of $(elffile) is $(x:mainAddr)";
+ }
+
+ if defined(flag) && flag != 0
+ {
+ load 0x1234.h > 0..10K;
+ }
+ else
+ {
+ // print message using both decimal and hex formatting
+ warning "loading only halfword = $(d:halfword) [$(x:halfword)]!";
+ load halfword > 0..1K;
+ }
+
+ info "size of main() in $(elffile) is $(mainSize)";
+ info "printMessage() size is $(printMessageSize)";
+ info "size of halfword = $(halfwordSize)";
+
+ load 0xff.b > 32K..32K + sizeof(elffile:printMessage);
+
+ from elffile {
+ load {{ 00 01 02 03 04 }} > 1K;
+
+ // load all sections except .mytext
+ load ~$.mytext;
+
+ // figure out where to go from here
+ call :maybeSwitchSections(callArg1);
+
+ // print msg and loop
+ load "hi from section 1" > :szMsg;
+ call :printMessage(0);
+
+ jump :hello(0);
+ }
+
+ // erase a function in memory
+ load 0.w > (elffile:endOfLine)..(elffile:endOfLine + sizeof(elffile:endOfLine));
+}
+
+section(2; alignment=64K) {
+ // cause an error if testConst has not been set
+ if !defined(testConst)
+ {
+ error "testConst is not defined!";
+ }
+
+ from elffile {
+ load "in section 2" > :szMsg;
+ call :printMessage();
+ }
+
+ // load the contents of binfile1 into the upper 128KB of ocram
+ load binfile1 > 128K..192K;
+
+ from elffile {
+ load "loaded binfile1" > :szMsg;
+ call :printMessage(0);
+
+ call :maybeSwitchSections(callArg2);
+
+ jump :endOfLine(2);
+ }
+}
+
+// non-bootable section between two bootable sections
+section(0xbeef; alignment=32K, cleartext=false) <= binfile2;
+
+section(3; alignment=8K) {
+ // load our special section
+ load $.mytext from elffile;
+ call elffile:countToN(5);
+
+ if (exists(foofile) && exists(anotherfile))
+ {
+ // a trainload of beef!
+ load 0xbeef.h > 128K..192K;
+ }
+ else if (exists(elffile) && callArg1 == 2)
+ {
+ // aaaaaaah!
+ load 0x12345678.w > 128K..192K;
+ }
+ else
+ {
+ from elffile
+ {
+ // aaaaaaah!
+ load 0xaaaa.h > 128K..192K;
+ load $.text;
+ load 0xbbbb.h > 128K..192K;
+ }
+ }
+
+ from elffile {
+ load "hold on now, in section 3" > :szMsg;
+ call :printMessage(0);
+
+ jump :endOfLine(3);
+ }
+
+ from elffile {
+ load elffile;
+ load elffile > .;
+ load elffile[ $.bss ] > elffile:countToN;
+// load [ $.bss ] > (elffile:countToN)..(elffile:countToN + sizeof(elffile:countToN));
+ call elffile;
+ call elffile(1);
+ }
+
+ info "address of _start in $(elffile) is $(elf_startAddr)";
+}
+
+section ('four'; alignment=8K, sectionFlags=0x1000) <= binfile1;
+
+section ('five'; alignment=8K, cleartext=1, sectionFlags=0x1000) <= binfile1;
+
+/*
+ * create a data section out of some sections of an elf file
+ */
+section (1234) <= ~$.bss, ~$.data from elffile;
+section (4321) <= elffile [ $* ];
+section (1111) <= elffile;
+
+/* test data sections from various data sources */
+section (0xaa) <= 0x12345678.w;
+section (0xbb) <= "hi there! this is a data section.";
+section (0xcc) <= {{ aa55aa55aa55aa55aa55aa55aa55aa55 }};
+
+
+section (2345)
+{
+ load elffile[ $*.text*, ~$.sdram* ];
+}
+
+
+section ('six_')
+{
+ // load a blob at address 0x1000
+ load {{
+ 00 0a 07 b0 bb ff 03 78
+ 00 0a 07 b0 bb ff 03 78
+ 00 0a 07 b0 bb ff 03 78
+ 00 0a 07 b0 bb ff 03 78
+ 00 0a 07 b0 bb ff 03 78
+ }} > 0x1000;
+}
+
+section ('bad_')
+{
+ // uncomment to test better error reporting for files that failed to open
+// load foofile;
+}
+
+//section (2345) <= {{ 00 11 22 33 44 55 }};
+
+
+
+
diff --git a/bdfiles/habtest.bd b/bdfiles/habtest.bd
new file mode 100644
index 0000000..25fc8de
--- /dev/null
+++ b/bdfiles/habtest.bd
@@ -0,0 +1,36 @@
+sources {
+ elffile = extern(0) (toolset="ghs");
+ redboot = extern(1);
+ hostlink = extern(2);
+ srecfile = "test_files/sd_player_gcc.srec";
+}
+
+constants {
+ IVT_ADDR = 0x1000;
+}
+
+section (0)
+{
+
+ load hostlink;
+ call hostlink;
+
+ load dcd {{ 00 11 22 33 }} > 0x100;
+
+ load ivt (
+ entry = elffile:_start
+// dcd = 0x2000,
+// csf = 0x3000,
+// boot_data = 0x55aa55aa.w
+// self = IVT_ADDR
+ ) > IVT_ADDR;
+
+ hab call IVT_ADDR;
+
+ load ivt (entry=hostlink:_start, self=IVT_ADDR);
+
+ hab jump IVT_ADDR;
+}
+
+
+
diff --git a/bdfiles/simple.e b/bdfiles/simple.e
new file mode 100644
index 0000000..65ac5e8
--- /dev/null
+++ b/bdfiles/simple.e
@@ -0,0 +1,8 @@
+options {}
+
+# create a section
+section (0) {
+ load 0 > 0..256K;
+ load "hello world!" > 0x1000;
+}
+
diff --git a/bdfiles/test_cmd.e b/bdfiles/test_cmd.e
new file mode 100644
index 0000000..29af510
--- /dev/null
+++ b/bdfiles/test_cmd.e
@@ -0,0 +1,120 @@
+
+# ooh! test input command file for elftosb 2!
+
+options {
+ searchPath = "elftosb2:elftosb2/elf_test_files";
+
+ maximumLoadBlock = 4K;
+ sectionAlign = 4K;
+
+ productVersion = "4.4.720";
+ componentVersion = "4.4.999";
+
+ coalesce = yes;
+}
+
+constants {
+ ocram_start = 0;
+ ocram_size = 256K;
+ ocram_end = ocram_start + ocram_size - 1;
+
+ prec_test = 1 + 5 * 10;
+ paren_test = (1 + 5) * 10;
+
+ a = 123;
+ foo = (1 + 0x1cf1.w).w ^ 5 + a;
+
+ bar1 = 0xa << 2;
+ bar2 = bar1 | 0x1000;
+ bar3 = bar2 & 0x5555;
+ bar4 = bar3 >> 1;
+
+ mod = 35 % 16;
+
+ n = -1;
+ x = 1 + -2;
+
+ c1 = 'x';
+ c2 = 'oh';
+ c4 = 'shit';
+
+ # test int size promotion
+ x = 0xff.b;
+ y = 0x1234.h;
+ z = 0x55aa55aa.w;
+ xx = x - (x / 2.b); # should produce byte
+ xy = x + y; # should produce half-word
+ xz = x - z; # should produce word
+ yz = y + z; # should produce word
+ xh = x.h;
+ xw = x.w;
+}
+
+sources {
+ hostlink = extern(0);
+ redboot = extern(1);
+
+ sd_player_elf="elftosb2/elf_test_files/sd_player_gcc";
+ sd_player_srec="elftosb2/elf_test_files/sd_player_gcc.srec";
+
+ datafile="elftosb2/elf_test_files/hello_NOR_arm";
+}
+
+#section('foo!') {
+# load 0.w > ocram_start..ocram_end; # word fill all ocram with 0
+#
+# load hostlink; # load all of hostlink source
+#
+# load 0x1000ffff.w > 0x1000; # load a word to address 0x1000
+# load 0x55aa.h > 0x2000; # load a half-word to address 0x2000
+# load redboot; # load all sections of redboot source
+#
+# from hostlink {
+# load $.*.text; # load some sections to their natural location
+# call :_start; # call function "_start" from hostlink
+# call hostlink:foofn; # call function "foofn" from hostlink
+#
+# call :monkey (1 + 1); # call function "monkey" from hostlink with an argument
+#
+# load $* > .; # load all sections of hostlink to their natural location
+#
+# load $.text > 0x1000; # load .text section to address 0x1000
+#
+# load 0x55.b > 0x0..0x4000; # fill 0 through 0x4000 with byte pattern 0x55
+# }
+#
+# load $*.text from hostlink > .; # load sections match "*.text" from hostlink to default places
+#
+# jump redboot; # jump to entry point of redboot source
+#}
+
+## this section...
+#section(2) {
+# from sd_player_elf {
+# load $* > .;
+# call :_start();
+# }
+#}
+#
+## and this one are both equivalent except for section ids
+#section(3) {
+# load $* from sd_player_elf;
+# call sd_player_elf:_start();
+#}
+#
+#section(100) {
+# # set the value of a symbol
+# load hostlink;
+# load 0x5555.h > hostlink:g_USBPID;
+#
+# # load a string to memory
+# load "this is a string" > 0x1e0;
+#}
+
+section (32) {
+ load sd_player_srec;
+ call sd_player_srec;
+}
+
+#section('rsrc') <= datafile;
+
diff --git a/common/AESKey.cpp b/common/AESKey.cpp
new file mode 100644
index 0000000..eedab32
--- /dev/null
+++ b/common/AESKey.cpp
@@ -0,0 +1,78 @@
+/*
+ * File: AESKey.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "AESKey.h"
+#include <stdexcept>
+#include "smart_ptr.h"
+#include "HexValues.h"
+#include <ctype.h>
+
+//! The data from the stream is expected to be hex encoded. Each two characters
+//! from the stream encode a single result byte. All non-hexadecimal characters
+//! are ignored, including newlines. Every two hexadecimal characters form
+//! an encoded byte. This is true even if the two characters representing the
+//! upper and lower nibbles are separated by whitespace or other characters.
+//!
+//! \post The stream read head is left pointing just after the last encoded byte.
+//!
+//! \param stream Input stream to read from.
+//! \param bytes Number of encoded bytes to read. This is the number of \e
+//! result bytes, not the count of bytes to read from the stream.
+//! \param[out] buffer Pointer to the buffer where decoded data is written.
+//!
+//! \exception std::runtime_error This exception will be thrown if less
+//! data than required is available from \a stream, or if some other
+//! error occurs while reading from \a stream.
+void AESKeyBase::_readFromStream(std::istream & stream, unsigned bytes, uint8_t * buffer)
+{
+ char temp[2];
+ char c;
+ char n = 0;
+
+ while (bytes)
+ {
+ if (stream.get(c).fail())
+ {
+ throw std::runtime_error("not enough data in stream");
+ }
+
+ if (isHexDigit(c))
+ {
+ temp[n++] = c;
+ if (n == 2)
+ {
+ *buffer++ = hexByteToInt(temp);
+ bytes--;
+ n = 0;
+ }
+ }
+ }
+}
+
+//! Key data is written to \a stream as a sequence of hex encoded octets, each two
+//! characters long. No spaces or newlines are inserted between the encoded octets
+//! or at the end of the sequence.
+//!
+//! \exception std::runtime_error Thrown if the \a stream reports an error while
+//! writing the key data.
+void AESKeyBase::_writeToStream(std::ostream & stream, unsigned bytes, const uint8_t * buffer)
+{
+ const char hexChars[] = "0123456789ABCDEF";
+ while (bytes--)
+ {
+ uint8_t thisByte = *buffer++;
+ char byteString[2];
+ byteString[0] = hexChars[(thisByte & 0xf0) >> 4];
+ byteString[1] = hexChars[thisByte & 0x0f];
+ if (stream.write(byteString, 2).bad())
+ {
+ throw std::runtime_error("error while writing to stream");
+ }
+ }
+}
+
+
diff --git a/common/AESKey.h b/common/AESKey.h
new file mode 100644
index 0000000..b92b1ae
--- /dev/null
+++ b/common/AESKey.h
@@ -0,0 +1,144 @@
+/*
+ * File: AESKey.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_AESKey_h_)
+#define _AESKey_h_
+
+#include "stdafx.h"
+#include <string.h>
+#include <iostream>
+#include "Random.h"
+
+//! An AES-128 key is 128 bits, or 16 bytes.
+typedef uint8_t aes128_key_t[16];
+
+/*!
+ * \brief Base class for AESKey<S>.
+ *
+ * This class implements some bigger, non-template methods used in the
+ * AESKey<S> templated subclass.
+ */
+class AESKeyBase
+{
+public:
+ //! \brief Reads hex encoded data from \a stream.
+ void _readFromStream(std::istream & stream, unsigned bytes, uint8_t * buffer);
+
+ //! \brief Writes hex encoded data to \a stream.
+ void _writeToStream(std::ostream & stream, unsigned bytes, const uint8_t * buffer);
+};
+
+/*!
+ * \brief Generic AES key class.
+ *
+ * The template parameter \a S is the number of bits in the key.
+ *
+ * The underlying key type can be accessed like this: AESKey<128>::key_t
+ *
+ * When a key instance is destroyed, it erases the key data by setting it
+ * to all zeroes.
+ *
+ * \todo Add a way to allow only key sizes of 128, 192, and 256 bits.
+ * \todo Find a cross platform way to prevent the key data from being written
+ * to the VM swapfile.
+ *
+ * AESKey<128> key = AESKey<128>::readFromStream(s);
+ */
+template <int S>
+class AESKey : public AESKeyBase
+{
+public:
+ //! Type for this size of AES key.
+ typedef uint8_t key_t[S/8];
+
+public:
+ //! \brief Default constructor.
+ //!
+ //! Initializes the key to 0.
+ AESKey()
+ {
+ memset(m_key, 0, sizeof(m_key));
+ }
+
+ //! \brief Constructor taking a key value reference.
+ AESKey(const key_t & key)
+ {
+ memcpy(m_key, &key, sizeof(m_key));
+ }
+
+ // \brief Constructor taking a key value pointer.
+ AESKey(const key_t * key)
+ {
+ memcpy(m_key, key, sizeof(m_key));
+ }
+
+ //! \brief Constructor, reads key from stream in hex format.
+ AESKey(std::istream & stream)
+ {
+ readFromStream(stream);
+ }
+
+ //! \brief Copy constructor.
+ AESKey(const AESKey<S> & other)
+ {
+ memcpy(m_key, other.m_key, sizeof(m_key));
+ }
+
+ //! \brief Destructor.
+ //!
+ //! Sets the key value to zero.
+ ~AESKey()
+ {
+ memset(m_key, 0, sizeof(m_key));
+ }
+
+ //! \brief Set to the key to a randomly generated value.
+ void randomize()
+ {
+ RandomNumberGenerator rng;
+ rng.generateBlock(m_key, sizeof(m_key));
+ }
+
+ //! \brief Reads the key from a hex encoded data stream.
+ void readFromStream(std::istream & stream)
+ {
+ _readFromStream(stream, S/8, reinterpret_cast<uint8_t*>(&m_key));
+ }
+
+ //! \brief Writes the key to a data stream in hex encoded format.
+ void writeToStream(std::ostream & stream)
+ {
+ _writeToStream(stream, S/8, reinterpret_cast<uint8_t*>(&m_key));
+ }
+
+ //! \name Key accessors
+ //@{
+ inline const key_t & getKey() const { return m_key; }
+ inline void getKey(key_t * key) const { memcpy(key, m_key, sizeof(m_key)); }
+
+ inline void setKey(const key_t & key) { memcpy(m_key, &key, sizeof(m_key)); }
+ inline void setKey(const key_t * key) { memcpy(m_key, key, sizeof(m_key)); }
+ inline void setKey(const AESKey<S> & key) { memcpy(m_key, key.m_key, sizeof(m_key)); }
+ //@}
+
+ //! \name Operators
+ //@{
+ const AESKey<S> & operator = (const AESKey<S> & key) { setKey(key); return *this; }
+ const AESKey<S> & operator = (const key_t & key) { setKey(key); return *this; }
+ const AESKey<S> & operator = (const key_t * key) { setKey(key); return *this; }
+
+ operator const key_t & () const { return m_key; }
+ operator const key_t * () const { return m_key; }
+ //@}
+
+protected:
+ key_t m_key; //!< The key value.
+};
+
+//! Standard type definition for an AES-128 key.
+typedef AESKey<128> AES128Key;
+
+#endif // _AESKey_h_
diff --git a/common/Blob.cpp b/common/Blob.cpp
new file mode 100644
index 0000000..3d02521
--- /dev/null
+++ b/common/Blob.cpp
@@ -0,0 +1,123 @@
+/*
+ * File: Blob.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Blob.h"
+#include <stdexcept>
+#include <stdlib.h>
+#include <string.h>
+
+Blob::Blob()
+: m_data(0),
+ m_length(0)
+{
+}
+
+//! Makes a local copy of the \a data argument.
+//!
+Blob::Blob(const uint8_t * data, unsigned length)
+: m_data(0),
+ m_length(length)
+{
+ m_data = reinterpret_cast<uint8_t*>(malloc(length));
+ memcpy(m_data, data, length);
+}
+
+//! Makes a local copy of the data owned by \a other.
+//!
+Blob::Blob(const Blob & other)
+: m_data(0),
+ m_length(other.m_length)
+{
+ m_data = reinterpret_cast<uint8_t *>(malloc(m_length));
+ memcpy(m_data, other.m_data, m_length);
+}
+
+//! Disposes of the binary data associated with this object.
+Blob::~Blob()
+{
+ if (m_data)
+ {
+ free(m_data);
+ }
+}
+
+//! Copies \a data onto the blob's data. The blob does not assume ownership
+//! of \a data.
+//!
+//! \param data Pointer to a buffer containing the data which will be copied
+//! into the blob.
+//! \param length Number of bytes pointed to by \a data.
+void Blob::setData(const uint8_t * data, unsigned length)
+{
+ setLength(length);
+ memcpy(m_data, data, length);
+}
+
+//! Sets the #m_length member variable to \a length and resizes #m_data to
+//! the new length. The contents of #m_data past any previous contents are undefined.
+//! If the new \a length is 0 then the data will be freed and a subsequent call
+//! to getData() will return NULL.
+//!
+//! \param length New length of the blob's data in bytes.
+void Blob::setLength(unsigned length)
+{
+ if (length == 0)
+ {
+ clear();
+ return;
+ }
+
+ // Allocate new block.
+ if (!m_data)
+ {
+ m_data = reinterpret_cast<uint8_t*>(malloc(length));
+ if (!m_data)
+ {
+ throw std::runtime_error("failed to allocate memory");
+ }
+ }
+ // Reallocate previous block.
+ else
+ {
+ void * newBlob = realloc(m_data, length);
+ if (!newBlob)
+ {
+ throw std::runtime_error("failed to reallocate memory");
+ }
+ m_data = reinterpret_cast<uint8_t*>(newBlob);
+ }
+
+ // Set length.
+ m_length = length;
+}
+
+void Blob::append(const uint8_t * newData, unsigned newDataLength)
+{
+ unsigned oldLength = m_length;
+
+ setLength(m_length + newDataLength);
+
+ memcpy(m_data + oldLength, newData, newDataLength);
+}
+
+void Blob::clear()
+{
+ if (m_data)
+ {
+ free(m_data);
+ m_data = NULL;
+ }
+
+ m_length = 0;
+}
+
+void Blob::relinquish()
+{
+ m_data = NULL;
+ m_length = 0;
+}
+
diff --git a/common/Blob.h b/common/Blob.h
new file mode 100644
index 0000000..e7753b3
--- /dev/null
+++ b/common/Blob.h
@@ -0,0 +1,70 @@
+/*
+ * File: Blob.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Blob_h_)
+#define _Blob_h_
+
+#include "stdafx.h"
+
+/*!
+ * \brief Manages a binary object of arbitrary length.
+ *
+ * The data block is allocated with malloc() instead of the new
+ * operator so that we can use realloc() to resize it.
+ */
+class Blob
+{
+public:
+ //! \brief Default constructor.
+ Blob();
+
+ //! \brief Constructor.
+ Blob(const uint8_t * data, unsigned length);
+
+ //! \brief Copy constructor.
+ Blob(const Blob & other);
+
+ //! \brief Destructor.
+ virtual ~Blob();
+
+ //! \name Operations
+ //@{
+ //! \brief Replaces the blob's data.
+ void setData(const uint8_t * data, unsigned length);
+
+ //! \brief Change the size of the blob's data.
+ void setLength(unsigned length);
+
+ //! \brief Adds data to the end of the blob.
+ void append(const uint8_t * newData, unsigned newDataLength);
+
+ //! \brief Disposes of the data.
+ void clear();
+
+ //! \brief Tell the blob that it no longer owns its data.
+ void relinquish();
+ //@}
+
+ //! \name Accessors
+ //@{
+ uint8_t * getData() { return m_data; }
+ const uint8_t * getData() const { return m_data; }
+ unsigned getLength() const { return m_length; }
+ //@}
+
+ //! \name Operators
+ //@{
+ operator uint8_t * () { return m_data; }
+ operator const uint8_t * () const { return m_data; }
+ //@}
+
+protected:
+ uint8_t * m_data; //!< The binary data held by this object.
+ unsigned m_length; //!< Number of bytes pointed to by #m_data.
+};
+
+#endif // _Blob_h_
+
diff --git a/common/BootImage.h b/common/BootImage.h
new file mode 100644
index 0000000..4ca2c21
--- /dev/null
+++ b/common/BootImage.h
@@ -0,0 +1,54 @@
+/*
+ * File: BootImage.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_BootImage_h_)
+#define _BootImage_h_
+
+#include <iostream>
+#include "Version.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract base class for all boot image format classes.
+ *
+ * Provides virtual methods for all of the common features between different
+ * boot image formats. These are the product and component version numbers
+ * and the drive tag.
+ *
+ * Also provided is the virtual method writeToStream() that lets the caller
+ * stream out the boot image without knowing the underlying format type.
+ */
+class BootImage
+{
+public:
+ //! \brief Constructor.
+ BootImage() {}
+
+ //! \brief Destructor.
+ virtual ~BootImage() {}
+
+ //! \name Versions
+ //@{
+ virtual void setProductVersion(const version_t & version)=0;
+ virtual void setComponentVersion(const version_t & version)=0;
+ //@}
+
+ //! \brief Specify the drive tag to be set in the output file header.
+ virtual void setDriveTag(uint16_t tag)=0;
+
+ //! \brief Returns a string containing the preferred file extension for image format.
+ virtual std::string getFileExtension() const=0;
+
+ //! \brief Write the boot image to an output stream.
+ virtual void writeToStream(std::ostream & stream)=0;
+};
+
+}; // namespace elftosb
+
+#endif // _BootImage_h_
+
diff --git a/common/DataSource.cpp b/common/DataSource.cpp
new file mode 100644
index 0000000..214104b
--- /dev/null
+++ b/common/DataSource.cpp
@@ -0,0 +1,224 @@
+/*
+ * File: DataSource.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "DataSource.h"
+#include "DataTarget.h"
+#include <assert.h>
+#include <string.h>
+using namespace elftosb;
+
+#pragma mark *** DataSource::PatternSegment ***
+
+DataSource::PatternSegment::PatternSegment(DataSource & source)
+: DataSource::Segment(source), m_pattern()
+{
+}
+
+DataSource::PatternSegment::PatternSegment(DataSource & source, const SizedIntegerValue & pattern)
+: DataSource::Segment(source), m_pattern(pattern)
+{
+}
+
+DataSource::PatternSegment::PatternSegment(DataSource & source, uint8_t pattern)
+: DataSource::Segment(source), m_pattern(static_cast<uint8_t>(pattern))
+{
+}
+
+DataSource::PatternSegment::PatternSegment(DataSource & source, uint16_t pattern)
+: DataSource::Segment(source), m_pattern(static_cast<uint16_t>(pattern))
+{
+}
+
+DataSource::PatternSegment::PatternSegment(DataSource & source, uint32_t pattern)
+: DataSource::Segment(source), m_pattern(static_cast<uint32_t>(pattern))
+{
+}
+
+unsigned DataSource::PatternSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
+{
+ memset(buffer, 0, maxBytes);
+
+ return maxBytes;
+}
+
+//! The pattern segment's length is a function of the data target. If the
+//! target is bounded, then the segment's length is simply the target's
+//! length. Otherwise, if no target has been set or the target is unbounded,
+//! then the length returned is 0.
+unsigned DataSource::PatternSegment::getLength()
+{
+ DataTarget * target = m_source.getTarget();
+ if (!target)
+ {
+ return 0;
+ }
+
+ uint32_t length;
+ if (target->isBounded())
+ {
+ length = target->getEndAddress() - target->getBeginAddress();
+ }
+ else
+ {
+ length = m_pattern.getSize();
+ }
+ return length;
+}
+
+#pragma mark *** PatternSource ***
+
+PatternSource::PatternSource()
+: DataSource(), DataSource::PatternSegment((DataSource&)*this)
+{
+}
+
+PatternSource::PatternSource(const SizedIntegerValue & value)
+: DataSource(), DataSource::PatternSegment((DataSource&)*this, value)
+{
+}
+
+#pragma mark *** UnmappedDataSource ***
+
+UnmappedDataSource::UnmappedDataSource()
+: DataSource(), DataSource::Segment((DataSource&)*this), m_data(), m_length(0)
+{
+}
+
+UnmappedDataSource::UnmappedDataSource(const uint8_t * data, unsigned length)
+: DataSource(), DataSource::Segment((DataSource&)*this), m_data(), m_length(0)
+{
+ setData(data, length);
+}
+
+//! Makes a copy of \a data that is freed when the data source is
+//! destroyed. The caller does not have to maintain \a data after this call
+//! returns.
+void UnmappedDataSource::setData(const uint8_t * data, unsigned length)
+{
+ m_data.safe_delete();
+
+ uint8_t * dataCopy = new uint8_t[length];
+ memcpy(dataCopy, data, length);
+ m_data = dataCopy;
+ m_length = length;
+}
+
+unsigned UnmappedDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
+{
+ assert(offset < m_length);
+ unsigned copyBytes = std::min<unsigned>(m_length - offset, maxBytes);
+ memcpy(buffer, m_data.get(), copyBytes);
+ return copyBytes;
+}
+
+#pragma mark *** MemoryImageDataSource ***
+
+MemoryImageDataSource::MemoryImageDataSource(StExecutableImage * image)
+: DataSource(), m_image(image)
+{
+ // reserve enough room for all segments
+ m_segments.reserve(m_image->getRegionCount());
+}
+
+MemoryImageDataSource::~MemoryImageDataSource()
+{
+ segment_array_t::iterator it = m_segments.begin();
+ for (; it != m_segments.end(); ++it)
+ {
+ // delete this segment if it has been created
+ if (*it)
+ {
+ delete *it;
+ }
+ }
+}
+
+unsigned MemoryImageDataSource::getSegmentCount()
+{
+ return m_image->getRegionCount();
+}
+
+DataSource::Segment * MemoryImageDataSource::getSegmentAt(unsigned index)
+{
+ // return previously created segment
+ if (index < m_segments.size() && m_segments[index])
+ {
+ return m_segments[index];
+ }
+
+ // extend array out to this index
+ if (index >= m_segments.size() && index < m_image->getRegionCount())
+ {
+ m_segments.resize(index + 1, NULL);
+ }
+
+ // create the new segment object
+ DataSource::Segment * newSegment;
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(index);
+ if (region.m_type == StExecutableImage::TEXT_REGION)
+ {
+ newSegment = new TextSegment(*this, m_image, index);
+ }
+ else if (region.m_type == StExecutableImage::FILL_REGION)
+ {
+ newSegment = new FillSegment(*this, m_image, index);
+ }
+
+ m_segments[index] = newSegment;
+ return newSegment;
+}
+
+#pragma mark *** MemoryImageDataSource::TextSegment ***
+
+MemoryImageDataSource::TextSegment::TextSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index)
+: DataSource::Segment(source), m_image(image), m_index(index)
+{
+}
+
+unsigned MemoryImageDataSource::TextSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
+{
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(m_index);
+ assert(region.m_type == StExecutableImage::TEXT_REGION);
+
+ unsigned copyBytes = std::min<unsigned>(region.m_length - offset, maxBytes);
+ memcpy(buffer, &region.m_data[offset], copyBytes);
+
+ return copyBytes;
+}
+
+unsigned MemoryImageDataSource::TextSegment::getLength()
+{
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(m_index);
+ return region.m_length;
+}
+
+uint32_t MemoryImageDataSource::TextSegment::getBaseAddress()
+{
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(m_index);
+ return region.m_address;
+}
+
+#pragma mark *** MemoryImageDataSource::FillSegment ***
+
+MemoryImageDataSource::FillSegment::FillSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index)
+: DataSource::PatternSegment(source), m_image(image), m_index(index)
+{
+ SizedIntegerValue zero(0, kWordSize);
+ setPattern(zero);
+}
+
+unsigned MemoryImageDataSource::FillSegment::getLength()
+{
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(m_index);
+ return region.m_length;
+}
+
+uint32_t MemoryImageDataSource::FillSegment::getBaseAddress()
+{
+ const StExecutableImage::MemoryRegion & region = m_image->getRegionAtIndex(m_index);
+ return region.m_address;
+}
diff --git a/common/DataSource.h b/common/DataSource.h
new file mode 100644
index 0000000..4fb9f00
--- /dev/null
+++ b/common/DataSource.h
@@ -0,0 +1,299 @@
+/*
+ * File: DataSource.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_DataSource_h_)
+#define _DataSource_h_
+
+#include <vector>
+#include "Value.h"
+#include "smart_ptr.h"
+#include "StExecutableImage.h"
+
+namespace elftosb
+{
+
+// Forward declaration
+class DataTarget;
+
+/*!
+ * \brief Abstract base class for data sources.
+ *
+ * Data sources represent any sort of data that can be placed or loaded
+ * into a target region. Sources may be a single blob of data read from
+ * a file or may consist of many segments.
+ *
+ * The three most important features of data sources are:
+ * - Sources may be multi-segmented.
+ * - Sources and/or segments can have a "natural" or default target location.
+ * - The target for a source may be taken into consideration when the source
+ * describes itself.
+ */
+class DataSource
+{
+public:
+ /*!
+ * \brief Discrete, contiguous part of the source's data.
+ *
+ * This class is purely abstract and subclasses of DataSource are expected
+ * to subclass it to implement a segment particular to their needs.
+ */
+ class Segment
+ {
+ public:
+ //! \brief Default constructor.
+ Segment(DataSource & source) : m_source(source) {}
+
+ //! \brief Destructor.
+ virtual ~Segment() {}
+
+ //! \brief Gets all or a portion of the segment's data.
+ //!
+ //! The data is copied into \a buffer. Up to \a maxBytes bytes may be
+ //! copied, so \a buffer must be at least that large.
+ //!
+ //! \param offset Index of the first byte to start copying from.
+ //! \param maxBytes The maximum number of bytes that can be returned. \a buffer
+ //! must be at least this large.
+ //! \param buffer Pointer to buffer where the data is copied.
+ //! \return The number of bytes copied into \a buffer.
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)=0;
+
+ //! \brief Gets the length of the segment's data.
+ virtual unsigned getLength()=0;
+
+ //! \brief Returns whether the segment has an associated address.
+ virtual bool hasNaturalLocation()=0;
+
+ //! \brief Returns the address associated with the segment.
+ virtual uint32_t getBaseAddress() { return 0; }
+
+ protected:
+ DataSource & m_source; //!< The data source to which this segment belongs.
+ };
+
+ /*!
+ * \brief This is a special type of segment containing a repeating pattern.
+ *
+ * By default the segment doesn't have a specific length or data. The length depends
+ * on the target's address range. And the data is just the pattern, repeated
+ * many times. In addition, pattern segments do not have a natural location.
+ *
+ * Calling code should look for instances of PatternSegment and handle them
+ * as special cases that can be optimized.
+ */
+ class PatternSegment : public Segment
+ {
+ public:
+ //! \brief Default constructor.
+ PatternSegment(DataSource & source);
+
+ //! \brief Constructor taking a fill pattern.
+ PatternSegment(DataSource & source, const SizedIntegerValue & pattern);
+
+ //! \brief Constructor taking a byte fill pattern.
+ PatternSegment(DataSource & source, uint8_t pattern);
+
+ //! \brief Constructor taking a half-word fill pattern.
+ PatternSegment(DataSource & source, uint16_t pattern);
+
+ //! \brief Constructor taking a word fill pattern.
+ PatternSegment(DataSource & source, uint32_t pattern);
+
+ //! \name Segment methods
+ //@{
+ //! \brief Pattern segments have no natural address.
+ virtual bool hasNaturalLocation() { return false; }
+
+ //! \brief Performs a pattern fill into the \a buffer.
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
+
+ //! \brief Returns a length based on the data target's address range.
+ virtual unsigned getLength();
+ //@}
+
+ //! \name Pattern accessors
+ //@{
+ //! \brief Assigns a new fill pattern.
+ inline void setPattern(const SizedIntegerValue & newPattern) { m_pattern = newPattern; }
+
+ //! \brief Return the fill pattern for the segment.
+ inline SizedIntegerValue & getPattern() { return m_pattern; }
+
+ //! \brief Assignment operator, sets the pattern value and length.
+ PatternSegment & operator = (const SizedIntegerValue & value) { m_pattern = value; return *this; }
+ //@}
+
+ protected:
+ SizedIntegerValue m_pattern; //!< The fill pattern.
+ };
+
+public:
+ //! \brief Default constructor.
+ DataSource() : m_target(0) {}
+
+ //! \brief Destructor.
+ virtual ~DataSource() {}
+
+ //! \name Data target
+ //@{
+ //! \brief Sets the associated data target.
+ inline void setTarget(DataTarget * target) { m_target = target; }
+
+ //! \brief Gets the associated data target.
+ inline DataTarget * getTarget() const { return m_target; }
+ //@}
+
+ //! \name Segments
+ //@{
+ //! \brief Returns the number of segments in this data source.
+ virtual unsigned getSegmentCount()=0;
+
+ //! \brief Returns segment number \a index of the data source.
+ virtual Segment * getSegmentAt(unsigned index)=0;
+ //@}
+
+protected:
+ DataTarget * m_target; //!< Corresponding target for this source.
+};
+
+/*!
+ * \brief Data source for a repeating pattern.
+ *
+ * The pattern is represented by a SizedIntegerValue object. Thus the pattern
+ * can be either byte, half-word, or word sized.
+ *
+ * This data source has only one segment, and the PatternSource instance acts
+ * as its own single segment.
+ */
+class PatternSource : public DataSource, public DataSource::PatternSegment
+{
+public:
+ //! \brief Default constructor.
+ PatternSource();
+
+ //! \brief Constructor taking the pattern value.
+ PatternSource(const SizedIntegerValue & value);
+
+ //! \brief There is only one segment.
+ virtual unsigned getSegmentCount() { return 1; }
+
+ //! \brief Returns this object, as it is its own segment.
+ virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }
+
+ //! \brief Assignment operator, sets the pattern value and length.
+ PatternSource & operator = (const SizedIntegerValue & value) { setPattern(value); return *this; }
+};
+
+/*!
+ * \brief Data source for data that is not memory mapped (has no natural address).
+ *
+ * This data source can only manage a single block of data, which has no
+ * associated address. It acts as its own Segment.
+ */
+class UnmappedDataSource : public DataSource, public DataSource::Segment
+{
+public:
+ //! \brief Default constructor.
+ UnmappedDataSource();
+
+ //! \brief Constructor taking the data, which is copied.
+ UnmappedDataSource(const uint8_t * data, unsigned length);
+
+ //! \brief Sets the source's data.
+ void setData(const uint8_t * data, unsigned length);
+
+ //! \brief There is only one segment.
+ virtual unsigned getSegmentCount() { return 1; }
+
+ //! \brief Returns this object, as it is its own segment.
+ virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }
+
+ //! \name Segment methods
+ //@{
+ //! \brief Unmapped data sources have no natural address.
+ virtual bool hasNaturalLocation() { return false; }
+
+ //! \brief Copies a portion of the data into \a buffer.
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
+
+ //! \brief Returns the number of bytes of data managed by the source.
+ virtual unsigned getLength() { return m_length; }
+ //@}
+
+protected:
+ smart_array_ptr<uint8_t> m_data; //!< The data.
+ unsigned m_length; //!< Byte count of the data.
+};
+
+/*!
+ * \brief Data source that takes its data from an executable image.
+ *
+ * \see StExecutableImage
+ */
+class MemoryImageDataSource : public DataSource
+{
+public:
+ //! \brief Default constructor.
+ MemoryImageDataSource(StExecutableImage * image);
+
+ //! \brief Destructor.
+ virtual ~MemoryImageDataSource();
+
+ //! \brief Returns the number of memory regions in the image.
+ virtual unsigned getSegmentCount();
+
+ //! \brief Returns the data source segment at position \a index.
+ virtual DataSource::Segment * getSegmentAt(unsigned index);
+
+protected:
+ /*!
+ * \brief Segment corresponding to a text region of the executable image.
+ */
+ class TextSegment : public DataSource::Segment
+ {
+ public:
+ //! \brief Default constructor
+ TextSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index);
+
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
+ virtual unsigned getLength();
+
+ virtual bool hasNaturalLocation() { return true; }
+ virtual uint32_t getBaseAddress();
+
+ protected:
+ StExecutableImage * m_image; //!< Coalesced image of the file.
+ unsigned m_index; //!< Record index.
+ };
+
+ /*!
+ * \brief Segment corresponding to a fill region of the executable image.
+ */
+ class FillSegment : public DataSource::PatternSegment
+ {
+ public:
+ FillSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index);
+
+ virtual unsigned getLength();
+
+ virtual bool hasNaturalLocation() { return true; }
+ virtual uint32_t getBaseAddress();
+
+ protected:
+ StExecutableImage * m_image; //!< Coalesced image of the file.
+ unsigned m_index; //!< Record index.
+ };
+
+protected:
+ StExecutableImage * m_image; //!< The memory image that is the data source.
+
+ typedef std::vector<DataSource::Segment*> segment_array_t; //!< An array of segments.
+ segment_array_t m_segments; //!< The array of Segment instances.
+};
+
+}; // namespace elftosb
+
+#endif // _DataSource_h_
diff --git a/common/DataSourceImager.cpp b/common/DataSourceImager.cpp
new file mode 100644
index 0000000..14a9307
--- /dev/null
+++ b/common/DataSourceImager.cpp
@@ -0,0 +1,143 @@
+/*
+ * File: DataSourceImager.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "DataSourceImager.h"
+#include <stdlib.h>
+#include <string.h>
+
+using namespace elftosb;
+
+DataSourceImager::DataSourceImager()
+: Blob(),
+ m_fill(0),
+ m_baseAddress(0),
+ m_isBaseAddressSet(false)
+{
+}
+
+void DataSourceImager::setBaseAddress(uint32_t address)
+{
+ m_baseAddress = address;
+ m_isBaseAddressSet = true;
+}
+
+void DataSourceImager::setFillPattern(uint8_t pattern)
+{
+ m_fill = pattern;
+}
+
+void DataSourceImager::reset()
+{
+ clear();
+
+ m_fill = 0;
+ m_baseAddress = 0;
+ m_isBaseAddressSet = false;
+}
+
+//! \param dataSource Pointer to an instance of a concrete data source subclass.
+//!
+void DataSourceImager::addDataSource(DataSource * source)
+{
+ unsigned segmentCount = source->getSegmentCount();
+ unsigned index = 0;
+ for (; index < segmentCount; ++index)
+ {
+ addDataSegment(source->getSegmentAt(index));
+ }
+}
+
+//! \param segment The segment to add. May be any type of data segment, including
+//! a pattern segment.
+void DataSourceImager::addDataSegment(DataSource::Segment * segment)
+{
+ DataSource::PatternSegment * patternSegment = dynamic_cast<DataSource::PatternSegment*>(segment);
+
+ unsigned segmentLength = segment->getLength();
+ bool segmentHasLocation = segment->hasNaturalLocation();
+ uint32_t segmentAddress = segment->getBaseAddress();
+
+ uint8_t * toPtr = NULL;
+ unsigned addressDelta;
+ unsigned newLength;
+
+ // If a pattern segment's length is 0 then make it as big as the fill pattern.
+ // This needs to be done before the buffer is adjusted.
+ if (patternSegment && segmentLength == 0)
+ {
+ SizedIntegerValue & pattern = patternSegment->getPattern();
+ segmentLength = pattern.getSize();
+ }
+
+ if (segmentLength)
+ {
+ if (segmentHasLocation)
+ {
+ // Make sure a base address is set.
+ if (!m_isBaseAddressSet)
+ {
+ m_baseAddress = segmentAddress;
+ m_isBaseAddressSet = true;
+ }
+
+ // The segment is located before our buffer's first address.
+ // toPtr is not set in this if, but in the else branch of the next if.
+ // Unless the segment completely overwrite the current data.
+ if (segmentAddress < m_baseAddress)
+ {
+ addressDelta = m_baseAddress - segmentAddress;
+
+ uint8_t * newData = (uint8_t *)malloc(m_length + addressDelta);
+ memcpy(&newData[addressDelta], m_data, m_length);
+ free(m_data);
+
+ m_data = newData;
+ m_length += addressDelta;
+ m_baseAddress = segmentAddress;
+ }
+
+ // This segment is located or extends outside of our buffer.
+ if (segmentAddress + segmentLength > m_baseAddress + m_length)
+ {
+ newLength = segmentAddress + segmentLength - m_baseAddress;
+
+ m_data = (uint8_t *)realloc(m_data, newLength);
+
+ // Clear any bytes between the old data and the new segment.
+ addressDelta = segmentAddress - (m_baseAddress + m_length);
+ if (addressDelta)
+ {
+ memset(m_data + m_length, 0, addressDelta);
+ }
+
+ toPtr = m_data + (segmentAddress - m_baseAddress);
+ m_length = newLength;
+ }
+ else
+ {
+ toPtr = m_data + (segmentAddress - m_baseAddress);
+ }
+ }
+ // Segment has no natural location, so just append it to the end of our buffer.
+ else
+ {
+ newLength = m_length + segmentLength;
+ m_data = (uint8_t *)realloc(m_data, newLength);
+ toPtr = m_data + m_length;
+ m_length = newLength;
+ }
+ }
+
+ // A loop is used because getData() may fill in less than the requested
+ // number of bytes per call.
+ unsigned offset = 0;
+ while (offset < segmentLength)
+ {
+ offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
+ }
+}
+
diff --git a/common/DataSourceImager.h b/common/DataSourceImager.h
new file mode 100644
index 0000000..00e61df
--- /dev/null
+++ b/common/DataSourceImager.h
@@ -0,0 +1,54 @@
+/*
+ * File: DataSourceImager.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_DataSourceImager_h_)
+#define _DataSourceImager_h_
+
+#include "Blob.h"
+#include "DataSource.h"
+
+namespace elftosb {
+
+/*!
+ * \brief Converts a DataSource into a single binary buffer.
+ */
+class DataSourceImager : public Blob
+{
+public:
+ //! \brief Constructor.
+ DataSourceImager();
+
+ //! \name Setup
+ //@{
+ void setBaseAddress(uint32_t address);
+ void setFillPattern(uint8_t pattern);
+ //@}
+
+ void reset();
+
+ //! \name Accessors
+ //@{
+ uint32_t getBaseAddress() { return m_baseAddress; }
+ //@}
+
+ //! \name Operations
+ //@{
+ //! \brief Adds all of the segments of which \a dataSource is composed.
+ void addDataSource(DataSource * source);
+
+ //! \brief Adds the data from one data segment.
+ void addDataSegment(DataSource::Segment * segment);
+ //@}
+
+protected:
+ uint8_t m_fill;
+ uint32_t m_baseAddress;
+ bool m_isBaseAddressSet;
+};
+
+};
+
+#endif // _DataSourceImager_h_
diff --git a/common/DataTarget.cpp b/common/DataTarget.cpp
new file mode 100644
index 0000000..aab2c7b
--- /dev/null
+++ b/common/DataTarget.cpp
@@ -0,0 +1,59 @@
+/*
+ * File: DataTarget.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "DataTarget.h"
+#include "DataSource.h"
+#include "ElftosbErrors.h"
+
+using namespace elftosb;
+
+//! \exception elftosb::semantic_error Thrown if the source has multiple segments.
+DataTarget::AddressRange ConstantDataTarget::getRangeForSegment(DataSource & source, DataSource::Segment & segment)
+{
+ // can't handle multi-segment data sources
+ if (source.getSegmentCount() > 1)
+ {
+ throw semantic_error("constant targets only support single-segment sources");
+ }
+
+ // always relocate the segment to our begin address
+ AddressRange range;
+ range.m_begin = m_begin;
+
+ if (isBounded())
+ {
+ // we have an end address. trim the result range to the segment size
+ // or let the end address crop the segment.
+ range.m_end = std::min<uint32_t>(m_end, m_begin + segment.getLength());
+ }
+ else
+ {
+ // we have no end address, so the segment size determines it.
+ range.m_end = m_begin + segment.getLength();
+ }
+
+ return range;
+}
+
+//! If the \a segment has a natural location, the returned address range extends
+//! from the segment's base address to its base address plus its length.
+//!
+//! \exception elftosb::semantic_error This exception is thrown if the \a segment
+//! does not have a natural location associated with it.
+DataTarget::AddressRange NaturalDataTarget::getRangeForSegment(DataSource & source, DataSource::Segment & segment)
+{
+ if (!segment.hasNaturalLocation())
+ {
+ throw semantic_error("source has no natural location");
+ }
+
+ AddressRange range;
+ range.m_begin = segment.getBaseAddress();
+ range.m_end = segment.getBaseAddress() + segment.getLength();
+ return range;
+}
+
diff --git a/common/DataTarget.h b/common/DataTarget.h
new file mode 100644
index 0000000..e154491
--- /dev/null
+++ b/common/DataTarget.h
@@ -0,0 +1,122 @@
+/*
+ * File: DataTarget.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_DataTarget_h_)
+#define _DataTarget_h_
+
+#include "stdafx.h"
+#include "DataSource.h"
+
+namespace elftosb
+{
+
+// Forward declaration
+class DataSource;
+
+/*!
+ * \brief Abstract base class for the target address or range of data.
+ *
+ * Targets at the most basic level have a single address, and potentially
+ * an address range. Unbounded targets have a beginning address but no
+ * specific end address, while bounded targets do have an end address.
+ *
+ * Users of a data target can access the begin and end addresses directly.
+ * However, the most powerful way to use a target is with the
+ * getRangeForSegment() method. This method returns the target address range
+ * for a segment of a data source. The value of the resulting range can be
+ * completely dependent upon the segment's properties, those of its data
+ * source, and the type of data target.
+ *
+ * \see elftosb::DataSource
+ */
+class DataTarget
+{
+public:
+ //! \brief Simple structure that describes an addressed region of memory.
+ //! \todo Decide if the end address is inclusive or not.
+ struct AddressRange
+ {
+ uint32_t m_begin;
+ uint32_t m_end;
+ };
+
+public:
+ //! \brief Default constructor.
+ DataTarget() : m_source(0) {}
+
+ //! \brief Destructor.
+ virtual ~DataTarget() {}
+
+ //! \brief Whether the target is just a single address or has an end to it.
+ virtual bool isBounded() { return false; }
+
+ virtual uint32_t getBeginAddress() { return 0; }
+ virtual uint32_t getEndAddress() { return 0; }
+
+ //! \brief Return the address range for a segment of a data source.
+ virtual DataTarget::AddressRange getRangeForSegment(DataSource & source, DataSource::Segment & segment)=0;
+
+ inline void setSource(DataSource * source) { m_source = source; }
+ inline DataSource * getSource() const { return m_source; }
+
+protected:
+ DataSource * m_source; //!< Corresponding data source for this target.
+};
+
+/*!
+ * \brief Target with a constant values for the addresses.
+ *
+ * This target type supports can be both bounded and unbounded. It always has
+ * at least one address, the beginning address. The end address is optional,
+ * and if not provided makes the target unbounded.
+ */
+class ConstantDataTarget : public DataTarget
+{
+public:
+ //! \brief Constructor taking only a begin address.
+ ConstantDataTarget(uint32_t start) : DataTarget(), m_begin(start), m_end(0), m_hasEnd(false) {}
+
+ //! \brief Constructor taking both begin and end addresses.
+ ConstantDataTarget(uint32_t start, uint32_t end) : DataTarget(), m_begin(start), m_end(end), m_hasEnd(true) {}
+
+ //! \brief The target is bounded if an end address was specified.
+ virtual bool isBounded() { return m_hasEnd; }
+
+ virtual uint32_t getBeginAddress() { return m_begin; }
+ virtual uint32_t getEndAddress() { return m_end; }
+
+ //! \brief Return the address range for a segment of a data source.
+ virtual DataTarget::AddressRange getRangeForSegment(DataSource & source, DataSource::Segment & segment);
+
+protected:
+ uint32_t m_begin; //!< Start address.
+ uint32_t m_end; //!< End address.
+ bool m_hasEnd; //!< Was an end address specified?
+};
+
+/*!
+ * \brief Target address that is the "natural" location of whatever the source data is.
+ *
+ * The data source used with the target must have a natural location. If
+ * getRangeForSegment() is called with a segment that does not have a natural
+ * location, a semantic_error will be thrown.
+ */
+class NaturalDataTarget : public DataTarget
+{
+public:
+ //! \brief Default constructor.
+ NaturalDataTarget() : DataTarget() {}
+
+ //! \brief Natural data targets are bounded by their source's segment lengths.
+ virtual bool isBounded() { return true; }
+
+ //! \brief Return the address range for a segment of a data source.
+ virtual DataTarget::AddressRange getRangeForSegment(DataSource & source, DataSource::Segment & segment);
+};
+
+}; // namespace elftosb
+
+#endif // _DataTarget_h_
diff --git a/common/ELF.h b/common/ELF.h
new file mode 100644
index 0000000..f477610
--- /dev/null
+++ b/common/ELF.h
@@ -0,0 +1,332 @@
+/*
+ * File: ELF.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ELF_h_)
+#define _ELF_h_
+
+//! \name ELF types
+//! Types used in ELF file structures.
+//@{
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef /*off_t*/ uint32_t Elf32_Off;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
+//@}
+
+// All ELF structures are byte aligned. Any alignment padding is explicit.
+#pragma pack(1)
+
+//! \name File header
+//@{
+
+/*!
+ * Constants for the various fields of Elf32_Ehdr.e_ident.
+ */
+enum {
+ EI_MAG0 = 0,
+ EI_MAG1,
+ EI_MAG2,
+ EI_MAG3,
+ EI_CLASS,
+ EI_DATA,
+ EI_VERSION,
+ EI_PAD,
+ EI_NIDENT = 16,
+
+ // Magic number.
+ ELFMAG0 = 0x7f,
+ ELFMAG1 = 'E',
+ ELFMAG2 = 'L',
+ ELFMAG3 = 'F',
+
+ // EI_CLASS
+ ELFCLASSNONE = 0,
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+
+ // EI_DATA
+ ELFDATANONE = 0,
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2
+};
+
+/*!
+ * \brief ELF file header.
+ */
+struct Elf32_Ehdr
+{
+ unsigned char e_ident[EI_NIDENT]; //!< Magic number identifying the file format.
+ Elf32_Half e_type; //!< Identifies the object file format.
+ Elf32_Half e_machine; //!< Specified the architecture for the object file.
+ Elf32_Word e_version; //!< Object file version.
+ Elf32_Addr e_entry; //!< Virtual address of the entry point, or 0.
+ Elf32_Off e_phoff; //!< Program header table offset in bytes, or 0 if no program header table.
+ Elf32_Off e_shoff; //!< Section header table offset in bytes, or 0 if no section header table.
+ Elf32_Word e_flags; //!< Processor-specific flags associated with the file.
+ Elf32_Half e_ehsize; //!< The ELF header's size in bytes.
+ Elf32_Half e_phentsize; //!< Size in bytes of one entry in the program header table.
+ Elf32_Half e_phnum; //!< Number of entries in the program header table.
+ Elf32_Half e_shentsize; //!< Size in bytes of an entry in the section header table.
+ Elf32_Half e_shnum; //!< Number of entries in the section header table.
+ Elf32_Half e_shstrndx; //!< Section header table index of the section name string table.
+};
+
+/*!
+ * Constants for #Elf32_Ehdr.e_type.
+ */
+enum {
+ ET_NONE, //!< No file type.
+ ET_REL, //!< Relocatable file.
+ ET_EXEC, //!< Executable file.
+ ET_DYN, //!< Shared object file.
+ ET_CORE, //!< Core file.
+ ET_LOPROC, //!< Low bound of processor-specific file types.
+ ET_HIPROC //!< High bound of processor-specific file types.
+};
+
+/*!
+ * ARM-specific #Elf32_Ehdr.e_flags
+ */
+enum {
+ EF_ARM_HASENTRY = 0x02, //!< #Elf32_Ehdr.e_entry contains a program-loader entry point.
+ EF_ARM_SYMSARESORTED = 0x04, //!< Each subsection of the symbol table is sorted by symbol value.
+ EF_ARM_DYNSYMSUSESEGIDX = 0x08, //!< Symbols in dynamic symbol tables that are defined in sections included in program segment n have #Elf32_Sym.st_shndx = n + 1.
+ EF_ARM_MAPSYMSFIRST = 0x10, //!< Mapping symbols precede other local symbols in the symbol table.
+ EF_ARM_EABIMASK = 0xff000000, //!< This masks an 8-bit version number, the version of the ARM EABI to which this ELF file conforms. The current EABI version is #ARM_EABI_VERSION.
+
+ ARM_EABI_VERSION = 0x02000000 //!< Current ARM EABI version.
+};
+
+//@}
+
+//! \name Sections
+//@{
+
+/*!
+ * \brief ELF section header.
+ *
+ * An object file's section header table lets one locate all the file's
+ * sections. The section header table is an array of #Elf32_Shdr structures.
+ * A section header table index is a subscript into this array. The ELF
+ * header's #Elf32_Ehdr::e_shoff member gives the byte offset from the beginning of
+ * the file to the section header table; #Elf32_Ehdr::e_shnum tells how many entries
+ * the section header table contains; #Elf32_Ehdr::e_shentsize gives the size in bytes
+ * of each entry.
+ *
+ * Some section header table indexes are reserved. An object file will not
+ * have sections for these special indexes:
+ * - #SHN_UNDEF
+ * - #SHN_LORESERVE
+ * - #SHN_LOPROC
+ * - #SHN_HIPROC
+ * - #SHN_ABS
+ * - #SHN_COMMON
+ * - #SHN_HIRESERVE
+ */
+struct Elf32_Shdr
+{
+ Elf32_Word sh_name; //!< The section's name. Index into the section header string table section.
+ Elf32_Word sh_type; //!< Section type, describing the contents and semantics.
+ Elf32_Word sh_flags; //!< Section flags describing various attributes.
+ Elf32_Addr sh_addr; //!< The address at which the section will appear in the memory image, or 0.
+ Elf32_Off sh_offset; //!< Offset from beginning of the file to the first byte in the section.
+ Elf32_Word sh_size; //!< The section's size in bytes.
+ Elf32_Word sh_link; //!< Section header table link index. Interpretation depends on section type.
+ Elf32_Word sh_info; //!< Extra information about the section. Depends on section type.
+ Elf32_Word sh_addralign; //!< Address alignment constraint. Values are 0 and positive powers of 2.
+ Elf32_Word sh_entsize; //!< Size in bytes of section entries, or 0 if the section does not have fixed-size entries.
+};
+
+/*!
+ * Special section indexes.
+ */
+enum {
+ SHN_UNDEF = 0,
+ SHN_LORESERVE = 0xff00,
+ SHN_LOPROC = 0xff00,
+ SHN_HIPROC = 0xff1f,
+ SHN_ABS = 0xfff1, //!< The symbol has an absolute value that will not change because of relocation.
+ SHN_COMMON = 0xfff2, //!< The symbol labels a common block that has not yet been allocated.
+ SHN_HIRESERVE = 0xffff
+};
+
+/*!
+ * Section type constants.
+ */
+enum {
+ SHT_NULL = 0,
+ SHT_PROGBITS = 1,
+ SHT_SYMTAB = 2,
+ SHT_STRTAB = 3,
+ SHT_RELA = 4,
+ SHT_HASH = 5,
+ SHT_DYNAMIC = 6,
+ SHT_NOTE = 7,
+ SHT_NOBITS = 8,
+ SHT_REL = 9,
+ SHT_SHLIB = 10,
+ SHT_DYNSYM = 11
+};
+
+/*!
+ * Section flag constants.
+ */
+enum {
+ SHF_WRITE = 0x1, //!< Section is writable.
+ SHF_ALLOC = 0x2, //!< Allocate section.
+ SHF_EXECINSTR = 0x4 //!< Section contains executable instructions.
+};
+
+/*!
+ * ARM-specific section flag constants
+ */
+enum {
+ SHF_ENTRYSECT = 0x10000000, //!< The section contains an entry point.
+ SHF_COMDEF = 0x80000000 //!< The section may be multiply defined in the input to a link step.
+};
+
+#define BSS_SECTION_NAME ".bss"
+#define DATA_SECTION_NAME ".data"
+#define TEXT_SECTION_NAME ".text"
+#define SHSTRTAB_SECTION_NAME ".shstrtab"
+#define STRTAB_SECTION_NAME ".strtab"
+#define SYMTAB_SECTION_NAME ".symtab"
+
+//@}
+
+//! \name Segments
+//@{
+
+/*!
+ * \brief ELF program header.
+ *
+ * An executable or shared object file's program header table is an array of
+ * structures, each describing a segment or other information the system needs
+ * to prepare the program for execution. An object file segment contains one
+ * or more sections. Program headers are meaningful only for executable and
+ * shared object files. A file specifies its own program header size with the
+ * ELF header's #Elf32_Ehdr::e_phentsize and #Elf32_Ehdr::e_phnum members.
+ */
+struct Elf32_Phdr
+{
+ Elf32_Word p_type; //!< What type of segment this header describes.
+ Elf32_Off p_offset; //!< Offset in bytes from start of file to the first byte of the segment.
+ Elf32_Addr p_vaddr; //!< Virtual address at which the segment will reside in memory.
+ Elf32_Addr p_paddr; //!< Physical address, for systems where this is relevant.
+ Elf32_Word p_filesz; //!< Number of bytes of file data the segment consumes. May be zero.
+ Elf32_Word p_memsz; //!< Size in bytes of the segment in memory. May be zero.
+ Elf32_Word p_flags; //!< Flags relevant to the segment.
+ Elf32_Word p_align; //!< Alignment constraint for segment addresses. Possible values are 0 and positive powers of 2.
+};
+
+/*!
+ * Segment type constants.
+ */
+enum {
+ PT_NULL = 0,
+ PT_LOAD = 1,
+ PT_DYNAMIC = 2,
+ PT_INTERP = 3,
+ PT_NOTE = 4,
+ PT_SHLIB = 5,
+ PT_PHDR = 6
+};
+
+/*!
+ * Program header flag constants.
+ */
+enum {
+ PF_X = 0x1, //!< Segment is executable.
+ PF_W = 0x2, //!< Segment is writable.
+ PF_R = 0x4 //!< Segment is readable.
+};
+
+//@}
+
+//! \name Symbol table
+//@{
+
+enum {
+ STN_UNDEF = 0 //!< Undefined symbol index.
+};
+
+/*!
+ * \brief ELF symbol table entry.
+ *
+ * An object file's symbol table holds information needed to locate and
+ * relocate a program's symbolic definitions and references. A symbol
+ * table index is a subscript into this array. Index 0 both designates
+ * the first entry in the table and serves as the undefined symbol index.
+ */
+struct Elf32_Sym
+{
+ Elf32_Word st_name; //!< Index into file's string table.
+ Elf32_Addr st_value; //!< Value associated with the symbol. Depends on context.
+ Elf32_Word st_size; //!< Size associated with symbol. 0 if the symbol has no size or an unknown size.
+ unsigned char st_info; //!< Specified the symbol's type and binding attributes.
+ unsigned char st_other; //!< Currently 0 (reserved).
+ Elf32_Half st_shndx; //!< Section header table index for this symbol.
+};
+
+//! \name st_info macros
+//! Macros for manipulating the st_info field of Elf32_Sym struct.
+//@{
+#define ELF32_ST_BIND(i) ((i) >> 4) //!< Get binding attributes.
+#define ELF32_ST_TYPE(i) ((i) & 0x0f) //!< Get symbol type.
+#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0x0f)) //!< Construct st_info value from binding attributes and symbol type.
+//@}
+
+/*!
+ * \brief Symbol binding attributes.
+ *
+ * These constants are mask values.
+ */
+enum {
+ STB_LOCAL = 0, //!< Local symbol not visible outside the object file.
+ STB_GLOBAL = 1, //!< Symbol is visible to all object files being linked together.
+ STB_WEAK = 2, //!< Like global symbols, but with lower precedence.
+
+ // Processor-specific semantics.
+ STB_LOPROC = 13,
+ STB_HIPROC = 15
+};
+
+/*!
+ * \brief Symbol types.
+ */
+enum {
+ STT_NOTYPE = 0, //!< The symbol's type is not specified.
+ STT_OBJECT = 1, //!< The symbol is associated with a data object, such as a variable or array.
+ STT_FUNC = 2, //!< The symbol is associated with a function or other executable code.
+ STT_SECTION = 3, //!< The synmbol is associated with a section. Primarily used for relocation.
+ STT_FILE = 4, //!< A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other STB_LOCAL symbols for the file, if it is present.
+
+ STT_LOPROC = 13, //!< Low bound of processor-specific symbol types.
+ STT_HIPROC = 15 //!< High bound of processor-specific symbol types.
+};
+
+/*!
+ * GHS-specific constants
+ */
+enum {
+ STO_THUMB = 1 //!< This flag is set on #Elf32_Sym.st_other if the symbol is Thumb mode code.
+};
+
+#define ARM_SEQUENCE_MAPSYM "$a"
+#define DATA_SEQUENCE_MAPSYM "$d"
+#define THUMB_SEQUENCE_MAPSYM "$t"
+
+#define THUMB_BL_TAGSYM "$b"
+#define FN_PTR_CONST_TAGSYM "$f"
+#define INDIRECT_FN_CALL_TAGSYM "$p"
+#define MAPPING_SYMBOL_COUNT_TAGSYM "$m"
+
+//@}
+
+#pragma pack()
+
+#endif // _ELF_h_
diff --git a/common/ELFSourceFile.cpp b/common/ELFSourceFile.cpp
new file mode 100644
index 0000000..68f99ff
--- /dev/null
+++ b/common/ELFSourceFile.cpp
@@ -0,0 +1,529 @@
+/*
+ * File: ELFSourceFile.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "ELFSourceFile.h"
+#include "Logging.h"
+#include "GHSSecInfo.h"
+#include <ctype.h>
+#include <algorithm>
+#include "string.h"
+
+//! The name of the toolset option.
+#define kToolsetOptionName "toolset"
+#define kGHSToolsetName "GHS"
+#define kGCCToolsetName "GCC"
+#define kGNUToolsetName "GNU"
+#define kADSToolsetName "ADS"
+
+//! Name of the option to control .secinfo action.
+#define kSecinfoClearOptionName "secinfoClear"
+#define kSecinfoDefaultName "DEFAULT"
+#define kSecinfoIgnoreName "IGNORE"
+#define kSecinfoROMName "ROM"
+#define kSecinfoCName "C"
+
+using namespace elftosb;
+
+ELFSourceFile::ELFSourceFile(const std::string & path)
+: SourceFile(path),
+ m_toolset(kUnknownToolset),
+ m_secinfoOption(kSecinfoDefault)
+{
+}
+
+ELFSourceFile::~ELFSourceFile()
+{
+}
+
+bool ELFSourceFile::isELFFile(std::istream & stream)
+{
+ try
+ {
+ StELFFile elf(stream);
+ return true;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
+
+void ELFSourceFile::open()
+{
+ // Read toolset option
+ m_toolset = readToolsetOption();
+
+ // Read option and select default value
+ m_secinfoOption = readSecinfoClearOption();
+ if (m_secinfoOption == kSecinfoDefault)
+ {
+ m_secinfoOption = kSecinfoCStartupClear;
+ }
+
+ // Open the stream
+ SourceFile::open();
+
+ m_file = new StELFFile(*m_stream);
+// m_file->dumpSections();
+
+ // Set toolset in elf file object
+ switch (m_toolset)
+ {
+ // default toolset is GHS
+ case kGHSToolset:
+ case kUnknownToolset:
+ m_file->setELFVariant(eGHSVariant);
+ break;
+ case kGCCToolset:
+ m_file->setELFVariant(eGCCVariant);
+ break;
+ case kADSToolset:
+ m_file->setELFVariant(eARMVariant);
+ break;
+ }
+}
+
+void ELFSourceFile::close()
+{
+ SourceFile::close();
+
+ m_file.safe_delete();
+}
+
+elf_toolset_t ELFSourceFile::readToolsetOption()
+{
+ do {
+ const OptionContext * options = getOptions();
+ if (!options || !options->hasOption(kToolsetOptionName))
+ {
+ break;
+ }
+
+ const Value * value = options->getOption(kToolsetOptionName);
+ const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
+ if (!stringValue)
+ {
+ // Not a string value, warn the user.
+ Log::log(Logger::WARNING, "invalid type for 'toolset' option\n");
+ break;
+ }
+
+ std::string toolsetName = *stringValue;
+
+ // convert option value to uppercase
+ std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(toolsetName.begin(), toolsetName.end(), toolsetName.begin(), toupper);
+
+ if (toolsetName == kGHSToolsetName)
+ {
+ return kGHSToolset;
+ }
+ else if (toolsetName == kGCCToolsetName || toolsetName == kGNUToolsetName)
+ {
+ return kGCCToolset;
+ }
+ else if (toolsetName == kADSToolsetName)
+ {
+ return kADSToolset;
+ }
+
+ // Unrecognized option value, log a warning.
+ Log::log(Logger::WARNING, "unrecognized value for 'toolset' option\n");
+ } while (0);
+
+ return kUnknownToolset;
+}
+
+//! It is up to the caller to convert from kSecinfoDefault to the actual default
+//! value.
+secinfo_clear_t ELFSourceFile::readSecinfoClearOption()
+{
+ do {
+ const OptionContext * options = getOptions();
+ if (!options || !options->hasOption(kSecinfoClearOptionName))
+ {
+ break;
+ }
+
+ const Value * value = options->getOption(kSecinfoClearOptionName);
+ const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
+ if (!stringValue)
+ {
+ // Not a string value, warn the user.
+ Log::log(Logger::WARNING, "invalid type for 'secinfoClear' option\n");
+ break;
+ }
+
+ std::string secinfoOption = *stringValue;
+
+ // convert option value to uppercase
+ std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(secinfoOption.begin(), secinfoOption.end(), secinfoOption.begin(), toupper);
+
+ if (secinfoOption == kSecinfoDefaultName)
+ {
+ return kSecinfoDefault;
+ }
+ else if (secinfoOption == kSecinfoIgnoreName)
+ {
+ return kSecinfoIgnore;
+ }
+ else if (secinfoOption == kSecinfoROMName)
+ {
+ return kSecinfoROMClear;
+ }
+ else if (secinfoOption == kSecinfoCName)
+ {
+ return kSecinfoCStartupClear;
+ }
+
+ // Unrecognized option value, log a warning.
+ Log::log(Logger::WARNING, "unrecognized value for 'secinfoClear' option\n");
+ } while (0);
+
+ return kSecinfoDefault;
+}
+
+//! To create a data source for all sections of the ELF file, a WildcardMatcher
+//! is instantiated and passed to createDataSource(StringMatcher&).
+DataSource * ELFSourceFile::createDataSource()
+{
+ WildcardMatcher matcher;
+ return createDataSource(matcher);
+}
+
+DataSource * ELFSourceFile::createDataSource(StringMatcher & matcher)
+{
+ assert(m_file);
+ ELFDataSource * source = new ELFDataSource(m_file);
+ source->setSecinfoOption(m_secinfoOption);
+
+ Log::log(Logger::DEBUG2, "filtering sections of file: %s\n", getPath().c_str());
+
+ // We start at section 1 to skip the null section that is always first.
+ unsigned index = 1;
+ for (; index < m_file->getSectionCount(); ++index)
+ {
+ const Elf32_Shdr & header = m_file->getSectionAtIndex(index);
+ std::string name = m_file->getSectionNameAtIndex(header.sh_name);
+
+ // Ignore most section types
+ if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
+ {
+ continue;
+ }
+
+ // Ignore sections that don't have the allocate flag set.
+ if ((header.sh_flags & SHF_ALLOC) == 0)
+ {
+ continue;
+ }
+
+ if (matcher.match(name))
+ {
+ Log::log(Logger::DEBUG2, "creating segment for section %s\n", name.c_str());
+ source->addSection(index);
+ }
+ else
+ {
+ Log::log(Logger::DEBUG2, "section %s did not match\n", name.c_str());
+ }
+ }
+
+ return source;
+}
+
+//! It is assumed that all ELF files have an entry point.
+//!
+bool ELFSourceFile::hasEntryPoint()
+{
+ return true;
+}
+
+//! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
+//! ARM/Thumb mode depending on the toolset.
+uint32_t ELFSourceFile::getEntryPointAddress()
+{
+ uint32_t entryPoint = 0;
+
+ // get entry point address
+ const Elf32_Ehdr & header = m_file->getFileHeader();
+
+ // find symbol corresponding to entry point and determine if
+ // it is arm or thumb mode
+ unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
+ if (symbolIndex != 0)
+ {
+ ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
+ bool entryPointIsThumb = (symbolType == eThumbSymbol);
+ const Elf32_Sym & symbol = m_file->getSymbolAtIndex(symbolIndex);
+ std::string symbolName = m_file->getSymbolName(symbol);
+
+ Log::log(Logger::DEBUG2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value, entryPointIsThumb ? "Thumb" : "ARM");
+
+ // set entry point, setting the low bit if it is thumb mode
+ entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
+ }
+ else
+ {
+ entryPoint = header.e_entry;
+ }
+
+ return entryPoint;
+}
+
+//! \return A DataTarget that describes the named section.
+//! \retval NULL There was no section with the requested name.
+DataTarget * ELFSourceFile::createDataTargetForSection(const std::string & section)
+{
+ assert(m_file);
+ unsigned index = m_file->getIndexOfSectionWithName(section);
+ if (index == SHN_UNDEF)
+ {
+ return NULL;
+ }
+
+ const Elf32_Shdr & sectionHeader = m_file->getSectionAtIndex(index);
+ uint32_t beginAddress = sectionHeader.sh_addr;
+ uint32_t endAddress = beginAddress + sectionHeader.sh_size;
+ ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
+ return target;
+}
+
+//! \return A DataTarget instance pointing at the requested symbol.
+//! \retval NULL No symbol matching the requested name was found.
+DataTarget * ELFSourceFile::createDataTargetForSymbol(const std::string & symbol)
+{
+ assert(m_file);
+ unsigned symbolCount = m_file->getSymbolCount();
+ unsigned i;
+
+ for (i=0; i < symbolCount; ++i)
+ {
+ const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
+ std::string symbolName = m_file->getSymbolName(symbolHeader);
+ if (symbolName == symbol)
+ {
+ ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
+ bool symbolIsThumb = (symbolType == eThumbSymbol);
+
+ uint32_t beginAddress = symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
+ uint32_t endAddress = beginAddress + symbolHeader.st_size;
+ ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
+ return target;
+ }
+ }
+
+ // didn't find a matching symbol
+ return NULL;
+}
+
+bool ELFSourceFile::hasSymbol(const std::string & name)
+{
+ Elf32_Sym symbol;
+ return lookupSymbol(name, symbol);
+}
+
+uint32_t ELFSourceFile::getSymbolValue(const std::string & name)
+{
+ unsigned symbolCount = m_file->getSymbolCount();
+ unsigned i;
+
+ for (i=0; i < symbolCount; ++i)
+ {
+ const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
+ std::string symbolName = m_file->getSymbolName(symbolHeader);
+ if (symbolName == name)
+ {
+ // If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
+ if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
+ {
+ ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
+ bool symbolIsThumb = (symbolType == eThumbSymbol);
+ return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
+ }
+ else
+ {
+ return symbolHeader.st_value;
+ }
+ }
+ }
+
+ // Couldn't find the symbol, so return 0.
+ return 0;
+}
+
+unsigned ELFSourceFile::getSymbolSize(const std::string & name)
+{
+ Elf32_Sym symbol;
+ if (!lookupSymbol(name, symbol))
+ {
+ return 0;
+ }
+
+ return symbol.st_size;
+}
+
+//! \param name The name of the symbol on which info is wanted.
+//! \param[out] info Upon succssful return this is filled in with the symbol's information.
+//!
+//! \retval true The symbol was found and \a info is valid.
+//! \retval false No symbol with \a name was found in the file.
+bool ELFSourceFile::lookupSymbol(const std::string & name, Elf32_Sym & info)
+{
+ assert(m_file);
+ unsigned symbolCount = m_file->getSymbolCount();
+ unsigned i;
+
+ for (i=0; i < symbolCount; ++i)
+ {
+ const Elf32_Sym & symbol = m_file->getSymbolAtIndex(i);
+ std::string thisSymbolName = m_file->getSymbolName(symbol);
+
+ // Is this the symbol we're looking for?
+ if (thisSymbolName == name)
+ {
+ info = symbol;
+ return true;
+ }
+ }
+
+ // Didn't file the symbol.
+ return false;
+}
+
+ELFSourceFile::ELFDataSource::~ELFDataSource()
+{
+ segment_vector_t::iterator it = m_segments.begin();
+ for (; it != m_segments.end(); ++it)
+ {
+ delete *it;
+ }
+}
+
+//! Not all sections will actually result in a new segment being created. Only
+//! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
+//! a new segment. Also, only sections whose size is non-zero will actually
+//! create a segment.
+//!
+//! In addition to this, ELF files that have been marked as being created by
+//! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
+//! are looked up in the .secinfo section to determine if they really
+//! should be filled. If not in the .secinfo table, no segment will be
+//! created for the section.
+void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
+{
+ // get section info
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(sectionIndex);
+ if (section.sh_size == 0)
+ {
+ // empty section, so ignore it
+ return;
+ }
+
+ // create the right segment subclass based on the section type
+ DataSource::Segment * segment = NULL;
+ if (section.sh_type == SHT_PROGBITS)
+ {
+ segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
+ }
+ else if (section.sh_type == SHT_NOBITS)
+ {
+ // Always add NOBITS sections by default.
+ bool addNobits = true;
+
+ // For GHS ELF files, we use the secinfoClear option to figure out what to do.
+ // If set to ignore, treat like a normal ELF file and always add. If set to
+ // ROM, then only clear if the section is listed in .secinfo. Otherwise if set
+ // to C startup, then let the C startup do all clearing.
+ if (m_elf->ELFVariant() == eGHSVariant)
+ {
+ GHSSecInfo secinfo(m_elf);
+
+ // If there isn't a .secinfo section present then use the normal ELF rules
+ // and always add NOBITS sections.
+ if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
+ {
+ switch (m_secinfoOption)
+ {
+ case kSecinfoROMClear:
+ addNobits = secinfo.isSectionFilled(section);
+ break;
+
+ case kSecinfoCStartupClear:
+ addNobits = false;
+ break;
+ }
+ }
+ }
+
+ if (addNobits)
+ {
+ segment = new NoBitsSegment(*this, m_elf, sectionIndex);
+ }
+ else
+ {
+ std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
+ Log::log(Logger::DEBUG2, "..section %s is not filled\n", name.c_str());
+ }
+ }
+
+ // add segment if one was created
+ if (segment)
+ {
+ m_segments.push_back(segment);
+ }
+}
+
+ELFSourceFile::ELFDataSource::ProgBitsSegment::ProgBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
+: DataSource::Segment(source), m_elf(elf), m_sectionIndex(index)
+{
+}
+
+unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
+{
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
+ uint8_t * data = m_elf->getSectionDataAtIndex(m_sectionIndex);
+
+ assert(offset < section.sh_size);
+
+ unsigned copyBytes = std::min<unsigned>(section.sh_size - offset, maxBytes);
+ if (copyBytes)
+ {
+ memcpy(buffer, &data[offset], copyBytes);
+ }
+
+ return copyBytes;
+}
+
+unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getLength()
+{
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
+ return section.sh_size;
+}
+
+uint32_t ELFSourceFile::ELFDataSource::ProgBitsSegment::getBaseAddress()
+{
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
+ return section.sh_addr;
+}
+
+ELFSourceFile::ELFDataSource::NoBitsSegment::NoBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
+: DataSource::PatternSegment(source), m_elf(elf), m_sectionIndex(index)
+{
+}
+
+unsigned ELFSourceFile::ELFDataSource::NoBitsSegment::getLength()
+{
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
+ return section.sh_size;
+}
+
+uint32_t ELFSourceFile::ELFDataSource::NoBitsSegment::getBaseAddress()
+{
+ const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
+ return section.sh_addr;
+}
+
diff --git a/common/ELFSourceFile.h b/common/ELFSourceFile.h
new file mode 100644
index 0000000..c07aa56
--- /dev/null
+++ b/common/ELFSourceFile.h
@@ -0,0 +1,224 @@
+/*
+ * File: ELFSourceFile.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ELFSourceFile_h_)
+#define _ELFSourceFile_h_
+
+#include "SourceFile.h"
+#include "StELFFile.h"
+#include "smart_ptr.h"
+#include "DataSource.h"
+#include "DataTarget.h"
+#include "ELF.h"
+
+namespace elftosb
+{
+
+//! Set of supported compiler toolsets.
+enum elf_toolset_t
+{
+ kUnknownToolset, //!< Unknown.
+ kGHSToolset, //!< Green Hills Software MULTI
+ kGCCToolset, //!< GNU GCC
+ kADSToolset //!< ARM UK RealView
+};
+
+//! Options for handling the .secinfo section in GHS-produced ELF files.
+enum secinfo_clear_t
+{
+ // Default value for the .secinfo action.
+ kSecinfoDefault,
+
+ //! Ignore the .secinfo section if present. The standard ELF loading
+ //! rules are followed.
+ kSecinfoIgnore,
+
+ //! The boot ROM clears only those SHT_NOBITS sections present in .secinfo.
+ kSecinfoROMClear,
+
+ //! The C startup is responsible for clearing sections. No fill commands
+ //! are generated for any SHT_NOBITS sections.
+ kSecinfoCStartupClear
+};
+
+/*!
+ * \brief Executable and Loading Format (ELF) source file.
+ */
+class ELFSourceFile : public SourceFile
+{
+public:
+ //! \brief Default constructor.
+ ELFSourceFile(const std::string & path);
+
+ //! \brief Destructor.
+ virtual ~ELFSourceFile();
+
+ //! \brief Identifies whether the stream contains an ELF file.
+ static bool isELFFile(std::istream & stream);
+
+ //! \name Opening and closing
+ //@{
+ //! \brief Opens the file.
+ virtual void open();
+
+ //! \brief Closes the file.
+ virtual void close();
+ //@}
+
+ //! \name Format capabilities
+ //@{
+ virtual bool supportsNamedSections() const { return true; }
+ virtual bool supportsNamedSymbols() const { return true; }
+ //@}
+
+ //! \name Data source
+ //@{
+ //! \brief Creates a data source from the entire file.
+ virtual DataSource * createDataSource();
+
+ //! \brief Creates a data source from one or more sections of the file.
+ virtual DataSource * createDataSource(StringMatcher & matcher);
+ //@}
+
+ //! \name Entry point
+ //@{
+ //! \brief Returns true if an entry point was set in the file.
+ virtual bool hasEntryPoint();
+
+ //! \brief Returns the entry point address.
+ virtual uint32_t getEntryPointAddress();
+ //@}
+
+ //! \name Data target
+ //@{
+ virtual DataTarget * createDataTargetForSection(const std::string & section);
+ virtual DataTarget * createDataTargetForSymbol(const std::string & symbol);
+ //@}
+
+ //! \name Symbols
+ //@{
+ //! \brief Returns whether a symbol exists in the source file.
+ virtual bool hasSymbol(const std::string & name);
+
+ //! \brief Returns the value of a symbol.
+ virtual uint32_t getSymbolValue(const std::string & name);
+
+ //! \brief Returns the size of a symbol.
+ virtual unsigned getSymbolSize(const std::string & name);
+ //@}
+
+ //! \name Direct ELF format access
+ //@{
+ //! \brief Returns the underlying StELFFile object.
+ StELFFile * getELFFile() { return m_file; }
+
+ //! \brief Gets information about a symbol in the ELF file.
+ bool lookupSymbol(const std::string & name, Elf32_Sym & info);
+ //@}
+
+protected:
+ smart_ptr<StELFFile> m_file; //!< Parser for the ELF file.
+ elf_toolset_t m_toolset; //!< Toolset that produced the ELF file.
+ secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
+
+protected:
+ //! \brief Parses the toolset option value.
+ elf_toolset_t readToolsetOption();
+
+ //! \brief Reads the secinfoClear option.
+ secinfo_clear_t readSecinfoClearOption();
+
+protected:
+ /*!
+ * \brief A data source with ELF file sections as the contents.
+ *
+ * Each segment of this data source corresponds directly with a named section
+ * of the ELF file it represents. When the data source is created, it contains
+ * no segments. Segments are created with the addSection() method, which takes
+ * the index of an ELF section and creates a corresponding segment.
+ *
+ * Two segment subclasses are used with this data source. The first, ProgBitsSegment,
+ * is used to represent sections whose type is #SHT_PROGBITS. These sections have
+ * binary data stored in the ELF file. The second segment type is NoBitsSegment.
+ * It is used to represent sections whose type is #SHT_NOBITS. These sections have
+ * no data, but simply allocate a region of memory to be filled with zeroes.
+ * As such, the NoBitsSegment class is a subclass of DataSource::PatternSegment.
+ */
+ class ELFDataSource : public DataSource
+ {
+ public:
+ /*!
+ * \brief Represents one named #SHT_PROGBITS section within the ELF file.
+ */
+ class ProgBitsSegment : public DataSource::Segment
+ {
+ public:
+ ProgBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index);
+
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
+ virtual unsigned getLength();
+
+ virtual bool hasNaturalLocation() { return true; }
+ virtual uint32_t getBaseAddress();
+
+ protected:
+ StELFFile * m_elf; //!< The format parser instance for this ELF file.
+ unsigned m_sectionIndex; //!< The index of the section this segment represents.
+ };
+
+ /*!
+ * \brief Represents one named #SHT_NOBITS section within the ELF file.
+ *
+ * This segment class is a subclass of DataSource::PatternSegment since it
+ * represents a region of memory to be filled with zeroes.
+ */
+ class NoBitsSegment : public DataSource::PatternSegment
+ {
+ public:
+ NoBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index);
+
+ virtual unsigned getLength();
+
+ virtual bool hasNaturalLocation() { return true; }
+ virtual uint32_t getBaseAddress();
+
+ protected:
+ StELFFile * m_elf; //!< The format parser instance for this ELF file.
+ unsigned m_sectionIndex; //!< The index of the section this segment represents.
+ };
+
+ public:
+ //! \brief Default constructor.
+ ELFDataSource(StELFFile * elf) : DataSource(), m_elf(elf) {}
+
+ //! \brief Destructor.
+ virtual ~ELFDataSource();
+
+ //! Set the option to control .secinfo usage.
+ inline void setSecinfoOption(secinfo_clear_t option) { m_secinfoOption = option; }
+
+ //! \brief Adds the ELF section at position \a sectionIndex to the data source.
+ void addSection(unsigned sectionIndex);
+
+ //! \brief Returns the number of segments in the source.
+ virtual unsigned getSegmentCount() { return (unsigned)m_segments.size(); }
+
+ //! \brief Returns the segment at position \a index.
+ virtual DataSource::Segment * getSegmentAt(unsigned index) { return m_segments[index]; }
+
+ protected:
+ StELFFile * m_elf; //!< The ELF file parser.
+ secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
+
+ typedef std::vector<DataSource::Segment*> segment_vector_t; //!< A list of segment instances.
+ segment_vector_t m_segments; //!< The segments of this data source.
+ };
+
+};
+
+}; // namespace elftosb
+
+#endif // _ELFSourceFile_h_
diff --git a/common/EncoreBootImage.cpp b/common/EncoreBootImage.cpp
new file mode 100644
index 0000000..cca62b7
--- /dev/null
+++ b/common/EncoreBootImage.cpp
@@ -0,0 +1,1372 @@
+/*
+ * File: EncoreBootImage.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "EncoreBootImage.h"
+#include <stdexcept>
+#include <algorithm>
+#include <time.h>
+#include "crc.h"
+#include "SHA1.h"
+#include "Random.h"
+#include "rijndael.h"
+#include "RijndaelCBCMAC.h"
+#include "Logging.h"
+#include "EndianUtilities.h"
+
+using namespace elftosb;
+
+EncoreBootImage::EncoreBootImage()
+: m_headerFlags(0),
+ m_productVersion(),
+ m_componentVersion(),
+ m_driveTag(0)
+{
+}
+
+EncoreBootImage::~EncoreBootImage()
+{
+ // dispose of all sections
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ delete *it;
+ }
+}
+
+//! \exception std::runtime_error Raised if \a newSection has the same tag as a previously
+//! added section.
+void EncoreBootImage::addSection(Section * newSection)
+{
+ // check for another section with this tag
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ if ((*it)->getIdentifier() == newSection->getIdentifier())
+ {
+ throw std::runtime_error("new section with non-unique tag");
+ }
+ }
+
+ // no conflicting section tags, so add it
+ m_sections.push_back(newSection);
+
+ // tell the image who owns it now
+ newSection->setImage(this);
+}
+
+EncoreBootImage::section_iterator_t EncoreBootImage::findSection(Section * section)
+{
+ return std::find(beginSection(), endSection(), section);
+}
+
+void EncoreBootImage::setProductVersion(const version_t & version)
+{
+ m_productVersion = version;
+}
+
+void EncoreBootImage::setComponentVersion(const version_t & version)
+{
+ m_componentVersion = version;
+}
+
+//! \todo Optimize writing section data. Right now it only writes one block at a
+//! time, which is of course quite slow (in relative terms).
+//! \todo Refactor this into several different methods for writing each region
+//! of the image. Use a context structure to keep track of shared data between
+//! each of the methods.
+//! \todo Refactor the section and boot tag writing code to only have a single
+//! copy of the block writing and encryption loop.
+void EncoreBootImage::writeToStream(std::ostream & stream)
+{
+ // always generate the session key or DEK even if image is unencrypted
+ m_sessionKey.randomize();
+
+ // prepare to compute CBC-MACs with each KEK
+ unsigned i;
+ smart_array_ptr<RijndaelCBCMAC> macs(0);
+ if (isEncrypted())
+ {
+ macs = new RijndaelCBCMAC[m_keys.size()];
+ for (i=0; i < m_keys.size(); ++i)
+ {
+ RijndaelCBCMAC mac(m_keys[i]);
+ (macs.get())[i] = mac;
+ }
+ }
+
+ // prepare to compute SHA-1 digest over entire image
+ CSHA1 hash;
+ hash.Reset();
+
+ // count of total blocks written to the file
+ unsigned fileBlocksWritten = 0;
+
+ // we need some pieces of the header down below
+ boot_image_header_t imageHeader;
+ prepareImageHeader(imageHeader);
+
+ // write plaintext header
+ {
+ // write header
+ assert(sizeOfPaddingForCipherBlocks(sizeof(boot_image_header_t)) == 0);
+ stream.write(reinterpret_cast<char *>(&imageHeader), sizeof(imageHeader));
+ fileBlocksWritten += numberOfCipherBlocks(sizeof(imageHeader));
+
+ // update CBC-MAC over image header
+ if (isEncrypted())
+ {
+ for (i=0; i < m_keys.size(); ++i)
+ {
+ (macs.get())[i].update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
+ }
+ }
+
+ // update SHA-1
+ hash.Update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
+ }
+
+ // write plaintext section table
+ {
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ Section * section = *it;
+
+ // write header for this section
+ assert(sizeOfPaddingForCipherBlocks(sizeof(section_header_t)) == 0);
+ section_header_t sectionHeader;
+ section->fillSectionHeader(sectionHeader);
+ stream.write(reinterpret_cast<char *>(&sectionHeader), sizeof(sectionHeader));
+ fileBlocksWritten += numberOfCipherBlocks(sizeof(sectionHeader));
+
+ // update CBC-MAC over this entry
+ if (isEncrypted())
+ {
+ for (i=0; i < m_keys.size(); ++i)
+ {
+ (macs.get())[i].update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
+ }
+ }
+
+ // update SHA-1
+ hash.Update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
+ }
+ }
+
+ // finished with the CBC-MAC
+ if (isEncrypted())
+ {
+ for (i=0; i < m_keys.size(); ++i)
+ {
+ (macs.get())[i].finalize();
+ }
+ }
+
+ // write key dictionary
+ if (isEncrypted())
+ {
+ key_iterator_t it = beginKeys();
+ for (i=0; it != endKeys(); ++it, ++i)
+ {
+ // write CBC-MAC result for this key, then update SHA-1
+ RijndaelCBCMAC & mac = (macs.get())[i];
+ const RijndaelCBCMAC::block_t & macResult = mac.getMAC();
+ stream.write(reinterpret_cast<const char *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
+ hash.Update(reinterpret_cast<const uint8_t *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
+ fileBlocksWritten++;
+
+ // encrypt DEK with this key, write it out, and update image digest
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, *it, Rijndael::Key16Bytes, imageHeader.m_iv);
+ AESKey<128>::key_t wrappedSessionKey;
+ cipher.blockEncrypt(m_sessionKey, sizeof(AESKey<128>::key_t) * 8, wrappedSessionKey);
+ stream.write(reinterpret_cast<char *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
+ hash.Update(reinterpret_cast<uint8_t *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
+ fileBlocksWritten++;
+ }
+ }
+
+ // write sections and boot tags
+ {
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ section_iterator_t itCopy = it;
+ bool isLastSection = (++itCopy == endSection());
+
+ Section * section = *it;
+ cipher_block_t block;
+ unsigned blockCount = section->getBlockCount();
+ unsigned blocksWritten = 0;
+
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
+
+ // Compute the number of padding blocks needed to align the section. This first
+ // call to getPadBlockCountForOffset() passes an offset that excludes
+ // the boot tag for this section.
+ unsigned paddingBlocks = getPadBlockCountForSection(section, fileBlocksWritten);
+
+ // Insert nop commands as padding to align the start of the section, if
+ // the section has special alignment requirements.
+ NopCommand nop;
+ while (paddingBlocks--)
+ {
+ blockCount = nop.getBlockCount();
+ blocksWritten = 0;
+ while (blocksWritten < blockCount)
+ {
+ nop.getBlocks(blocksWritten, 1, &block);
+
+ if (isEncrypted())
+ {
+ // re-init after encrypt to update IV
+ cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
+ }
+
+ stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
+ hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
+
+ blocksWritten++;
+ fileBlocksWritten++;
+ }
+ }
+
+ // reinit cipher for boot tag
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
+
+ // write boot tag
+ TagCommand tag(*section);
+ tag.setLast(isLastSection);
+ if (!isLastSection)
+ {
+ // If this isn't the last section, the tag needs to include any
+ // padding for the next section in its length, otherwise the ROM
+ // won't be able to find the next section's boot tag.
+ unsigned nextSectionOffset = fileBlocksWritten + section->getBlockCount() + 1;
+ tag.setSectionLength(section->getBlockCount() + getPadBlockCountForSection(*itCopy, nextSectionOffset));
+ }
+ blockCount = tag.getBlockCount();
+ blocksWritten = 0;
+ while (blocksWritten < blockCount)
+ {
+ tag.getBlocks(blocksWritten, 1, &block);
+
+ if (isEncrypted())
+ {
+ // re-init after encrypt to update IV
+ cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
+ }
+
+ stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
+ hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
+
+ blocksWritten++;
+ fileBlocksWritten++;
+ }
+
+ // reinit cipher for section data
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
+
+ // write section data
+ blockCount = section->getBlockCount();
+ blocksWritten = 0;
+ while (blocksWritten < blockCount)
+ {
+ section->getBlocks(blocksWritten, 1, &block);
+
+ // Only encrypt the section contents if the entire boot image is encrypted
+ // and the section doesn't have the "leave unencrypted" flag set. Even if the
+ // section is unencrypted the boot tag will remain encrypted.
+ if (isEncrypted() && !section->getLeaveUnencrypted())
+ {
+ // re-init after encrypt to update IV
+ cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
+ }
+
+ stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
+ hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
+
+ blocksWritten++;
+ fileBlocksWritten++;
+ }
+ }
+ }
+
+ // write SHA-1 digest over entire image
+ {
+ // allocate enough room for digest and bytes to pad out to the next cipher block
+ const unsigned padBytes = sizeOfPaddingForCipherBlocks(sizeof(sha1_digest_t));
+ unsigned digestBlocksSize = sizeof(sha1_digest_t) + padBytes;
+ smart_array_ptr<uint8_t> digestBlocks = new uint8_t[digestBlocksSize];
+ hash.Final();
+ hash.GetHash(digestBlocks.get());
+
+ // set the pad bytes to random values
+ RandomNumberGenerator rng;
+ rng.generateBlock(&(digestBlocks.get())[sizeof(sha1_digest_t)], padBytes);
+
+ // encrypt with session key
+ if (isEncrypted())
+ {
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
+ cipher.blockEncrypt(digestBlocks.get(), digestBlocksSize * 8, digestBlocks.get());
+ }
+
+ // write to the stream
+ stream.write(reinterpret_cast<char *>(digestBlocks.get()), digestBlocksSize);
+ }
+}
+
+void EncoreBootImage::prepareImageHeader(boot_image_header_t & header)
+{
+ // get identifier for the first bootable section
+ Section * firstBootSection = findFirstBootableSection();
+ section_id_t firstBootSectionID = 0;
+ if (firstBootSection)
+ {
+ firstBootSectionID = firstBootSection->getIdentifier();
+ }
+
+ // fill in header fields
+ header.m_signature[0] = 'S';
+ header.m_signature[1] = 'T';
+ header.m_signature[2] = 'M';
+ header.m_signature[3] = 'P';
+ header.m_majorVersion = ROM_BOOT_IMAGE_MAJOR_VERSION;
+ header.m_minorVersion = ROM_BOOT_IMAGE_MINOR_VERSION;
+ header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_headerFlags);
+ header.m_imageBlocks = ENDIAN_HOST_TO_LITTLE_U32(getImageSize());
+ header.m_firstBootableSectionID = ENDIAN_HOST_TO_LITTLE_U32(firstBootSectionID);
+ header.m_keyCount = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)m_keys.size());
+ header.m_headerBlocks = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)numberOfCipherBlocks(sizeof(header)));
+ header.m_sectionCount = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)m_sections.size());
+ header.m_sectionHeaderSize = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)numberOfCipherBlocks(sizeof(section_header_t)));
+ header.m_signature2[0] = 's';
+ header.m_signature2[1] = 'g';
+ header.m_signature2[2] = 't';
+ header.m_signature2[3] = 'l';
+ header.m_timestamp = ENDIAN_HOST_TO_LITTLE_U64(getTimestamp());
+ header.m_driveTag = m_driveTag;
+
+ // Prepare version fields by converting them to the correct byte order.
+ header.m_productVersion = m_productVersion;
+ header.m_componentVersion = m_componentVersion;
+ header.m_productVersion.fixByteOrder();
+ header.m_componentVersion.fixByteOrder();
+
+ // the fields are dependant on others
+ header.m_keyDictionaryBlock = ENDIAN_HOST_TO_LITTLE_U16(header.m_headerBlocks + header.m_sectionCount * header.m_sectionHeaderSize);
+ header.m_firstBootTagBlock = ENDIAN_HOST_TO_LITTLE_U32(header.m_keyDictionaryBlock + header.m_keyCount * 2);
+
+ // generate random pad bytes
+ RandomNumberGenerator rng;
+ rng.generateBlock(header.m_padding0, sizeof(header.m_padding0));
+ rng.generateBlock(header.m_padding1, sizeof(header.m_padding1));
+
+ // compute SHA-1 digest over the image header
+ uint8_t * message = reinterpret_cast<uint8_t *>(&header.m_signature);
+ uint32_t length = static_cast<uint32_t>(sizeof(header) - sizeof(header.m_digest)); // include padding
+
+ CSHA1 hash;
+ hash.Reset();
+ hash.Update(message, length);
+ hash.Final();
+ hash.GetHash(header.m_digest);
+}
+
+//! Returns the number of microseconds since 00:00 1-1-2000. In actuality, the timestamp
+//! is only accurate to seconds, and is simply extended out to microseconds.
+//!
+//! \todo Use the operating system's low-level functions to get a true microsecond
+//! timestamp, instead of faking it like we do now.
+//! \bug The timestamp might be off an hour.
+uint64_t EncoreBootImage::getTimestamp()
+{
+#if WIN32
+ struct tm epoch = { 0, 0, 0, 1, 0, 100, 0, 0 }; // 00:00 1-1-2000
+#else
+ struct tm epoch = { 0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL }; // 00:00 1-1-2000
+#endif
+ time_t epochTime = mktime(&epoch);
+ time_t now = time(NULL);
+ now -= epochTime;
+ uint64_t microNow = uint64_t(now) * 1000000; // convert to microseconds
+ return microNow;
+}
+
+//! Scans the section list looking for the first section which has
+//! the #ROM_SECTION_BOOTABLE flag set on it.
+EncoreBootImage::Section * EncoreBootImage::findFirstBootableSection()
+{
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ if ((*it)->getFlags() & ROM_SECTION_BOOTABLE)
+ {
+ return *it;
+ }
+ }
+
+ // no bootable sections were found
+ return NULL;
+}
+
+//! The boot tag for \a section is taken into account, thus making the
+//! result offset point to the first block of the actual section data.
+//!
+//! \note The offset will only be valid if all encryption keys and all
+//! sections have already been added to the image.
+uint32_t EncoreBootImage::getSectionOffset(Section * section)
+{
+ // start with boot image headers
+ uint32_t offset = numberOfCipherBlocks(sizeof(boot_image_header_t)); // header
+ offset += numberOfCipherBlocks(sizeof(section_header_t)) * sectionCount(); // section table
+ offset += 2 * keyCount(); // key dictiontary
+
+ // add up sections before this one
+ section_iterator_t it = beginSection();
+ for (; it != endSection() && *it != section; ++it)
+ {
+ Section * thisSection = *it;
+
+ // insert padding for section alignment
+ offset += getPadBlockCountForSection(thisSection, offset);
+
+ // add one for boot tag associated with this section
+ offset++;
+
+ // now add the section's contents
+ offset += thisSection->getBlockCount();
+ }
+
+ // and add padding for this section
+ offset += getPadBlockCountForSection(section, offset);
+
+ // skip over this section's boot tag
+ offset++;
+
+ return offset;
+}
+
+//! Computes the number of blocks of padding required to align \a section while
+//! taking into account the boot tag that gets inserted before the section contents.
+unsigned EncoreBootImage::getPadBlockCountForSection(Section * section, unsigned offset)
+{
+ // Compute the number of padding blocks needed to align the section. This first
+ // call to getPadBlockCountForOffset() passes an offset that excludes
+ // the boot tag for this section.
+ unsigned paddingBlocks = section->getPadBlockCountForOffset(offset);
+
+ // If the pad count comes back as 0 then we need to try again with an offset that
+ // includes the boot tag. This is all because we're aligning the section contents
+ // start and not the section's boot tag.
+ if (paddingBlocks == 0)
+ {
+ paddingBlocks = section->getPadBlockCountForOffset(offset + 1);
+ }
+ // Otherwise if we get a nonzero pad amount then we need to subtract the block
+ // for the section's boot tag from the pad count.
+ else
+ {
+ paddingBlocks--;
+ }
+
+ return paddingBlocks;
+}
+
+uint32_t EncoreBootImage::getImageSize()
+{
+ // determine to total size of the image
+ const uint32_t headerBlocks = numberOfCipherBlocks(sizeof(boot_image_header_t));
+ const uint32_t sectionHeaderSize = numberOfCipherBlocks(sizeof(section_header_t));
+ uint32_t imageBlocks = headerBlocks;
+ imageBlocks += sectionHeaderSize * m_sections.size(); // section table
+ imageBlocks += 2 * m_keys.size(); // key dict
+
+ // add in each section's size
+ section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ // add in this section's size, padding to align it, and its boot tag
+ imageBlocks += getPadBlockCountForSection(*it, imageBlocks);
+ imageBlocks += (*it)->getBlockCount();
+ imageBlocks++;
+ }
+
+ // image MAC
+ imageBlocks += 2;
+
+ return imageBlocks;
+}
+
+void EncoreBootImage::debugPrint() const
+{
+ const_section_iterator_t it = beginSection();
+ for (; it != endSection(); ++it)
+ {
+ const Section * section = *it;
+ section->debugPrint();
+ }
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \return A new boot command instance.
+//! \retval NULL The boot command pointed to by \a blocks was not recognized as a known
+//! command type.
+//!
+//! \exception std::runtime_error This exception indicates that a command was recognized
+//! but contained invalid data. Compare this to a NULL result which indicates that
+//! no command was recognized at all.
+EncoreBootImage::BootCommand * EncoreBootImage::BootCommand::createFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ BootCommand * command = NULL;
+
+ switch (header->m_tag)
+ {
+ case ROM_NOP_CMD:
+ command = new NopCommand();
+ break;
+ case ROM_TAG_CMD:
+ command = new TagCommand();
+ break;
+ case ROM_LOAD_CMD:
+ command = new LoadCommand();
+ break;
+ case ROM_FILL_CMD:
+ command = new FillCommand();
+ break;
+ case ROM_MODE_CMD:
+ command = new ModeCommand();
+ break;
+ case ROM_JUMP_CMD:
+ command = new JumpCommand();
+ break;
+ case ROM_CALL_CMD:
+ command = new CallCommand();
+ break;
+ }
+
+ if (command)
+ {
+ command->initFromData(blocks, count, consumed);
+ }
+ return command;
+}
+
+//! The checksum algorithm is totally straightforward, except that the
+//! initial checksum byte value is set to 0x5a instead of 0.
+uint8_t EncoreBootImage::BootCommand::calculateChecksum(const boot_command_t & header)
+{
+ const uint8_t * bytes = reinterpret_cast<const uint8_t *>(&header);
+ uint8_t checksum = 0x5a;
+ int i;
+
+ // start at one to skip checksum field
+ for (i = 1; i < sizeof(header); ++i)
+ {
+ checksum += bytes[i];
+ }
+
+ return checksum;
+}
+
+//! The default implementation returns 0, indicating that no blocks are
+//! available.
+unsigned EncoreBootImage::BootCommand::getBlockCount() const
+{
+ return 1 + getDataBlockCount();
+}
+
+//! Up to \a maxCount cipher blocks are copied into the buffer pointed to by
+//! the \a data argument. The index of the first block to copy is
+//! held in the \a offset argument.
+//!
+//! \param offset Starting block number to copy. Zero means the first available block.
+//! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
+//! \param data Buffer for outgoing cipher blocks. Must have enough room to hold
+//! \a maxCount blocks.
+//!
+//! \return The number of cipher blocks copied into \a data.
+//! \retval 0 No more blocks are available and nothing was written to \a data.
+//!
+//! \exception std::out_of_range If \a offset is invalid.
+unsigned EncoreBootImage::BootCommand::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
+{
+ assert(data);
+ assert(maxCount >= 1);
+
+ // check for valid offset
+ if (offset >= getBlockCount())
+ {
+ throw std::out_of_range("invalid offset");
+ }
+
+ // handle the command header block separately
+ if (offset == 0)
+ {
+ assert(sizeof(boot_command_t) == sizeof(cipher_block_t));
+
+ boot_command_t header;
+ fillCommandHeader(header);
+ memcpy(data, &header, sizeof(header));
+
+ return 1;
+ }
+
+ // handle any data blocks
+ return getDataBlocks(offset - 1, maxCount, data);
+}
+
+//! The checksum field of \a testHeader is always computed and checked against itself.
+//! All other fields are compared to the corresponding value set in \a modelHeader
+//! if the appropriate flag is set in \a whichFields. For example, the m_address fields
+//! in \a testHeader and \a modelHeader are compared when the CMD_ADDRESS_FIELD bit
+//! is set in \a whichFields. An exception is thrown if any comparison fails.
+//!
+//! \param modelHeader The baseline header to compare against. Only those fields that
+//! have corresponding bits set in \a whichFields need to be set.
+//! \param testHeader The actual command header which is being validated.
+//! \param whichFields A bitfield used to determine which fields of the boot command
+//! header are compared. Possible values are:
+//! - CMD_TAG_FIELD
+//! - CMD_FLAGS_FIELD
+//! - CMD_ADDRESS_FIELD
+//! - CMD_COUNT_FIELD
+//! - CMD_DATA_FIELD
+//!
+//! \exception std::runtime_error Thrown if any requested validation fails.
+void EncoreBootImage::BootCommand::validateHeader(const boot_command_t * modelHeader, const boot_command_t * testHeader, unsigned whichFields)
+{
+ // compare all the fields that were requested
+ if ((whichFields & CMD_TAG_FIELD) && (testHeader->m_tag != modelHeader->m_tag))
+ {
+ throw std::runtime_error("invalid tag field");
+ }
+
+ if ((whichFields & CMD_FLAGS_FIELD) && (testHeader->m_flags != modelHeader->m_flags))
+ {
+ throw std::runtime_error("invalid flags field");
+ }
+
+ if ((whichFields & CMD_ADDRESS_FIELD) && (testHeader->m_address != modelHeader->m_address))
+ {
+ throw std::runtime_error("invalid address field");
+ }
+
+ if ((whichFields & CMD_COUNT_FIELD) && (testHeader->m_count != modelHeader->m_count))
+ {
+ throw std::runtime_error("invalid count field");
+ }
+
+ if ((whichFields & CMD_DATA_FIELD) && (testHeader->m_data != modelHeader->m_data))
+ {
+ throw std::runtime_error("invalid data field");
+ }
+
+ // calculate checksum
+ uint8_t testChecksum = calculateChecksum(*testHeader);
+ if (testChecksum != testHeader->m_checksum)
+ {
+ throw std::runtime_error("invalid checksum");
+ }
+}
+
+//! Since the NOP command has no data, this method just validates the command header.
+//! All fields except the checksum are expected to be set to 0.
+//!
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error Thrown if header fields are invalid.
+void EncoreBootImage::NopCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ const boot_command_t model = { 0, ROM_NOP_CMD, 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD | CMD_ADDRESS_FIELD | CMD_COUNT_FIELD | CMD_DATA_FIELD);
+
+ *consumed = 1;
+}
+
+//! All fields of the boot command header structure are set to 0, except
+//! for the checksum. This includes the tag field since the tag value for
+//! the #ROM_NOP_CMD is zero. And since all fields are zeroes the checksum
+//! remains the initial checksum value of 0x5a.
+void EncoreBootImage::NopCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = 0;
+ header.m_address = 0;
+ header.m_count = 0;
+ header.m_data = 0;
+ header.m_checksum = calculateChecksum(header); // do this last
+}
+
+void EncoreBootImage::NopCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, "\tNOOP\n");
+}
+
+//! The identifier, length, and flags fields are taken from \a section.
+//!
+//! \todo How does length get set correctly if the length is supposed to include
+//! this command?
+EncoreBootImage::TagCommand::TagCommand(const Section & section)
+{
+ m_sectionIdentifier = section.getIdentifier();
+ m_sectionLength = section.getBlockCount();
+ m_sectionFlags = section.getFlags();
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error Thrown if header fields are invalid.
+void EncoreBootImage::TagCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ const boot_command_t model = { 0, ROM_TAG_CMD, 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD);
+
+ // read fields from header
+ m_isLast = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_LAST_TAG) != 0;
+ m_sectionIdentifier = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
+ m_sectionLength = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
+ m_sectionFlags = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
+
+ *consumed = 1;
+}
+
+//! This method currently assumes that the next tag command will come immediately
+//! after the data for this section.
+void EncoreBootImage::TagCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_isLast ? ROM_LAST_TAG : 0);
+ header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_sectionIdentifier);
+ header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_sectionLength);
+ header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_sectionFlags);
+ header.m_checksum = calculateChecksum(header); // do this last
+}
+
+void EncoreBootImage::TagCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " BTAG | sec=0x%08x | cnt=0x%08x | flg=0x%08x\n", m_sectionIdentifier, m_sectionLength, m_sectionFlags);
+}
+
+//! All fields are set to zero.
+//!
+EncoreBootImage::LoadCommand::LoadCommand()
+: BootCommand(), m_data(), m_padCount(0), m_length(0), m_address(0), m_loadDCD(false)
+{
+ fillPadding();
+}
+
+EncoreBootImage::LoadCommand::LoadCommand(uint32_t address, const uint8_t * data, uint32_t length)
+: BootCommand(), m_data(), m_padCount(0), m_length(0), m_address(address), m_loadDCD(false)
+{
+ fillPadding();
+ setData(data, length);
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error This exception is thrown if the actual CRC of the load
+//! data does not match the CRC stored in the command header. Also thrown if the
+//! \a count parameter is less than the number of data blocks needed for the length
+//! specified in the command header or if header fields are invalid.
+void EncoreBootImage::LoadCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ // check static fields
+ const boot_command_t model = { 0, ROM_LOAD_CMD, 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD);
+
+ // read fields from header
+ m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
+ m_length = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
+ unsigned crc = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
+ unsigned dataBlockCount = numberOfCipherBlocks(m_length);
+ m_padCount = sizeOfPaddingForCipherBlocks(dataBlockCount);
+ m_loadDCD = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_LOAD_DCD) != 0;
+
+ // make sure there are enough blocks
+ if (count - 1 < dataBlockCount)
+ {
+ throw std::runtime_error("not enough cipher blocks for load data");
+ }
+
+ // copy data
+ setData(reinterpret_cast<const uint8_t *>(blocks + 1), m_length);
+
+ // copy padding
+ if (m_padCount)
+ {
+ const uint8_t * firstPadByte = reinterpret_cast<const uint8_t *> (blocks + (1 + dataBlockCount)) - m_padCount;
+ memcpy(m_padding, firstPadByte, m_padCount);
+ }
+
+ // check CRC
+ uint32_t actualCRC = calculateCRC();
+ if (actualCRC != crc)
+ {
+ throw std::runtime_error("load data failed CRC check");
+ }
+
+ *consumed = 1 + dataBlockCount;
+}
+
+//! The only thing unique in the load command header is the
+//! #elftosb::EncoreBootImage::boot_command_t::m_data. It contains a CRC-32 over the
+//! load data, plus any bytes of padding in the last data cipher block.
+void EncoreBootImage::LoadCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_loadDCD ? ROM_LOAD_DCD : 0);
+ header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
+ header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_length);
+ header.m_data = ENDIAN_HOST_TO_LITTLE_U32(calculateCRC());
+
+ // do this last
+ header.m_checksum = calculateChecksum(header);
+}
+
+//! A CRC-32 is calculated over the load data, including any pad bytes
+//! that are required in the last data cipher block. Including the
+//! pad bytes in the CRC makes it vastly easier for the ROM to calculate
+//! the CRC for validation.
+uint32_t EncoreBootImage::LoadCommand::calculateCRC() const
+{
+ uint32_t result;
+ CRC32 crc;
+ crc.update(m_data, m_length);
+ if (m_padCount)
+ {
+ // include random padding in the CRC
+ crc.update(m_padding, m_padCount);
+ }
+ crc.truncatedFinal(reinterpret_cast<uint8_t*>(&result), sizeof(result));
+
+ return result;
+}
+
+//! A local copy of the load data is made. This copy will be disposed of when this object
+//! is destroyed. This means the caller is free to deallocate \a data after this call
+//! returns. It also means the caller can pass a pointer into the middle of a buffer for
+//! \a data and not worry about ownership issues.
+void EncoreBootImage::LoadCommand::setData(const uint8_t * data, uint32_t length)
+{
+ assert(data);
+ assert(length);
+
+ uint8_t * dataCopy = new uint8_t[length];
+ memcpy(dataCopy, data, length);
+
+ m_data = dataCopy;
+ m_length = length;
+
+ m_padCount = sizeOfPaddingForCipherBlocks(m_length);
+}
+
+//! \return The number of cipher blocks required to hold the load data,
+//! rounded up as necessary.
+unsigned EncoreBootImage::LoadCommand::getDataBlockCount() const
+{
+ // round up to the next cipher block
+ return numberOfCipherBlocks(m_length);
+}
+
+//! Up to \a maxCount data blocks are copied into the buffer pointed to by
+//! the \a data argument. This is only a request for \a maxCount blocks.
+//! A return value of 0 indicates that no more blocks are available. The
+//! index of the first block to copy is held in the \a offset argument.
+//! If there are pad bytes needed to fill out the last data block, they
+//! will be filled with random data in order to add to the "whiteness" of
+//! the data on both sides of encryption.
+//!
+//! \param offset Starting block number to copy. Zero means the first available block.
+//! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
+//! \param data Buffer for outgoing data blocks. Must have enough room to hold
+//! \a maxCount blocks.
+//!
+//! \return The number of data blocks copied into \a data.
+//! \retval 0 No more blocks are available and nothing was written to \a data.
+//!
+//! \exception std::out_of_range Thrown when offset is invalid.
+//!
+//! \todo fill pad bytes with random bytes
+unsigned EncoreBootImage::LoadCommand::getDataBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
+{
+ assert(data);
+ assert(maxCount != 0);
+
+ uint32_t blockCount = getDataBlockCount();
+
+ // check offset
+ if (offset >= blockCount)
+ {
+ throw std::out_of_range("invalid offset");
+ }
+
+ // figure out how many blocks to return
+ unsigned resultBlocks = blockCount - offset;
+ if (resultBlocks > maxCount)
+ {
+ resultBlocks = maxCount;
+
+ // exclude last block if there is padding
+ if (m_padCount && (offset != blockCount - 1) && (offset + resultBlocks == blockCount))
+ {
+ resultBlocks--;
+ }
+ }
+
+ // if there are pad bytes, handle the last block specially
+ if (m_padCount && offset == blockCount - 1)
+ {
+ // copy the remainder of the load data into the first part of the result block
+ unsigned remainderLength = sizeof(cipher_block_t) - m_padCount;
+ memcpy(data, &m_data[sizeof(cipher_block_t) * offset], remainderLength);
+
+ // copy pad bytes we previously generated into the last part of the result block
+ // data is a cipher block pointer, so indexing is done on cipher block
+ // boundaries, thus we need a byte pointer to index properly
+ uint8_t * bytePtr = reinterpret_cast<uint8_t*>(data);
+ memcpy(bytePtr + remainderLength, &m_padding, m_padCount);
+ }
+ else
+ {
+ memcpy(data, &m_data[sizeof(cipher_block_t) * offset], sizeof(cipher_block_t) * resultBlocks);
+ }
+
+ return resultBlocks;
+}
+
+//! Fills #m_padding with random bytes that may be used to fill up the last data
+//! cipher block.
+void EncoreBootImage::LoadCommand::fillPadding()
+{
+ RandomNumberGenerator rng;
+ rng.generateBlock(m_padding, sizeof(m_padding));
+}
+
+void EncoreBootImage::LoadCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " LOAD | adr=0x%08x | len=0x%08x | crc=0x%08x | flg=0x%08x\n", m_address, m_length, calculateCRC(), m_loadDCD ? ROM_LOAD_DCD : 0);
+}
+
+//! The pattern, address, and count are all initialized to zero, and the pattern
+//! size is set to a word.
+EncoreBootImage::FillCommand::FillCommand()
+: BootCommand(), m_address(0), m_count(0), m_pattern(0)
+{
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error Thrown if header fields are invalid.
+void EncoreBootImage::FillCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ // check static fields
+ const boot_command_t model = { 0, ROM_FILL_CMD, 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD);
+
+ // read fields from header
+ m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
+ m_count = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
+ m_pattern = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
+
+ *consumed = 1;
+}
+
+void EncoreBootImage::FillCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = 0;
+ header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
+ header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_count);
+ header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_pattern);
+ header.m_checksum = calculateChecksum(header); // do this last
+}
+
+//! Extends the pattern across 32 bits.
+//!
+void EncoreBootImage::FillCommand::setPattern(uint8_t pattern)
+{
+ m_pattern = (pattern << 24) | (pattern << 16) | (pattern << 8) | pattern;
+}
+
+//! Extends the pattern across 32 bits.
+//!
+void EncoreBootImage::FillCommand::setPattern(uint16_t pattern)
+{
+ m_pattern = (pattern << 16) | pattern;
+}
+
+void EncoreBootImage::FillCommand::setPattern(uint32_t pattern)
+{
+ m_pattern = pattern;
+}
+
+void EncoreBootImage::FillCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " FILL | adr=0x%08x | len=0x%08x | ptn=0x%08x\n", m_address, m_count, m_pattern);
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error Thrown if header fields are invalid.
+void EncoreBootImage::ModeCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ // check static fields
+ const boot_command_t model = { 0, ROM_MODE_CMD, 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD | CMD_ADDRESS_FIELD | CMD_COUNT_FIELD);
+
+ // read fields from header
+ m_mode = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
+
+ *consumed = 1;
+}
+
+void EncoreBootImage::ModeCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = 0;
+ header.m_address = 0;
+ header.m_count = 0;
+ header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_mode);
+ header.m_checksum = calculateChecksum(header); // do this last
+}
+
+void EncoreBootImage::ModeCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " MODE | mod=0x%08x\n", m_mode);
+}
+
+//! \param blocks Pointer to the raw data blocks.
+//! \param count Number of blocks pointed to by \a blocks.
+//! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+//! by the command. Should be at least 1 for every command. This must not be NULL
+//! on entry!
+//!
+//! \exception std::runtime_error Thrown if header fields are invalid.
+void EncoreBootImage::JumpCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
+{
+ // check static fields
+ const boot_command_t model = { 0, getTag(), 0, 0, 0, 0 };
+ const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
+ validateHeader(&model, header, CMD_TAG_FIELD | CMD_COUNT_FIELD);
+
+ // read fields from header
+ m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
+ m_argument = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
+ m_isHAB = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_HAB_EXEC) != 0;
+
+ *consumed = 1;
+}
+
+void EncoreBootImage::JumpCommand::fillCommandHeader(boot_command_t & header)
+{
+ header.m_tag = getTag();
+ header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_isHAB ? ROM_HAB_EXEC : 0);
+ header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
+ header.m_count = 0;
+ header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_argument);
+ header.m_checksum = calculateChecksum(header); // do this last
+}
+
+void EncoreBootImage::JumpCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " JUMP | adr=0x%08x | arg=0x%08x | flg=0x%08x\n", m_address, m_argument, m_isHAB ? ROM_HAB_EXEC : 0);
+}
+
+void EncoreBootImage::CallCommand::debugPrint() const
+{
+ Log::log(Logger::INFO2, " CALL | adr=0x%08x | arg=0x%08x | flg=0x%08x\n", m_address, m_argument, m_isHAB ? ROM_HAB_EXEC : 0);
+}
+
+//! Only if the section has been assigned a boot image owner object will this
+//! method be able to fill in the #section_header_t::m_offset field. If no
+//! boot image has been set the offset will be set to 0.
+void EncoreBootImage::Section::fillSectionHeader(section_header_t & header)
+{
+ header.m_tag = getIdentifier();
+ header.m_offset = 0;
+ header.m_length = ENDIAN_HOST_TO_LITTLE_U32(getBlockCount());
+ header.m_flags = ENDIAN_HOST_TO_LITTLE_U32(getFlags());
+
+ // if we're attached to an image, we can compute our real offset
+ if (m_image)
+ {
+ header.m_offset = ENDIAN_HOST_TO_LITTLE_U32(m_image->getSectionOffset(this));
+ }
+}
+
+//! The alignment will never be less than 16, since that is the size of the
+//! cipher block which is the basic unit of the boot image format. If an
+//! alignment less than 16 is set it will be ignored.
+//!
+//! \param alignment Alignment in bytes for this section. Must be a power of two.
+//! Ignored if less than 16.
+void EncoreBootImage::Section::setAlignment(unsigned alignment)
+{
+ if (alignment > BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT)
+ {
+ m_alignment = alignment;
+ }
+}
+
+//! This method calculates the number of padding blocks that need to be inserted
+//! from a given offset for the section to be properly aligned. The value returned
+//! is the number of padding blocks that should be inserted starting just after
+//! \a offset to align the first cipher block of the section contents. The section's
+//! boot tag is \i not taken into account by this method, so the caller must
+//! deal with that herself.
+//!
+//! \param offset Start offset in cipher blocks (not bytes).
+//!
+//! \return A number of cipher blocks of padding to insert.
+unsigned EncoreBootImage::Section::getPadBlockCountForOffset(unsigned offset)
+{
+ // convert alignment from byte to block alignment
+ unsigned blockAlignment = m_alignment >> 4;
+
+ unsigned nextAlignmentOffset = (offset + blockAlignment - 1) / blockAlignment * blockAlignment;
+
+ return nextAlignmentOffset - offset;
+}
+
+EncoreBootImage::BootSection::~BootSection()
+{
+ deleteCommands();
+}
+
+void EncoreBootImage::BootSection::deleteCommands()
+{
+ // dispose of all sections
+ iterator_t it = begin();
+ for (; it != end(); ++it)
+ {
+ delete *it;
+ }
+}
+
+//! Always returns at least 1 for the required tag command.
+//!
+unsigned EncoreBootImage::BootSection::getBlockCount() const
+{
+ unsigned count = 0;
+
+ const_iterator_t it = begin();
+ for (; it != end(); ++it)
+ {
+ count += (*it)->getBlockCount();
+ }
+
+ return count;
+}
+
+//! Up to \a maxCount cipher blocks are copied into the buffer pointed to by
+//! the \a data argument. A return value of 0 indicates that
+//! no more blocks are available. The index of the first block to copy is
+//! held in the \a offset argument.
+//!
+//! \param offset Starting block number to copy. Zero means the first available block.
+//! \param maxCount Up to this number of blocks may be copied into \a data.
+//! \param data Buffer for outgoing cipher blocks. Must have enough room to hold
+//! \a maxCount blocks.
+//!
+//! \return The number of cipher blocks copied into \a data.
+//! \retval 0 No more blocks are available and nothing was written to \a data.
+unsigned EncoreBootImage::BootSection::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
+{
+ assert(data);
+ assert(maxCount >= 1);
+
+ unsigned currentOffset = 0;
+ unsigned readCount = maxCount;
+
+ iterator_t it = begin();
+ for (; it != end(); ++it)
+ {
+ BootCommand * command = *it;
+ unsigned commandBlocks = command->getBlockCount();
+
+ // this should never be false!
+ assert(offset >= currentOffset);
+
+ // skip forward until we hit the requested offset
+ if (offset >= currentOffset + commandBlocks)
+ {
+ currentOffset += commandBlocks;
+ continue;
+ }
+
+ // read from this command
+ unsigned commandOffset = offset - currentOffset;
+ unsigned commandRemaining = commandBlocks - commandOffset;
+ if (readCount > commandRemaining)
+ {
+ readCount = commandRemaining;
+ }
+ return command->getBlocks(commandOffset, readCount, data);
+ }
+
+ return 0;
+}
+
+//! The entire contents of the section must be in memory, pointed to by \a blocks.
+//! Any commands that had previously been added to the section are disposed of.
+//!
+//! \param blocks Pointer to the section contents.
+//! \param count Number of blocks pointed to by \a blocks.
+//!
+//! \exception std::runtime_error Thrown if a boot command cannot be created from
+//! the cipher block stream.
+void EncoreBootImage::BootSection::fillFromData(const cipher_block_t * blocks, unsigned count)
+{
+ // start with an empty slate
+ deleteCommands();
+
+ const cipher_block_t * currentBlock = blocks;
+ unsigned remaining = count;
+ while (remaining)
+ {
+ // try to create a command from the next cipher block. the number of
+ // blocks the command used up is returned in consumed.
+ unsigned consumed;
+ BootCommand * command = BootCommand::createFromData(currentBlock, remaining, &consumed);
+ if (!command)
+ {
+ throw std::runtime_error("invalid boot section data");
+ }
+
+ addCommand(command);
+
+ // update loop counters
+ remaining -= consumed;
+ currentBlock += consumed;
+ }
+}
+
+void EncoreBootImage::BootSection::debugPrint() const
+{
+ Log::log(Logger::INFO2, "Boot Section 0x%08x:\n", m_identifier);
+
+ const_iterator_t it = begin();
+ for (; it != end(); ++it)
+ {
+ const BootCommand * command = *it;
+ command->debugPrint();
+ }
+}
+
+//! A copy is made of \a data. Any previously assigned data is disposed of.
+//!
+void EncoreBootImage::DataSection::setData(const uint8_t * data, unsigned length)
+{
+ m_data = new uint8_t[length];
+ memcpy(m_data.get(), data, length);
+ m_length = length;
+}
+
+//! The section takes ownership of \a data and will dispose of it using the
+//! array delete operator upon its destruction.
+void EncoreBootImage::DataSection::setDataNoCopy(const uint8_t * data, unsigned length)
+{
+ m_data = data;
+ m_length = length;
+}
+
+unsigned EncoreBootImage::DataSection::getBlockCount() const
+{
+ return numberOfCipherBlocks(m_length);
+}
+
+unsigned EncoreBootImage::DataSection::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
+{
+ assert(data);
+ assert(maxCount != 0);
+
+ unsigned blockCount = getBlockCount();
+ unsigned padCount = sizeOfPaddingForCipherBlocks(m_length);
+
+ // check offset
+ if (offset >= blockCount)
+ {
+ throw std::out_of_range("invalid offset");
+ }
+
+ // figure out how many blocks to return
+ unsigned resultBlocks = blockCount - offset;
+ if (resultBlocks > maxCount)
+ {
+ resultBlocks = maxCount;
+
+ // exclude last block if there is padding
+ if (padCount && (offset != blockCount - 1) && (offset + resultBlocks == blockCount))
+ {
+ resultBlocks--;
+ }
+ }
+
+ // if there are pad bytes, handle the last block specially
+ if (padCount && offset == blockCount - 1)
+ {
+ // copy the remainder of the load data into the first part of the result block
+ unsigned remainderLength = sizeof(cipher_block_t) - padCount;
+ memcpy(data, &m_data[sizeOfCipherBlocks(offset)], remainderLength);
+
+ // set pad bytes to zeroes.
+ // data is a cipher block pointer, so indexing is done on cipher block
+ // boundaries, thus we need a byte pointer to index properly
+ uint8_t * bytePtr = reinterpret_cast<uint8_t*>(data);
+ memset(bytePtr + remainderLength, 0, padCount);
+ }
+ else
+ {
+ memcpy(data, &m_data[sizeOfCipherBlocks(offset)], sizeOfCipherBlocks(resultBlocks));
+ }
+
+ return resultBlocks;
+}
+
+void EncoreBootImage::DataSection::debugPrint() const
+{
+ Log::log(Logger::INFO2, "Data Section 0x%08x: (%d bytes, %d blocks)\n", m_identifier, m_length, getBlockCount());
+}
+
diff --git a/common/EncoreBootImage.h b/common/EncoreBootImage.h
new file mode 100644
index 0000000..1e78aee
--- /dev/null
+++ b/common/EncoreBootImage.h
@@ -0,0 +1,967 @@
+/*
+ * File: EncoreBootImage.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_EncoreBootImage_h_)
+#define _EncoreBootImage_h_
+
+#include <list>
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include "BootImage.h"
+#include "rijndael.h"
+#include "smart_ptr.h"
+#include "AESKey.h"
+#include "StExecutableImage.h"
+
+namespace elftosb
+{
+
+//! An AES-128 cipher block is 16 bytes.
+typedef uint8_t cipher_block_t[16];
+
+//! A SHA-1 digest is 160 bits, or 20 bytes.
+typedef uint8_t sha1_digest_t[20];
+
+//! Unique identifier type for a section.
+typedef uint32_t section_id_t;
+
+//! Utility to return the byte length of a number of cipher blocks.
+inline size_t sizeOfCipherBlocks(unsigned count) { return sizeof(cipher_block_t) * count; }
+
+//! Utility to return the number of cipher blocks required to hold an object
+//! that is \a s bytes long.
+inline size_t numberOfCipherBlocks(size_t s) { return (s + sizeof(cipher_block_t) - 1) / sizeof(cipher_block_t); }
+
+//! Utility to calculate the byte length for the cipher blocks required to hold
+//! and object that is \a bytes long.
+inline size_t sizeInCipherBlocks(size_t s) { return (unsigned)sizeOfCipherBlocks(numberOfCipherBlocks(s)); }
+
+//! Utility to return the number of bytes of padding required to fill out
+//! the last cipher block in a set of cipher blocks large enough to hold
+//! an object that is \a s bytes large. The result may be 0 if \a s is
+//! an even multiple of the cipher block size.
+inline size_t sizeOfPaddingForCipherBlocks(size_t s) { return sizeInCipherBlocks(s) - s; }
+
+/*!
+ * \brief Class to manage Encore boot image files.
+ *
+ * Initially this class will only support generation of boot images, but
+ * its design will facilitate the addition of the ability to read an
+ * image and examine its contents.
+ *
+ * A boot image is composed of the following regions:
+ * - Header
+ * - Section table
+ * - Key dictionary
+ * - Section data
+ * - Authentication
+ *
+ * Multiple sections are within a boot image are fully supported. Two general types
+ * of sections are supported with this class. Bootable sections, represented by the
+ * EncoreBootImage::BootSection class, contain a sequence of commands to be
+ * interpreted by the boot ROM. Data sections are represented by the
+ * EncoreBootImage::DataSection class and can contain any arbitrary data.
+ *
+ * An image can either be encrypted or unencrypted. The image uses a session key,
+ * or DEK (data encryption key), and the key dictionary to support any number of keys
+ * using a single image. The header and section table are always unencrypted even
+ * in encrypted images. This allows host utilities to access the individual
+ * sections without needing to have access to an encryption key.
+ *
+ * To construct a boot image, first create an instance of EncoreBootImage. Then
+ * create instances of the EncoreBootImage::BootSection or EncoreBootImage::DataSection
+ * for each of the sections in the image. For bootable sections, create and add
+ * the desired boot command objects. These are all subclasses of
+ * EncoreBootImage::BootCommand.
+ *
+ * If the boot image is to be encrypted, you need to add keys, which are instances
+ * of the AES128Key class. If no keys are added, the entire boot image will be unencrypted.
+ *
+ * When the image is fully constructed, it can be written to any std::ostream with
+ * a call to writeToStream(). The same image can be written to streams any
+ * number of times.
+ */
+class EncoreBootImage : public BootImage
+{
+public:
+ //! \brief Flag constants for the m_flags field of #elftosb::EncoreBootImage::boot_image_header_t.
+ enum
+ {
+ ROM_DISPLAY_PROGRESS = (1 << 0), //!< Print progress reports.
+ ROM_VERBOSE_PROGRESS = (1 << 1) //!< Progress reports are verbose.
+ };
+
+ enum {
+ ROM_IMAGE_HEADER_SIGNATURE = 'STMP', //!< Signature in #elftosb::EncoreBootImage::boot_image_header_t::m_signature.
+ ROM_IMAGE_HEADER_SIGNATURE2 = 'sgtl', //!< Value for #elftosb::EncoreBootImage::boot_image_header_t::m_signature2;
+ ROM_BOOT_IMAGE_MAJOR_VERSION = 1, //!< Current boot image major version.
+ ROM_BOOT_IMAGE_MINOR_VERSION = 1 //!< Current boot image minor version.
+ };
+
+ enum {
+ //! Minimum alignment for a section is 16 bytes.
+ BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT = sizeof(cipher_block_t)
+ };
+
+// All of these structures are packed to byte alignment in order to match
+// the structure on disk.
+#pragma pack(1)
+
+ //! \brief Header for the entire boot image.
+ //!
+ //! Fields of this header are arranged so that those used by the bootloader ROM all come
+ //! first. They are also set up so that all fields are not split across cipher block
+ //! boundaries. The fields not used by the bootloader are not subject to this
+ //! restraint.
+ //!
+ //! Image header size is always a round number of cipher blocks. The same also applies to
+ //! the boot image itself. The padding, held in #elftosb::EncoreBootImage::boot_image_header_t::m_padding0
+ //! and #elftosb::EncoreBootImage::boot_image_header_t::m_padding1 is filled with random bytes.
+ //!
+ //! The DEK dictionary, section table, and each section data region must all start on
+ //! cipher block boundaries.
+ //!
+ //! This header is not encrypted in the image file.
+ //!
+ //! The m_digest field contains a SHA-1 digest of the fields of the header that follow it.
+ //! It is the first field in the header so it doesn't change position or split the header
+ //! in two if fields are added to the header.
+ struct boot_image_header_t
+ {
+ union
+ {
+ sha1_digest_t m_digest; //!< SHA-1 digest of image header. Also used as the crypto IV.
+ struct
+ {
+ cipher_block_t m_iv; //!< The first 16 bytes of the digest form the initialization vector.
+ uint8_t m_extra[4]; //!< The leftover top four bytes of the SHA-1 digest.
+ };
+ };
+ uint8_t m_signature[4]; //!< 'STMP', see #ROM_IMAGE_HEADER_SIGNATURE.
+ uint8_t m_majorVersion; //!< Major version for the image format, see #ROM_BOOT_IMAGE_MAJOR_VERSION.
+ uint8_t m_minorVersion; //!< Minor version of the boot image format, see #ROM_BOOT_IMAGE_MINOR_VERSION.
+ uint16_t m_flags; //!< Flags or options associated with the entire image.
+ uint32_t m_imageBlocks; //!< Size of entire image in blocks.
+ uint32_t m_firstBootTagBlock; //!< Offset from start of file to the first boot tag, in blocks.
+ section_id_t m_firstBootableSectionID; //!< ID of section to start booting from.
+ uint16_t m_keyCount; //!< Number of entries in DEK dictionary.
+ uint16_t m_keyDictionaryBlock; //!< Starting block number for the key dictionary.
+ uint16_t m_headerBlocks; //!< Size of this header, including this size word, in blocks.
+ uint16_t m_sectionCount; //!< Number of section headers in this table.
+ uint16_t m_sectionHeaderSize; //!< Size in blocks of a section header.
+ uint8_t m_padding0[2]; //!< Padding to align #m_timestamp to long word.
+ uint8_t m_signature2[4]; //!< Second signature to distinguish this .sb format from the 36xx format, see #ROM_IMAGE_HEADER_SIGNATURE2.
+ uint64_t m_timestamp; //!< Timestamp when image was generated in microseconds since 1-1-2000.
+ version_t m_productVersion; //!< Product version.
+ version_t m_componentVersion; //!< Component version.
+ uint16_t m_driveTag; //!< Drive tag for the system drive which this boot image belongs to.
+ uint8_t m_padding1[6]; //!< Padding to round up to next cipher block.
+ };
+
+ //! \brief Entry in #elftosb::EncoreBootImage::dek_dictionary_t.
+ //!
+ //! The m_dek field in each entry is encrypted using the KEK with the m_iv field from
+ //! the image header as the IV.
+ struct dek_dictionary_entry_t
+ {
+ cipher_block_t m_mac; //!< CBC-MAC of the header.
+ aes128_key_t m_dek; //!< AES-128 key with which the image payload is encrypted.
+ };
+
+ //! \brief The DEK dictionary always follows the image header, in the next cipher block.
+ struct dek_dictionary_t
+ {
+ dek_dictionary_entry_t m_entries[1];
+ };
+
+ //! \brief Section flags constants for the m_flags field of #elftosb::EncoreBootImage::section_header_t.
+ enum
+ {
+ ROM_SECTION_BOOTABLE = (1 << 0), //!< The section contains bootloader commands.
+ ROM_SECTION_CLEARTEXT = (1 << 1) //!< The section is unencrypted. Applies only if the rest of the boot image is encrypted.
+ };
+
+ //! \brief Information about each section, held in the section table.
+ //! \see section_table_t
+ struct section_header_t
+ {
+ uint32_t m_tag; //!< Unique identifier for this section. High bit must be zero.
+ uint32_t m_offset; //!< Offset to section data from start of image in blocks.
+ uint32_t m_length; //!< Size of section data in blocks.
+ uint32_t m_flags; //!< Section flags.
+ };
+
+ //! \brief An index of all sections within the boot image.
+ //!
+ //! The section table will be padded so that its length is divisible by 16 (if necessary).
+ //! Actually, each entry is padded to be a round number of cipher blocks, which
+ //! automatically makes this true for the entire table.
+ //!
+ //! Sections are ordered as they appear in this table, but are identified by the
+ //! #elftosb::EncoreBootImage::section_header_t::m_tag.
+ //!
+ //! The data for each section in encrypted separately with the DEK in CBC mode using
+ //! m_iv for the IV. This allows the ROM to jump to any given section without needing
+ //! to read the previous cipher block. In addition, the data for each section is
+ //! prefixed with a "boot tag", which describes the section which follows it. Boot
+ //! tags are the same format as a boot command, and are described by the
+ //! EncoreBootImage::TagCommand class.
+ //!
+ //! The section table starts immediately after the image header, coming before the
+ //! key dictionary (if present). The section table is not encrypted.
+ struct section_table_t
+ {
+ section_header_t m_sections[1]; //!< The table entries.
+ };
+
+ //! \brief Structure for a Piano bootloader command.
+ //!
+ //! Each command is composed of a fixed length header of 16 bytes. This happens to be
+ //! the size of a cipher block. Most commands will only require the header.
+ //!
+ //! But some commands, i.e. the "load data" command, may require additional arbitrary
+ //! amounts of data. This data is packed into the N cipher blocks that immediately
+ //! follow the command header. If the length of the data is not divisible by 16, then
+ //! random (not zero!) pad bytes will be added.
+ struct boot_command_t
+ {
+ uint8_t m_checksum; //!< Simple checksum over other command fields.
+ uint8_t m_tag; //!< Tag telling which command this is.
+ uint16_t m_flags; //!< Flags for this command.
+ uint32_t m_address; //!< Target address.
+ uint32_t m_count; //!< Number of bytes on which to operate.
+ uint32_t m_data; //!< Additional data used by certain commands.
+ };
+
+#pragma pack()
+
+ //! \brief Bootloader command tag constants.
+ enum
+ {
+ ROM_NOP_CMD = 0x00, //!< A no-op command.
+ ROM_TAG_CMD = 0x01, //!< Section tag command.
+ ROM_LOAD_CMD = 0x02, //!< Load data command.
+ ROM_FILL_CMD = 0x03, //!< Pattern fill command.
+ ROM_JUMP_CMD = 0x04, //!< Jump to address command.
+ ROM_CALL_CMD = 0x05, //!< Call function command.
+ ROM_MODE_CMD = 0x06 //!< Change boot mode command.
+ };
+
+ //! \brief Flag field constants for #ROM_TAG_CMD.
+ enum
+ {
+ ROM_LAST_TAG = (1 << 0) //!< This tag command is the last one in the image.
+ };
+
+ //! \brief Flag field constants for #ROM_LOAD_CMD.
+ enum
+ {
+ ROM_LOAD_DCD = (1 << 0) //!< Execute the DCD after loading completes.
+ };
+
+ //! \brief Flag field constants for #ROM_FILL_CMD.
+ enum
+ {
+ ROM_FILL_BYTE = 0, //!< Fill with byte sized pattern.
+ ROM_FILL_HALF_WORD = 1, //!< Fill with half-word sized pattern.
+ ROM_FILL_WORD = 2 //!< Fill with word sized pattern.
+ };
+
+ //! brief Flag field constants for #ROM_JUMP_CMD and #ROM_CALL_CMD.
+ enum
+ {
+ ROM_HAB_EXEC = (1 << 0) //!< Changes jump or call command to a HAB jump or call.
+ };
+
+public:
+ // Forward declaration.
+ class Section;
+
+ /*!
+ * \brief Base class for objects that produce cipher blocks.
+ */
+ class CipherBlockGenerator
+ {
+ public:
+
+ //! \name Cipher blocks
+ //@{
+ //! \brief Returns the total number of cipher blocks.
+ //!
+ //! The default implementation returns 0, indicating that no blocks are
+ //! available.
+ virtual unsigned getBlockCount() const { return 0; }
+
+ //! \brief Returns the contents of up to \a maxCount cipher blocks.
+ //!
+ //! Up to \a maxCount cipher blocks are copied into the buffer pointed to by
+ //! the \a data argument. This is only a request for \a maxCount blocks,
+ //! the subclass implementation of this method is free to return any number
+ //! of blocks from 0 up to \a maxCount. A return value of 0 indicates that
+ //! no more blocks are available. The index of the first block to copy is
+ //! held in the \a offset argument.
+ //!
+ //! \param offset Starting block number to copy. Zero means the first available block.
+ //! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
+ //! \param data Buffer for outgoing cipher blocks. Must have enough room to hold
+ //! \a maxCount blocks.
+ //!
+ //! \return The number of cipher blocks copied into \a data.
+ //! \retval 0 No more blocks are available and nothing was written to \a data.
+ virtual unsigned getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data) { return 0; }
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const {}
+ };
+
+ /*!
+ * \brief Abstract base class for all bootloader commands.
+ */
+ class BootCommand : public CipherBlockGenerator
+ {
+ public:
+ //! \brief Creates the correct subclass of BootCommand for the given raw data.
+ static BootCommand * createFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ public:
+ //! \brief Default constructor.
+ BootCommand() : CipherBlockGenerator() {}
+
+ //! \brief Destructor.
+ virtual ~BootCommand() {}
+
+ //! \brief Read the command contents from raw data.
+ //!
+ //! The subclass implementations should validate the contents of the command, including
+ //! the fields of the command header in the first block. It should be assumed that
+ //! only the tag field was examined to determine which subclass of BootCommand
+ //! should be created.
+ //!
+ //! \param blocks Pointer to the raw data blocks.
+ //! \param count Number of blocks pointed to by \a blocks.
+ //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
+ //! by the command. Should be at least 1 for every command. This must not be NULL
+ //! on entry!
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)=0;
+
+ //! \name Header
+ //@{
+ //! \brief Pure virtual method to return the tag value for this command.
+ virtual uint8_t getTag() const = 0;
+
+ //! \brief Pure virtual method to construct the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header) = 0;
+
+ //! \brief Calculates the checksum for the given command header.
+ virtual uint8_t calculateChecksum(const boot_command_t & header);
+ //@}
+
+ //! \name Cipher blocks
+ //@{
+ //! \brief Returns the total number of cipher blocks.
+ virtual unsigned getBlockCount() const;
+
+ //! \brief Returns the contents of up to \a maxCount cipher blocks.
+ virtual unsigned getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data);
+ //@}
+
+ //! \name Data blocks
+ //@{
+ //! \brief Returns the number of data cipher blocks that follow this command.
+ //!
+ //! The default implementation returns 0, indicating that no data blocks are
+ //! available.
+ virtual unsigned getDataBlockCount() const { return 0; }
+
+ //! \brief Returns the contents of up to \a maxCount data blocks.
+ //!
+ //! Up to \a maxCount data blocks are copied into the buffer pointed to by
+ //! the \a data argument. This is only a request for \a maxCount blocks,
+ //! the subclass implementation of this method is free to return any number
+ //! of blocks from 0 up to \a maxCount. A return value of 0 indicates that
+ //! no more blocks are available. The index of the first block to copy is
+ //! held in the \a offset argument.
+ //!
+ //! \param offset Starting block number to copy. Zero means the first available block.
+ //! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
+ //! \param data Buffer for outgoing data blocks. Must have enough room to hold
+ //! \a maxCount blocks.
+ //!
+ //! \return The number of data blocks copied into \a data.
+ //! \retval 0 No more blocks are available and nothing was written to \a data.
+ virtual unsigned getDataBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data) { return 0; }
+ //@}
+
+ protected:
+ //! The flag bit values for the \a whichFields parameter of validateHeader().
+ enum
+ {
+ CMD_TAG_FIELD = 1,
+ CMD_FLAGS_FIELD = 2,
+ CMD_ADDRESS_FIELD = 4,
+ CMD_COUNT_FIELD = 8,
+ CMD_DATA_FIELD = 16
+ };
+
+ //! \brief
+ void validateHeader(const boot_command_t * modelHeader, const boot_command_t * testHeader, unsigned whichFields);
+ };
+
+ /*!
+ * \brief No operation bootloader command.
+ */
+ class NopCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ NopCommand() : BootCommand() {}
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_NOP_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+ };
+
+ /*!
+ * \brief Section tag bootloader command.
+ */
+ class TagCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ TagCommand() : BootCommand() {}
+
+ //! \brief Constructor taking a section object.
+ TagCommand(const Section & section);
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_TAG_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+ //@}
+
+ //! \name Field accessors
+ //@{
+ inline void setSectionIdentifier(uint32_t identifier) { m_sectionIdentifier = identifier; }
+ inline void setSectionLength(uint32_t length) { m_sectionLength = length; }
+ inline void setSectionFlags(uint32_t flags) { m_sectionFlags = flags; }
+ inline void setLast(bool isLast) { m_isLast = isLast; }
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ uint32_t m_sectionIdentifier; //!< Unique identifier for the section containing this command.
+ uint32_t m_sectionLength; //!< Number of cipher blocks this section occupies.
+ uint32_t m_sectionFlags; //!< Flags pertaining to this section.
+ bool m_isLast; //!< Is this the last tag command?
+ };
+
+ /*!
+ * \brief Load data bootloader command.
+ */
+ class LoadCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ LoadCommand();
+
+ //! \brief Constructor.
+ LoadCommand(uint32_t address, const uint8_t * data, uint32_t length);
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_LOAD_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+
+ //! \brief Sets the load-dcd flag.
+ inline void setDCD(bool isDCD) { m_loadDCD = isDCD; }
+ //@}
+
+ //! \name Address
+ //@{
+ inline void setLoadAddress(uint32_t address) { m_address = address; }
+ inline uint32_t getLoadAddress() const { return m_address; }
+ //@}
+
+ //! \name Load data
+ //@{
+ //! \brief Set the data for the command to load.
+ void setData(const uint8_t * data, uint32_t length);
+
+ inline uint8_t * getData() { return m_data; }
+ inline const uint8_t * getData() const { return m_data; }
+ inline uint32_t getLength() const { return m_length; }
+ //@}
+
+ //! \name Data blocks
+ //@{
+ //! \brief Returns the number of data cipher blocks that follow this command.
+ virtual unsigned getDataBlockCount() const;
+
+ //! \brief Returns the contents of up to \a maxCount data blocks.
+ virtual unsigned getDataBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data);
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ smart_array_ptr<uint8_t> m_data; //!< Pointer to data to load.
+ uint8_t m_padding[15]; //!< Up to 15 pad bytes may be required.
+ unsigned m_padCount; //!< Number of pad bytes.
+ uint32_t m_length; //!< Number of bytes to load.
+ uint32_t m_address; //!< Address to which data will be loaded.
+ bool m_loadDCD; //!< Whether to execute the DCD after loading.
+
+ void fillPadding();
+ uint32_t calculateCRC() const;
+ };
+
+ /*!
+ * \brief Pattern fill bootloader command.
+ */
+ class FillCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ FillCommand();
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_FILL_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+ //@}
+
+ //! \name Address range
+ //@{
+ inline void setAddress(uint32_t address) { m_address = address; };
+ inline uint32_t getAddress() const { return m_address; }
+
+ inline void setFillCount(uint32_t count) { m_count = count; }
+ inline uint32_t getFillCount() const { return m_count; }
+ //@}
+
+ //! \name Pattern
+ //@{
+ void setPattern(uint8_t pattern);
+ void setPattern(uint16_t pattern);
+ void setPattern(uint32_t pattern);
+
+ inline uint32_t getPattern() const { return m_pattern; }
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ uint32_t m_address; //!< Fill start address.
+ uint32_t m_count; //!< Number of bytes to fill.
+ uint32_t m_pattern; //!< Fill pattern.
+ };
+
+ /*!
+ * \brief Change boot mode bootloader command.
+ */
+ class ModeCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ ModeCommand() : BootCommand(), m_mode(0) {}
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_MODE_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+ //@}
+
+ //! \name Boot mode
+ //@{
+ inline void setBootMode(uint32_t mode) { m_mode = mode; }
+ inline uint32_t getBootMode() const { return m_mode; }
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ uint32_t m_mode; //!< New boot mode.
+ };
+
+ /*!
+ * \brief Jump to address bootloader command.
+ */
+ class JumpCommand : public BootCommand
+ {
+ public:
+ //! \brief Default constructor.
+ JumpCommand() : BootCommand(), m_address(0), m_argument(0), m_isHAB(false), m_ivtSize(0) {}
+
+ //! \brief Read the command contents from raw data.
+ virtual void initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_JUMP_CMD; }
+
+ //! \brief Constructs the header for this boot command.
+ virtual void fillCommandHeader(boot_command_t & header);
+ //@}
+
+ //! \name Accessors
+ //@{
+ inline void setAddress(uint32_t address) { m_address = address; }
+ inline uint32_t getAddress() const { return m_address; }
+
+ inline void setArgument(uint32_t argument) { m_argument = argument; }
+ inline uint32_t getArgument() const { return m_argument; }
+
+ inline void setIsHAB(bool isHAB) { m_isHAB = isHAB; }
+ inline bool isHAB() const { return m_isHAB; }
+
+ inline void setIVTSize(uint32_t ivtSize) { m_ivtSize = ivtSize; }
+ inline uint32_t getIVTSize() const { return m_ivtSize; }
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ uint32_t m_address; //!< Address of the code to execute.
+ uint32_t m_argument; //!< Sole argument to pass to code.
+ bool m_isHAB; //!< Whether this jump/call is a special HAB jump/call. When this flag is set, m_address becomes the IVT address and m_ivtSize is the IVT size.
+ uint32_t m_ivtSize; //!< Size of the IVT for a HAB jump/call.
+ };
+
+ /*!
+ * \brief Call function bootloader command.
+ */
+ class CallCommand : public JumpCommand
+ {
+ public:
+ //! \brief Default constructor.
+ CallCommand() : JumpCommand() {}
+
+ //! \brief Returns the tag value for this command.
+ virtual uint8_t getTag() const { return ROM_CALL_CMD; }
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+ };
+
+ /*!
+ * \brief Base class for a section of an Encore boot image.
+ *
+ * Provides methods to manage the unique identifier that all sections have, and
+ * to set the boot image object which owns the section. There are also virtual
+ * methods to get header flags and fill in the header used in the section
+ * table. Subclasses must implement at least fillSectionHeader().
+ */
+ class Section : public CipherBlockGenerator
+ {
+ public:
+ //! \brief Default constructor.
+ Section() : CipherBlockGenerator(), m_identifier(0), m_image(0), m_alignment(BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT), m_flags(0), m_leaveUnencrypted(false) {}
+
+ //! \brief Constructor taking the unique identifier for this section.
+ Section(uint32_t identifier) : CipherBlockGenerator(), m_identifier(identifier), m_image(0), m_alignment(BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT), m_flags(0), m_leaveUnencrypted(false) {}
+
+ //! \name Identifier
+ //@{
+ inline void setIdentifier(uint32_t identifier) { m_identifier = identifier; }
+ inline uint32_t getIdentifier() const { return m_identifier; }
+ //@}
+
+ //! \name Header
+ //@{
+ //! \brief Sets explicit flags for this section.
+ virtual void setFlags(uint32_t flags) { m_flags = flags; }
+
+ //! \brief Returns the flags for this section.
+ //!
+ //! The return value consists of the flags set with setFlags() possibly or-ed
+ //! with #ROM_SECTION_CLEARTEXT if the section has been set to be left
+ //! unencrypted.
+ virtual uint32_t getFlags() const { return m_flags | ( m_leaveUnencrypted ? ROM_SECTION_CLEARTEXT : 0); }
+
+ //! \brief Pure virtual method to construct the header for this section.
+ virtual void fillSectionHeader(section_header_t & header);
+ //@}
+
+ //! \name Owner image
+ //@{
+ //! \brief Called when the section is added to an image.
+ void setImage(EncoreBootImage * image) { m_image = image; }
+
+ //! \brief Returns a pointer to the image that this section belongs to.
+ EncoreBootImage * getImage() const { return m_image; }
+ //@}
+
+ //! \name Alignment
+ //@{
+ //! \brief Sets the required alignment in the output file for this section.
+ void setAlignment(unsigned alignment);
+
+ //! \brief Returns the current alignment, the minimum of which will be 16.
+ unsigned getAlignment() const { return m_alignment; }
+
+ //! \brief Computes padding amount for alignment requirement.
+ unsigned getPadBlockCountForOffset(unsigned offset);
+ //@}
+
+ //! \name Leave unencrypted flag
+ //@{
+ //! \brief Sets whether the section will be left unencrypted.
+ void setLeaveUnencrypted(unsigned flag) { m_leaveUnencrypted = flag; }
+
+ //! \brief Returns true if the section will remain unencrypted.
+ bool getLeaveUnencrypted() const { return m_leaveUnencrypted; }
+ //@}
+
+ protected:
+ uint32_t m_identifier; //!< Unique identifier for this section.
+ EncoreBootImage * m_image; //!< The image to which this section belongs.
+ unsigned m_alignment; //!< Alignment requirement for the start of this section.
+ uint32_t m_flags; //!< Section flags set by the user.
+ bool m_leaveUnencrypted; //!< Set to true to prevent this section from being encrypted.
+ };
+
+ /*!
+ * \brief A bootable section of an Encore boot image.
+ */
+ class BootSection : public Section
+ {
+ public:
+ typedef std::list<BootCommand*> command_list_t;
+ typedef command_list_t::iterator iterator_t;
+ typedef command_list_t::const_iterator const_iterator_t;
+
+ public:
+ //! \brief Default constructor.
+ BootSection() : Section() {}
+
+ //! \brief Constructor taking the unique identifier for this section.
+ BootSection(uint32_t identifier) : Section(identifier) {}
+
+ //! \brief Destructor.
+ virtual ~BootSection();
+
+ //! \brief Load the section from raw data.
+ virtual void fillFromData(const cipher_block_t * blocks, unsigned count);
+
+ //! \name Header
+ //@{
+ //! \brief Returns the flags for this section.
+ virtual uint32_t getFlags() const { return Section::getFlags() | ROM_SECTION_BOOTABLE; }
+ //@}
+
+ //! \name Commands
+ //@{
+ //! \brief Append a new command to the section.
+ //!
+ //! The section takes ownership of the command and will delete it when
+ //! the section is destroyed.
+ void addCommand(BootCommand * command) { m_commands.push_back(command); }
+
+ //! \brief Returns the number of commands in this section, excluding the tag command.
+ unsigned getCommandCount() const { return (unsigned)m_commands.size(); }
+
+ iterator_t begin() { return m_commands.begin(); }
+ iterator_t end() { return m_commands.end(); }
+
+ const_iterator_t begin() const { return m_commands.begin(); }
+ const_iterator_t end() const { return m_commands.end(); }
+ //@}
+
+ //! \name Cipher blocks
+ //@{
+ //! \brief Returns the total number of cipher blocks occupied by this section.
+ virtual unsigned getBlockCount() const;
+
+ //! \brief Returns the contents of up to \a maxCount cipher blocks.
+ virtual unsigned getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data);
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ command_list_t m_commands; //!< Commands held in this section.
+
+ protected:
+ //! \brief Remove all commands from the section.
+ void deleteCommands();
+ };
+
+ /*!
+ * \brief A non-bootable section of an Encore boot image.
+ */
+ class DataSection : public Section
+ {
+ public:
+ //! \brief Default constructor.
+ DataSection() : Section(), m_data(), m_length(0) {}
+
+ //! \brief Constructor taking the unique identifier for this section.
+ DataSection(uint32_t identifier) : Section(identifier), m_data(), m_length(0) {}
+
+ //! \brief Set the data section's contents.
+ void setData(const uint8_t * data, unsigned length);
+
+ //! \brief Set the data section's contents without copying \a data.
+ void setDataNoCopy(const uint8_t * data, unsigned length);
+
+ //! \name Cipher blocks
+ //@{
+ //! \brief Returns the total number of cipher blocks occupied by this section.
+ virtual unsigned getBlockCount() const;
+
+ //! \brief Returns the contents of up to \a maxCount cipher blocks.
+ virtual unsigned getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data);
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+ protected:
+ smart_array_ptr<uint8_t> m_data; //!< The section's contents.
+ unsigned m_length; //!< Number of bytes of data.
+ };
+
+public:
+ typedef std::list<Section*> section_list_t; //!< List of image sections.
+ typedef section_list_t::iterator section_iterator_t; //!< Iterator over sections.
+ typedef section_list_t::const_iterator const_section_iterator_t; //!< Const iterator over sections.
+
+ typedef std::vector<AES128Key> key_list_t; //!< List of KEKs.
+ typedef key_list_t::iterator key_iterator_t; //!< Iterator over KEKs.
+ typedef key_list_t::const_iterator const_key_iterator_t; //!< Const iterator over KEKs.
+
+public:
+ //! \brief Default constructor.
+ EncoreBootImage();
+
+ //! \brief Destructor.
+ virtual ~EncoreBootImage();
+
+ //! \name Sections
+ //@{
+ void addSection(Section * newSection);
+ inline unsigned sectionCount() const { return (unsigned)m_sections.size(); }
+
+ inline section_iterator_t beginSection() { return m_sections.begin(); }
+ inline section_iterator_t endSection() { return m_sections.end(); }
+ inline const_section_iterator_t beginSection() const { return m_sections.begin(); }
+ inline const_section_iterator_t endSection() const { return m_sections.end(); }
+
+ section_iterator_t findSection(Section * section);
+
+ //! \brief Calculates the starting block number for the given section.
+ uint32_t getSectionOffset(Section * section);
+ //@}
+
+ //! \name Encryption keys
+ //@{
+ inline void addKey(const AES128Key & newKey) { m_keys.push_back(newKey); }
+ inline unsigned keyCount() const { return (unsigned)m_keys.size(); }
+
+ inline key_iterator_t beginKeys() { return m_keys.begin(); }
+ inline key_iterator_t endKeys() { return m_keys.end(); }
+ inline const_key_iterator_t beginKeys() const { return m_keys.begin(); }
+ inline const_key_iterator_t endKeys() const { return m_keys.end(); }
+
+ //! \brief The image is encrypted if there is at least one key.
+ inline bool isEncrypted() const { return m_keys.size() != 0; }
+ //@}
+
+ //! \name Versions
+ //@{
+ virtual void setProductVersion(const version_t & version);
+ virtual void setComponentVersion(const version_t & version);
+ //@}
+
+ //! \name Flags
+ //@{
+ inline void setFlags(uint16_t flags) { m_headerFlags = flags; }
+ inline uint32_t getFlags() const { return m_headerFlags; }
+ //@}
+
+ //! \brief Specify the drive tag to be set in the output file header.
+ virtual void setDriveTag(uint16_t tag) { m_driveTag = tag; }
+
+ //! \brief Calculates the total number of cipher blocks the image consumes.
+ uint32_t getImageSize();
+
+ //! \brief Returns the preferred ".sb" extension for Encore boot images.
+ virtual std::string getFileExtension() const { return ".sb"; }
+
+ //! \name Output
+ //@{
+ //! \brief Write the boot image to an output stream.
+ virtual void writeToStream(std::ostream & stream);
+ //@}
+
+ //! \brief Print out a string representation of the object.
+ virtual void debugPrint() const;
+
+protected:
+ uint16_t m_headerFlags; //!< Flags field in the boot image header.
+ version_t m_productVersion; //!< Product version.
+ version_t m_componentVersion; //!< Component version.
+ uint16_t m_driveTag; //!< System drive tag for this boot image.
+ section_list_t m_sections; //!< Sections contained in this image.
+ key_list_t m_keys; //!< List of key encryption keys. If empty, the image is unencrypted.
+ AES128Key m_sessionKey; //!< Session key we're using.
+
+ void prepareImageHeader(boot_image_header_t & header);
+ uint64_t getTimestamp();
+ Section * findFirstBootableSection();
+ unsigned getPadBlockCountForSection(Section * section, unsigned offset);
+};
+
+}; // namespace elftosb
+
+#endif // _EncoreBootImage_h_
diff --git a/common/EndianUtilities.h b/common/EndianUtilities.h
new file mode 100644
index 0000000..f915309
--- /dev/null
+++ b/common/EndianUtilities.h
@@ -0,0 +1,141 @@
+/*
+ * File: EndianUtilities.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_EndianUtilities_h_)
+#define _EndianUtilities_h_
+
+//! \name Swap macros
+//! These macros always swap the data.
+//@{
+
+//! Byte swap 16-bit value.
+#define _BYTESWAP16(value) \
+ (((((uint16_t)value)<<8) & 0xFF00) | \
+ ((((uint16_t)value)>>8) & 0x00FF))
+
+//! Byte swap 32-bit value.
+#define _BYTESWAP32(value) \
+ (((((uint32_t)value)<<24) & 0xFF000000) | \
+ ((((uint32_t)value)<< 8) & 0x00FF0000) | \
+ ((((uint32_t)value)>> 8) & 0x0000FF00) | \
+ ((((uint32_t)value)>>24) & 0x000000FF))
+
+//! Byte swap 64-bit value.
+#define _BYTESWAP64(value) \
+ (((((uint64_t)value)<<56) & 0xFF00000000000000ULL) | \
+ ((((uint64_t)value)<<40) & 0x00FF000000000000ULL) | \
+ ((((uint64_t)value)<<24) & 0x0000FF0000000000ULL) | \
+ ((((uint64_t)value)<< 8) & 0x000000FF00000000ULL) | \
+ ((((uint64_t)value)>> 8) & 0x00000000FF000000ULL) | \
+ ((((uint64_t)value)>>24) & 0x0000000000FF0000ULL) | \
+ ((((uint64_t)value)>>40) & 0x000000000000FF00ULL) | \
+ ((((uint64_t)value)>>56) & 0x00000000000000FFULL))
+
+//@}
+
+//! \name Inline swap functions
+//@{
+
+inline uint16_t _swap_u16(uint16_t value) { return _BYTESWAP16(value); }
+inline int16_t _swap_s16(int16_t value) { return (int16_t)_BYTESWAP16((uint16_t)value); }
+
+inline uint32_t _swap_u32(uint32_t value) { return _BYTESWAP32(value); }
+inline int32_t _swap_s32(int32_t value) { return (int32_t)_BYTESWAP32((uint32_t)value); }
+
+inline uint64_t _swap_u64(uint64_t value) { return _BYTESWAP64(value); }
+inline int64_t _swap_s64(int64_t value) { return (uint64_t)_BYTESWAP64((uint64_t)value); }
+
+//@}
+
+#if defined(__LITTLE_ENDIAN__)
+
+ /* little endian host */
+
+ #define ENDIAN_BIG_TO_HOST_U16(value) (_swap_u16(value))
+ #define ENDIAN_HOST_TO_BIG_U16(value) (_swap_u16(value))
+
+ #define ENDIAN_BIG_TO_HOST_S16(value) (_swap_s16(value))
+ #define ENDIAN_HOST_TO_BIG_S16(value) (_swap_s16(value))
+
+ #define ENDIAN_BIG_TO_HOST_U32(value) (_swap_u32(value))
+ #define ENDIAN_HOST_TO_BIG_U32(value) (_swap_u32(value))
+
+ #define ENDIAN_BIG_TO_HOST_S32(value) (_swap_s32(value))
+ #define ENDIAN_HOST_TO_BIG_S32(value) (_swap_s32(value))
+
+ #define ENDIAN_BIG_TO_HOST_U64(value) (_swap_u64(value))
+ #define ENDIAN_HOST_TO_BIG_U64(value) (_swap_u64(value))
+
+ #define ENDIAN_BIG_TO_HOST_S64(value) (_swap_s64(value))
+ #define ENDIAN_HOST_TO_BIG_S64(value) (_swap_s64(value))
+
+ /* no-ops */
+
+ #define ENDIAN_LITTLE_TO_HOST_U16(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_U16(value) (value)
+
+ #define ENDIAN_LITTLE_TO_HOST_S16(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_S16(value) (value)
+
+ #define ENDIAN_LITTLE_TO_HOST_U32(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_U32(value) (value)
+
+ #define ENDIAN_LITTLE_TO_HOST_S32(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_S32(value) (value)
+
+ #define ENDIAN_LITTLE_TO_HOST_U64(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_U64(value) (value)
+
+ #define ENDIAN_LITTLE_TO_HOST_S64(value) (value)
+ #define ENDIAN_HOST_TO_LITTLE_S64(value) (value)
+
+#elif defined(__BIG_ENDIAN__)
+
+ /* big endian host */
+
+ #define ENDIAN_LITTLE_TO_HOST_U16(value) (_swap_u16(value))
+ #define ENDIAN_HOST_TO_LITTLE_U16(value) (_swap_u16(value))
+
+ #define ENDIAN_LITTLE_TO_HOST_S16(value) (_swap_s16(value))
+ #define ENDIAN_HOST_TO_LITTLE_S16(value) (_swap_s16(value))
+
+ #define ENDIAN_LITTLE_TO_HOST_U32(value) (_swap_u32(value))
+ #define ENDIAN_HOST_TO_LITTLE_U32(value) (_swap_u32(value))
+
+ #define ENDIAN_LITTLE_TO_HOST_S32(value) (_swap_s32(value))
+ #define ENDIAN_HOST_TO_LITTLE_S32(value) (_swap_s32(value))
+
+ #define ENDIAN_LITTLE_TO_HOST_U64(value) (_swap_u64(value))
+ #define ENDIAN_HOST_TO_LITTLE_U64(value) (_swap_u64(value))
+
+ #define ENDIAN_LITTLE_TO_HOST_S64(value) (_swap_s64(value))
+ #define ENDIAN_HOST_TO_LITTLE_S64(value) (_swap_s64(value))
+
+ /* no-ops */
+
+ #define ENDIAN_BIG_TO_HOST_U16(value) (value)
+ #define ENDIAN_HOST_TO_BIG_U16(value) (value)
+
+ #define ENDIAN_BIG_TO_HOST_S16(value) (value)
+ #define ENDIAN_HOST_TO_BIG_S16(value) (value)
+
+ #define ENDIAN_BIG_TO_HOST_U32(value) (value)
+ #define ENDIAN_HOST_TO_BIG_U32(value) (value)
+
+ #define ENDIAN_BIG_TO_HOST_S32(value) (value)
+ #define ENDIAN_HOST_TO_BIG_S32(value) (value)
+
+ #define ENDIAN_BIG_TO_HOST_U64(value) (value)
+ #define ENDIAN_HOST_TO_BIG_U64(value) (value)
+
+ #define ENDIAN_BIG_TO_HOST_S64(value) (value)
+ #define ENDIAN_HOST_TO_BIG_S64(value) (value)
+
+#endif
+
+
+
+#endif // _EndianUtilities_h_
diff --git a/common/EvalContext.cpp b/common/EvalContext.cpp
new file mode 100644
index 0000000..876bb81
--- /dev/null
+++ b/common/EvalContext.cpp
@@ -0,0 +1,111 @@
+/*
+ * File: EvalContext.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "EvalContext.h"
+#include <stdexcept>
+#include "format_string.h"
+
+using namespace elftosb;
+
+EvalContext::EvalContext()
+: m_sourcesManager(0)
+{
+}
+
+EvalContext::~EvalContext()
+{
+}
+
+bool EvalContext::isVariableDefined(const std::string & name)
+{
+ variable_map_t::const_iterator it = m_variables.find(name);
+ return it != m_variables.end();
+}
+
+uint32_t EvalContext::getVariableValue(const std::string & name)
+{
+ variable_map_t::const_iterator it = m_variables.find(name);
+ if (it == m_variables.end())
+ {
+ throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
+ }
+
+ return it->second.m_value;
+}
+
+int_size_t EvalContext::getVariableSize(const std::string & name)
+{
+ variable_map_t::const_iterator it = m_variables.find(name);
+ if (it == m_variables.end())
+ {
+ throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
+ }
+
+ return it->second.m_size;
+}
+
+void EvalContext::setVariable(const std::string & name, uint32_t value, int_size_t size)
+{
+ // check if var is locked
+ variable_map_t::const_iterator it = m_variables.find(name);
+ if (it != m_variables.end() && it->second.m_isLocked)
+ {
+ return;
+ }
+
+ // set var info
+ variable_info_t info;
+ info.m_value = value;
+ info.m_size = size;
+ info.m_isLocked = false;
+ m_variables[name] = info;
+}
+
+bool EvalContext::isVariableLocked(const std::string & name)
+{
+ variable_map_t::const_iterator it = m_variables.find(name);
+ if (it == m_variables.end())
+ {
+ throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
+ }
+
+ return it->second.m_isLocked;
+}
+
+void EvalContext::lockVariable(const std::string & name)
+{
+ variable_map_t::iterator it = m_variables.find(name);
+ if (it == m_variables.end())
+ {
+ throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
+ }
+
+ it->second.m_isLocked = true;
+}
+
+void EvalContext::unlockVariable(const std::string & name)
+{
+ variable_map_t::iterator it = m_variables.find(name);
+ if (it == m_variables.end())
+ {
+ throw std::runtime_error("undefined variable");
+ }
+
+ it->second.m_isLocked = false;
+}
+
+void EvalContext::dump()
+{
+ variable_map_t::iterator it = m_variables.begin();
+ for (; it != m_variables.end(); ++it)
+ {
+ variable_info_t & info = it->second;
+ const char * lockedString = info.m_isLocked ? "locked" : "unlocked";
+ printf("%s = %u:%d (%s)\n", it->first.c_str(), info.m_value, (int)info.m_size, lockedString);
+ }
+}
+
diff --git a/common/EvalContext.h b/common/EvalContext.h
new file mode 100644
index 0000000..8c56d60
--- /dev/null
+++ b/common/EvalContext.h
@@ -0,0 +1,99 @@
+/*
+ * File: EvalContext.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_EvalContext_h_)
+#define _EvalContext_h_
+
+#include <map>
+#include <string>
+#include "Value.h"
+#include "int_size.h"
+#include "SourceFile.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Context for evaluating AST tree and expressions.
+ *
+ * Keeps a map of variable names to integer values. Each integer value has a
+ * size attribute in addition to the actual value. Variables can be locked, which
+ * simply means that they cannot be assigned a new value.
+ *
+ * \todo Switch to using Value instances to keep track of variable values. This
+ * will enable variables to have string values, for one.
+ */
+class EvalContext
+{
+public:
+ /*!
+ * \brief Abstract interface for a manager of source files.
+ */
+ class SourceFileManager
+ {
+ public:
+ //! \brief Returns true if a source file with the name \a name exists.
+ virtual bool hasSourceFile(const std::string & name)=0;
+
+ //! \brief Gets the requested source file.
+ virtual SourceFile * getSourceFile(const std::string & name)=0;
+
+ //! \brief Returns the default source file, or NULL if none is set.
+ virtual SourceFile * getDefaultSourceFile()=0;
+ };
+
+public:
+ //! \brief Constructor.
+ EvalContext();
+
+ //! \brief Destructor.
+ virtual ~EvalContext();
+
+ //! \name Source file manager
+ //@{
+ //! \brief
+ void setSourceFileManager(SourceFileManager * manager) { m_sourcesManager = manager; }
+
+ //! \brief
+ SourceFileManager * getSourceFileManager() { return m_sourcesManager; }
+ //@}
+
+ //! \name Variables
+ //@{
+ bool isVariableDefined(const std::string & name);
+ uint32_t getVariableValue(const std::string & name);
+ int_size_t getVariableSize(const std::string & name);
+ void setVariable(const std::string & name, uint32_t value, int_size_t size=kWordSize);
+ //@}
+
+ //! \name Locks
+ //@{
+ bool isVariableLocked(const std::string & name);
+ void lockVariable(const std::string & name);
+ void unlockVariable(const std::string & name);
+ //@}
+
+ void dump();
+
+protected:
+ //! Information about a variable's value.
+ struct variable_info_t
+ {
+ uint32_t m_value; //!< Variable value.
+ int_size_t m_size; //!< Number of bytes
+ bool m_isLocked; //!< Can this variable's value be changed?
+ };
+
+ //! Type to maps between the variable name and its info.
+ typedef std::map<std::string, variable_info_t> variable_map_t;
+
+ SourceFileManager * m_sourcesManager; //!< Interface to source file manager.
+ variable_map_t m_variables; //!< Map of variables to their final values.
+};
+
+}; // namespace elftosb
+
+#endif // _EvalContext_h_
diff --git a/common/ExcludesListMatcher.cpp b/common/ExcludesListMatcher.cpp
new file mode 100644
index 0000000..56d67d6
--- /dev/null
+++ b/common/ExcludesListMatcher.cpp
@@ -0,0 +1,88 @@
+/*
+ * File: ExcludesListMatcher.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "ExcludesListMatcher.h"
+
+using namespace elftosb;
+
+ExcludesListMatcher::ExcludesListMatcher()
+: GlobMatcher("")
+{
+}
+
+ExcludesListMatcher::~ExcludesListMatcher()
+{
+}
+
+//! \param isInclude True if this pattern is an include, false if it is an exclude.
+//! \param pattern String containing the glob pattern.
+void ExcludesListMatcher::addPattern(bool isInclude, const std::string & pattern)
+{
+ glob_list_item_t item;
+ item.m_isInclude = isInclude;
+ item.m_glob = pattern;
+
+ // add to end of list
+ m_patterns.push_back(item);
+}
+
+//! If there are no entries in the match list, the match fails.
+//!
+//! \param testValue The string to match against the pattern list.
+//! \retval true The \a testValue argument matches.
+//! \retval false No match was made against the argument.
+bool ExcludesListMatcher::match(const std::string & testValue)
+{
+ if (!m_patterns.size())
+ {
+ return false;
+ }
+
+ // Iterate over the match list. Includes act as an OR operator, while
+ // excludes act as an AND operator.
+ bool didMatch = false;
+ bool isFirstItem = true;
+ glob_list_t::iterator it = m_patterns.begin();
+ for (; it != m_patterns.end(); ++it)
+ {
+ glob_list_item_t & item = *it;
+
+ // if this pattern is an include and it doesn't match, or
+ // if this pattern is an exclude and it does match, then the match fails
+ bool didItemMatch = globMatch(testValue.c_str(), item.m_glob.c_str());
+
+ if (item.m_isInclude)
+ {
+ // Include
+ if (isFirstItem)
+ {
+ didMatch = didItemMatch;
+ }
+ else
+ {
+ didMatch = didMatch || didItemMatch;
+ }
+ }
+ else
+ {
+ // Exclude
+ if (isFirstItem)
+ {
+ didMatch = !didItemMatch;
+ }
+ else
+ {
+ didMatch = didMatch && !didItemMatch;
+ }
+ }
+
+ isFirstItem = false;
+ }
+
+ return didMatch;
+}
+
diff --git a/common/ExcludesListMatcher.h b/common/ExcludesListMatcher.h
new file mode 100644
index 0000000..31398a8
--- /dev/null
+++ b/common/ExcludesListMatcher.h
@@ -0,0 +1,67 @@
+/*
+ * File: ExcludesListMatcher.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ExcludesListMatcher_h_)
+#define _ExcludesListMatcher_h_
+
+#include "GlobMatcher.h"
+#include <vector>
+#include <string>
+
+namespace elftosb
+{
+
+/*!
+ * \brief Matches strings using a series of include and exclude glob patterns.
+ *
+ * This string matcher class uses a sequential, ordered list of glob patterns to
+ * determine whether a string matches. Attached to each pattern is an include/exclude
+ * action. The patterns in the list effectively form a Boolean expression. Includes
+ * act as an OR operator while excludes act as an AND NOT operator.
+ *
+ * Examples (plus prefix is include, minus prefix is exclude):
+ * - +foo: foo
+ * - -foo: !foo
+ * - +foo, +bar: foo || bar
+ * - +foo, -bar: foo && !bar
+ * - +foo, -bar, +baz: foo && !bar || baz
+ *
+ * The only reason for inheriting from GlobMatcher is so we can access the protected
+ * globMatch() method.
+ */
+class ExcludesListMatcher : public GlobMatcher
+{
+public:
+ //! \brief Default constructor.
+ ExcludesListMatcher();
+
+ //! \brief Destructor.
+ ~ExcludesListMatcher();
+
+ //! \name Pattern list
+ //@{
+ //! \brief Add one include or exclude pattern to the end of the match list.
+ void addPattern(bool isInclude, const std::string & pattern);
+ //@}
+
+ //! \brief Performs a single string match test against testValue.
+ virtual bool match(const std::string & testValue);
+
+protected:
+ //! \brief Information about one glob pattern entry in a match list.
+ struct glob_list_item_t
+ {
+ bool m_isInclude; //!< True if include, false if exclude.
+ std::string m_glob; //!< The glob pattern to match.
+ };
+
+ typedef std::vector<glob_list_item_t> glob_list_t;
+ glob_list_t m_patterns; //!< Ordered list of include and exclude patterns.
+};
+
+}; // namespace elftosb
+
+#endif // _ExcludesListMatcher_h_
diff --git a/common/GHSSecInfo.cpp b/common/GHSSecInfo.cpp
new file mode 100644
index 0000000..300366c
--- /dev/null
+++ b/common/GHSSecInfo.cpp
@@ -0,0 +1,100 @@
+/*
+ * File: GHSSecInfo.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "GHSSecInfo.h"
+#include <stdexcept>
+#include "Logging.h"
+#include "EndianUtilities.h"
+
+//! The name of the GHS-specific section info table ELF section.
+const char * const kSecInfoSectionName = ".secinfo";
+
+using namespace elftosb;
+
+//! The ELF file passed into this constructor as the \a elf argument must remain
+//! valid for the life of this object.
+//!
+//! \param elf The ELF file parser. An assertion is raised if this is NULL.
+GHSSecInfo::GHSSecInfo(StELFFile * elf)
+: m_elf(elf), m_hasInfo(false), m_info(0), m_entryCount(0)
+{
+ assert(elf);
+
+ // look up the section. if it's not there just leave m_info and m_entryCount to 0
+ unsigned sectionIndex = m_elf->getIndexOfSectionWithName(kSecInfoSectionName);
+ if (sectionIndex == SHN_UNDEF)
+ {
+ return;
+ }
+
+ // get the section data
+ const Elf32_Shdr & secInfo = m_elf->getSectionAtIndex(sectionIndex);
+ if (secInfo.sh_type != SHT_PROGBITS)
+ {
+ // .secinfo section isn't the right type, so something is wrong
+ return;
+ }
+
+ m_hasInfo = true;
+ m_info = (ghs_secinfo_t *)m_elf->getSectionDataAtIndex(sectionIndex);
+ m_entryCount = secInfo.sh_size / sizeof(ghs_secinfo_t);
+}
+
+//! Looks up \a addr for \a length in the .secinfo array. Only if that address is in the
+//! .secinfo array does this section need to be filled. If the section is found but the
+//! length does not match the \a length argument, a message is logged at the
+//! #Logger::WARNING level.
+//!
+//! If the .secinfo section is not present in the ELF file, this method always returns
+//! true.
+//!
+//! \param addr The start address of the section to query.
+//! \param length The length of the section. If a section with a start address matching
+//! \a addr is found, its length must match \a length to be considered.
+//!
+//! \retval true The section matching \a addr and \a length was found and should be filled.
+//! True is also returned when the ELF file does not have a .secinfo section.
+//! \retval false The section was not found and should not be filled.
+bool GHSSecInfo::isSectionFilled(uint32_t addr, uint32_t length)
+{
+ if (!m_hasInfo)
+ {
+ return true;
+ }
+
+ unsigned i;
+ for (i = 0; i < m_entryCount; ++i)
+ {
+ // byte swap these values into host endianness
+ uint32_t clearAddr = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_clearAddr);
+ uint32_t numBytesToClear = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_numBytesToClear);
+
+ // we only consider non-zero length clear regions
+ if ((addr == clearAddr) && (numBytesToClear != 0))
+ {
+ // it is an error if the address matches but the length does not
+ if (length != numBytesToClear)
+ {
+ Log::log(Logger::WARNING, "ELF Error: Size mismatch @ sect=%u, .secinfo=%u at addr 0x%08X\n", length, numBytesToClear, addr);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//! Simply calls through to isSectionFilled(uint32_t, uint32_t) to determine
+//! if \a section should be filled.
+//!
+//! If the .secinfo section is not present in the ELF file, this method always returns
+//! true.
+bool GHSSecInfo::isSectionFilled(const Elf32_Shdr & section)
+{
+ return isSectionFilled(section.sh_addr, section.sh_size);
+}
+
diff --git a/common/GHSSecInfo.h b/common/GHSSecInfo.h
new file mode 100644
index 0000000..9042d39
--- /dev/null
+++ b/common/GHSSecInfo.h
@@ -0,0 +1,72 @@
+/*
+ * File: GHSSecInfo.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_GHSSecInfo_h_)
+#define _GHSSecInfo_h_
+
+#include "StELFFile.h"
+#include "smart_ptr.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Wrapper around the GHS-specific .secinfo ELF section.
+ *
+ * ELF files produced by the Green Hills MULTI toolset will have a
+ * special .secinfo section. For the most part, this section contains
+ * a list of address
+ * ranges that should be filled by the C runtime startup code. The
+ * address ranges correspond to those of ELF sections whose type is
+ * #SHT_NOBITS. The GHS runtime uses this table instead of just filling
+ * all #SHT_NOBITS sections because the linker command file can
+ * be used to optionally not fill individual sections.
+ *
+ * The isSectionFilled() methods let calling code determine if an ELF
+ * section is found in the .secinfo table. If the section is found,
+ * then it should be filled.
+ */
+class GHSSecInfo
+{
+public:
+ //! \brief Default constructor.
+ GHSSecInfo(StELFFile * elf);
+
+ //! \brief Returns true if there is a .secinfo section present in the ELF file.
+ bool hasSecinfo() const { return m_hasInfo; }
+
+ //! \brief Determines if a section should be filled.
+ bool isSectionFilled(uint32_t addr, uint32_t length);
+
+ //! \brief Determines if \a section should be filled.
+ bool isSectionFilled(const Elf32_Shdr & section);
+
+protected:
+
+#pragma pack(1)
+
+ /*!
+ * \brief The structure of one .secinfo entry.
+ */
+ struct ghs_secinfo_t
+ {
+ uint32_t m_clearAddr; //!< Address to start filling from.
+ uint32_t m_clearValue; //!< Value to fill with.
+ uint32_t m_numBytesToClear; //!< Number of bytes to fill.
+ };
+
+#pragma pack()
+
+protected:
+ StELFFile * m_elf; //!< The parser object for our ELF file.
+ bool m_hasInfo; //!< Whether .secinfo is present in the ELF file.
+ smart_array_ptr<ghs_secinfo_t> m_info; //!< Pointer to the .secinfo entries. Will be NULL if there is no .secinfo section in the file.
+ unsigned m_entryCount; //!< Number of entries in #m_info.
+};
+
+}; // namespace elftosb
+
+#endif // _GHSSecInfo_h_
diff --git a/common/GlobMatcher.cpp b/common/GlobMatcher.cpp
new file mode 100644
index 0000000..24e7b91
--- /dev/null
+++ b/common/GlobMatcher.cpp
@@ -0,0 +1,129 @@
+/*
+ * File: GlobMatcher.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "GlobMatcher.h"
+
+#ifndef NEGATE
+#define NEGATE '^' // std cset negation char
+#endif
+
+using namespace elftosb;
+
+//! The glob pattern must match the \e entire test value argument in order
+//! for the match to be considered successful. Thus, even if, for example,
+//! the pattern matches all but the last character the result will be false.
+//!
+//! \retval true The test value does match the glob pattern.
+//! \retval false The test value does not match the glob pattern.
+bool GlobMatcher::match(const std::string & testValue)
+{
+ return globMatch(testValue.c_str(), m_pattern.c_str());
+}
+
+//! \note This glob implementation was originally written by ozan s. yigit in
+//! December 1994. This is public domain source code.
+bool GlobMatcher::globMatch(const char *str, const char *p)
+{
+ int negate;
+ int match;
+ int c;
+
+ while (*p) {
+ if (!*str && *p != '*')
+ return false;
+
+ switch (c = *p++) {
+
+ case '*':
+ while (*p == '*')
+ p++;
+
+ if (!*p)
+ return true;
+
+ if (*p != '?' && *p != '[' && *p != '\\')
+ while (*str && *p != *str)
+ str++;
+
+ while (*str) {
+ if (globMatch(str, p))
+ return true;
+ str++;
+ }
+ return false;
+
+ case '?':
+ if (*str)
+ break;
+ return false;
+
+ // set specification is inclusive, that is [a-z] is a, z and
+ // everything in between. this means [z-a] may be interpreted
+ // as a set that contains z, a and nothing in between.
+ case '[':
+ if (*p != NEGATE)
+ negate = false;
+ else {
+ negate = true;
+ p++;
+ }
+
+ match = false;
+
+ while (!match && (c = *p++)) {
+ if (!*p)
+ return false;
+ if (*p == '-') { // c-c
+ if (!*++p)
+ return false;
+ if (*p != ']') {
+ if (*str == c || *str == *p ||
+ (*str > c && *str < *p))
+ match = true;
+ }
+ else { // c-]
+ if (*str >= c)
+ match = true;
+ break;
+ }
+ }
+ else { // cc or c]
+ if (c == *str)
+ match = true;
+ if (*p != ']') {
+ if (*p == *str)
+ match = true;
+ }
+ else
+ break;
+ }
+ }
+
+ if (negate == match)
+ return false;
+ // if there is a match, skip past the cset and continue on
+ while (*p && *p != ']')
+ p++;
+ if (!*p++) // oops!
+ return false;
+ break;
+
+ case '\\':
+ if (*p)
+ c = *p++;
+ default:
+ if (c != *str)
+ return false;
+ break;
+
+ }
+ str++;
+ }
+
+ return !*str;
+}
+
diff --git a/common/GlobMatcher.h b/common/GlobMatcher.h
new file mode 100644
index 0000000..c9e5641
--- /dev/null
+++ b/common/GlobMatcher.h
@@ -0,0 +1,59 @@
+/*
+ * File: GlobMatcher.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_GlobMatcher_h_)
+#define _GlobMatcher_h_
+
+#include "StringMatcher.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief This class uses glob pattern matching to match strings.
+ *
+ * Glob patterns:
+ * - * matches zero or more characters
+ * - ? matches any single character
+ * - [set] matches any character in the set
+ * - [^set] matches any character NOT in the set
+ * where a set is a group of characters or ranges. a range
+ * is written as two characters seperated with a hyphen: a-z denotes
+ * all characters between a to z inclusive.
+ * - [-set] set matches a literal hypen and any character in the set
+ * - []set] matches a literal close bracket and any character in the set
+ *
+ * - char matches itself except where char is '*' or '?' or '['
+ * - \\char matches char, including any pattern character
+ *
+ * Examples:
+ * - a*c ac abc abbc ...
+ * - a?c acc abc aXc ...
+ * - a[a-z]c aac abc acc ...
+ * - a[-a-z]c a-c aac abc ...
+ */
+class GlobMatcher : public StringMatcher
+{
+public:
+ //! \brief Constructor.
+ GlobMatcher(const std::string & pattern)
+ : StringMatcher(), m_pattern(pattern)
+ {
+ }
+
+ //! \brief Returns whether \a testValue matches the glob pattern.
+ virtual bool match(const std::string & testValue);
+
+protected:
+ std::string m_pattern; //!< The glob pattern to match against.
+
+ //! \brief Glob implementation.
+ bool globMatch(const char * str, const char * p);
+};
+
+}; // namespace elftosb
+
+#endif // _GlobMatcher_h_
diff --git a/common/HexValues.cpp b/common/HexValues.cpp
new file mode 100644
index 0000000..5eb2e39
--- /dev/null
+++ b/common/HexValues.cpp
@@ -0,0 +1,34 @@
+/*
+ * File: HexValues.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "HexValues.h"
+
+bool isHexDigit(char c)
+{
+ return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+//! \return The integer equivalent to \a c.
+//! \retval -1 The character \a c is not a hex character.
+uint8_t hexCharToInt(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else
+ return static_cast<uint8_t>(-1);
+}
+
+//! \param encodedByte Must point to at least two ASCII hex characters.
+//!
+uint8_t hexByteToInt(const char * encodedByte)
+{
+ return (hexCharToInt(encodedByte[0]) << 4) | hexCharToInt(encodedByte[1]);
+}
diff --git a/common/HexValues.h b/common/HexValues.h
new file mode 100644
index 0000000..b6dd821
--- /dev/null
+++ b/common/HexValues.h
@@ -0,0 +1,21 @@
+/*
+ * File: HexValues.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_HexValues_h_)
+#define _HexValues_h_
+
+#include "stdafx.h"
+
+//! \brief Determines whether \a c is a hex digit character.
+bool isHexDigit(char c);
+
+//! \brief Converts a hexidecimal character to the integer equivalent.
+uint8_t hexCharToInt(char c);
+
+//! \brief Converts a hex-encoded byte to the integer equivalent.
+uint8_t hexByteToInt(const char * encodedByte);
+
+#endif // _HexValues_h_
diff --git a/common/IVTDataSource.cpp b/common/IVTDataSource.cpp
new file mode 100644
index 0000000..88c4753
--- /dev/null
+++ b/common/IVTDataSource.cpp
@@ -0,0 +1,113 @@
+/*
+ * File: DataSource.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Freescale Semiconductor, Inc.
+ * Proprietary & Confidential
+ *
+ * This source code and the algorithms implemented therein constitute
+ * confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
+ * or its associates, and any use thereof is subject to the terms and
+ * conditions of the Confidential Disclosure Agreement pursual to which this
+ * source code was originally received.
+ */
+
+#include "IVTDataSource.h"
+#include "DataTarget.h"
+#include "EndianUtilities.h"
+#include <algorithm>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace elftosb;
+
+IVTDataSource::IVTDataSource()
+: DataSource(),
+ DataSource::Segment((DataSource&)*this),
+ m_isSelfSet(false)
+{
+ // Init the IVT structure.
+ memset(&m_ivt, 0, sizeof(m_ivt));
+ hab_hdr_t hdr = IVT_HDR(sizeof(m_ivt), HAB_VERSION);
+ m_ivt.hdr = hdr;
+}
+
+unsigned IVTDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
+{
+ // Bail if the offset is out of range.
+ if (offset >= sizeof(m_ivt))
+ {
+ return 0;
+ }
+
+ // If we have an associated target, and the IVT self pointer is not set, then
+ // fill in the self pointer from the target address.
+ if (m_target && !m_isSelfSet)
+ {
+ m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(m_target->getBeginAddress());
+ }
+
+ // Truncate max bytes at the end of the IVT.
+ maxBytes = std::min<unsigned>(maxBytes, sizeof(m_ivt) - offset);
+
+ // Copy into output buffer.
+ if (maxBytes)
+ {
+ memcpy(buffer, (uint8_t *)&m_ivt + offset, maxBytes);
+ }
+
+ return maxBytes;
+}
+
+unsigned IVTDataSource::getLength()
+{
+ return sizeof(m_ivt);
+}
+
+//! The IVT has a natural location if its self pointer was explicitly specified.
+//!
+bool IVTDataSource::hasNaturalLocation()
+{
+ return m_isSelfSet;
+}
+
+//!
+uint32_t IVTDataSource::getBaseAddress()
+{
+ return m_ivt.self;
+}
+
+bool IVTDataSource::setFieldByName(const std::string & name, uint32_t value)
+{
+ if (name == "entry")
+ {
+ m_ivt.entry = ENDIAN_HOST_TO_LITTLE_U32(value);
+ }
+ else if (name == "dcd")
+ {
+ m_ivt.dcd = ENDIAN_HOST_TO_LITTLE_U32(value);
+ }
+ else if (name == "boot_data")
+ {
+ m_ivt.boot_data = ENDIAN_HOST_TO_LITTLE_U32(value);
+ }
+ else if (name == "self")
+ {
+ m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(value);
+ m_isSelfSet = true;
+ }
+ else if (name == "csf")
+ {
+ m_ivt.csf = ENDIAN_HOST_TO_LITTLE_U32(value);
+ }
+ else
+ {
+ // Unrecognized field name.
+ return false;
+ }
+
+ return true;
+}
+
+
diff --git a/common/IVTDataSource.h b/common/IVTDataSource.h
new file mode 100644
index 0000000..1890bdd
--- /dev/null
+++ b/common/IVTDataSource.h
@@ -0,0 +1,296 @@
+/*
+ * File: DataSource.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Freescale Semiconductor, Inc.
+ * Proprietary & Confidential
+ *
+ * This source code and the algorithms implemented therein constitute
+ * confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
+ * or its associates, and any use thereof is subject to the terms and
+ * conditions of the Confidential Disclosure Agreement pursual to which this
+ * source code was originally received.
+ */
+#if !defined(_IVTDataSource_h_)
+#define _IVTDataSource_h_
+
+#include "DataSource.h"
+
+/** Header field components
+ * @ingroup hdr
+ */
+typedef struct hab_hdr {
+ uint8_t tag; /**< Tag field */
+ uint8_t len[2]; /**< Length field in bytes (big-endian) */
+ uint8_t par; /**< Parameters field */
+} hab_hdr_t;
+
+/** Image entry function prototype
+ * @ingroup rvt
+ *
+ * This typedef serves as the return type for hab_rvt.authenticate_image(). It
+ * specifies a void-void function pointer, but can be cast to another function
+ * pointer type if required.
+ */
+typedef void (*hab_image_entry_f)(void);
+
+/** @ref ivt structure
+ * @ingroup ivt
+ *
+ * @par Format
+ *
+ * An @ref ivt consists of a @ref hdr followed by a list of addresses as
+ * described further below.
+ *
+ * @warning The @a entry address may not be NULL.
+ *
+ * @warning On an IC not configured as #HAB_CFG_CLOSED, the
+ * @a csf address may be NULL. If it is not NULL, the @ref csf will be
+ * processed, but any failures should be non-fatal.
+ *
+ * @warning On an IC configured as #HAB_CFG_CLOSED, the @a
+ * csf address may not be NULL, and @ref csf failures are typically fatal.
+ *
+ * @remark The Boot Data located using the @a boot_data field is interpreted
+ * by the HAB caller in a boot-mode specific manner. This may be used by the
+ * boot ROM as to determine the load address and boot device configuration for
+ * images loaded from block devices (see @ref ref_rug for details).
+ *
+ * @remark All addresses given in the IVT, including the Boot Data (if
+ * present) are those for the final load location.
+ *
+ * @anchor ila
+ *
+ * @par Initial load addresses
+ *
+ * The @a self field is used to calculate addresses in boot modes where an
+ * initial portion of the image is loaded to an initial location. In such
+ * cases, the IVT, Boot Data (if present) and DCD (if present) are used in
+ * configuring the IC and loading the full image to its final location. Only
+ * the IVT, Boot Data (if present) and DCD (if present) are required to be
+ * within the initial image portion.
+ *
+ * The method for calculating an initial load address for the DCD is
+ * illustrated in the following C fragment. Similar calculations apply to
+ * other fields.
+ *
+@verbatim
+ hab_ivt_t* ivt_initial = <initial IVT load address>;
+ const void* dcd_initial = ivt_initial->dcd;
+ if (ivt_initial->dcd != NULL)
+ dcd_initial = (const uint8_t*)ivt_initial
+ + (ivt_initial->dcd - ivt_initial->self)
+@endverbatim
+
+ * \note The void* types in this structure have been changed to uint32_t so
+ * that this code will work correctly when compiled on a 64-bit host.
+ * Otherwise the structure would come out incorrect.
+ */
+struct hab_ivt {
+ /** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields
+ * (see @ref data)
+ */
+ hab_hdr_t hdr;
+ /** Absolute address of the first instruction to execute from the
+ * image
+ */
+ /*hab_image_entry_f*/ uint32_t entry;
+ /** Reserved in this version of HAB: should be NULL. */
+ /*const void*/ uint32_t reserved1;
+ /** Absolute address of the image DCD: may be NULL. */
+ /*const void*/ uint32_t dcd;
+ /** Absolute address of the Boot Data: may be NULL, but not interpreted
+ * any further by HAB
+ */
+ /*const void*/ uint32_t boot_data;
+ /** Absolute address of the IVT.*/
+ /*const void*/ uint32_t self;
+ /** Absolute address of the image CSF.*/
+ /*const void*/ uint32_t csf;
+ /** Reserved in this version of HAB: should be zero. */
+ uint32_t reserved2;
+};
+
+/** @ref ivt type
+ * @ingroup ivt
+ */
+typedef struct hab_ivt hab_ivt_t;
+
+/*
+ * Helper macros
+ */
+#define HAB_CMD_UNS 0xff
+
+#define DEFAULT_IMG_KEY_IDX 2
+
+#define GEN_MASK(width) \
+ ((1UL << (width)) - 1)
+
+#define GEN_FIELD(f, width, shift) \
+ (((f) & GEN_MASK(width)) << (shift))
+
+#define PACK_UINT32(a, b, c, d) \
+ ( (((a) & 0xFF) << 24) \
+ |(((b) & 0xFF) << 16) \
+ |(((c) & 0xFF) << 8) \
+ |(((d) & 0xFF)) )
+
+#define EXPAND_UINT32(w) \
+ (uint8_t)((w)>>24), (uint8_t)((w)>>16), (uint8_t)((w)>>8), (uint8_t)(w)
+
+#define HDR(tag, bytes, par) \
+ (uint8_t)(tag), (uint8_t)((bytes)>>8), (uint8_t)(bytes), (uint8_t)(par)
+
+#define HAB_VER(maj, min) \
+ (GEN_FIELD((maj), HAB_VER_MAJ_WIDTH, HAB_VER_MAJ_SHIFT) \
+ | GEN_FIELD((min), HAB_VER_MIN_WIDTH, HAB_VER_MIN_SHIFT))
+
+/*
+ * CSF header
+ */
+
+#define CSF_HDR(bytes, HABVER) \
+ HDR(HAB_TAG_CSF, (bytes), HABVER)
+
+
+/*
+ * DCD header
+ */
+
+#define DCD_HDR(bytes, HABVER) \
+ HDR(HAB_TAG_DCD, (bytes), HABVER)
+
+/*
+ * IVT header (goes in the struct's hab_hdr_t field, not a byte array)
+ */
+#define IVT_HDR(bytes, HABVER) \
+ {HAB_TAG_IVT, {(uint8_t)((bytes)>>8), (uint8_t)(bytes)}, HABVER}
+
+/** @name External data structure tags
+ * @anchor dat_tag
+ *
+ * Tag values 0x00 .. 0xef are reserved for HAB. Values 0xf0 .. 0xff
+ * are available for custom use.
+ */
+/*@{*/
+#define HAB_TAG_IVT 0xd1 /**< Image Vector Table */
+#define HAB_TAG_DCD 0xd2 /**< Device Configuration Data */
+#define HAB_TAG_CSF 0xd4 /**< Command Sequence File */
+#define HAB_TAG_CRT 0xd7 /**< Certificate */
+#define HAB_TAG_SIG 0xd8 /**< Signature */
+#define HAB_TAG_EVT 0xdb /**< Event */
+#define HAB_TAG_RVT 0xdd /**< ROM Vector Table */
+/* Values b0 ... cf reserved for CSF commands. Values e0 ... ef reserved for
+ * key types.
+ *
+ * Available values: 03, 05, 06, 09, 0a, 0c, 0f, 11, 12, 14, 17, 18, 1b, 1d,
+ * 1e, 21, 22, 24, 27, 28, 2b, 2d, 2e, 30, 33, 35, 36, 39, 3a, 3c, 3f, 41, 42,
+ * 44, 47, 48, 4b, 4d, 4e, 50, 53, 55, 56, 59, 5a, 5c, 5f, 60, 63, 65, 66, 69,
+ * 6a, 6c, 6f, 71, 72, 74, 77, 78, 7b, 7d, 7e, 81, 82, 84, 87, 88, 8b, 8d, 8e,
+ * 90, 93, 95, 96, 99, 9a, 9c, 9f, a0, a3, a5, a6, a9, aa, ac, af, b1, b2, b4,
+ * b7, b8, bb, bd, be
+ *
+ * Custom values: f0, f3, f5, f6, f9, fa, fc, ff
+ */
+/*@}*/
+
+/** @name HAB version */
+/*@{*/
+#define HAB_MAJOR_VERSION 4 /**< Major version of this HAB release */
+#define HAB_MINOR_VERSION 0 /**< Minor version of this HAB release */
+#define HAB_VER_MAJ_WIDTH 4 /**< Major version field width */
+#define HAB_VER_MAJ_SHIFT 4 /**< Major version field offset */
+#define HAB_VER_MIN_WIDTH 4 /**< Minor version field width */
+#define HAB_VER_MIN_SHIFT 0 /**< Minor version field offset */
+/** Full version of this HAB release @hideinitializer */
+#define HAB_VERSION HAB_VER(HAB_MAJOR_VERSION, HAB_MINOR_VERSION)
+/** Base version for this HAB release @hideinitializer */
+#define HAB_BASE_VERSION HAB_VER(HAB_MAJOR_VERSION, 0)
+
+/*@}*/
+
+namespace elftosb {
+
+/*!
+ * \brief Data source for an IVT structure used by HAB4.
+ *
+ * This data source represents an IVT structure used by HAB4. Fields of the IVT can be set
+ * by name, making it easy to interface with a parser. And it has some intelligence regarding
+ * the IVT's self pointer. Before the data is copied out by the getData() method, the self field
+ * will be filled in automatically if it has not already been set and there is an associated
+ * data target object. This lets the IVT pick up its own address from the location where it is
+ * being loaded. Alternatively, if the self pointer is filled in explicitly, then the data
+ * source will have a natural location equal to the self pointer.
+ *
+ * This data source acts as its own segment.
+ */
+class IVTDataSource : public DataSource, public DataSource::Segment
+{
+public:
+ //! \brief Default constructor.
+ IVTDataSource();
+
+ //! \brief There is only one segment.
+ virtual unsigned getSegmentCount() { return 1; }
+
+ //! \brief Returns this object, as it is its own segment.
+ virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }
+
+ //! \name Segment methods
+ //@{
+
+ //! \brief Copy out some or all of the IVT structure.
+ //!
+ virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
+
+ //! \brief Gets the length of the segment's data.
+ virtual unsigned getLength();
+
+ //! \brief Returns whether the segment has an associated address.
+ virtual bool hasNaturalLocation();
+
+ //! \brief Returns the address associated with the segment.
+ virtual uint32_t getBaseAddress();
+
+ //@}
+
+ //! \name IVT access
+ //@{
+
+ //! \brief Set one of the IVT's fields by providing its name.
+ //!
+ //! Acceptable field names are:
+ //! - entry
+ //! - dcd
+ //! - boot_data
+ //! - self
+ //! - csf
+ //!
+ //! As long as the \a name parameter specifies one of these fields, the return value
+ //! will be true. If \a name contains any other value, then false will be returned and
+ //! the IVT left unmodified.
+ //!
+ //! Once the \a self field has been set to any value, the data source will have a
+ //! natural location. This works even if the \a self address is 0.
+ //!
+ //! \param name The name of the field to set. Field names are case sensitive, just like in
+ //! the C language.
+ //! \param value The value to which the field will be set.
+ //! \retval true The field was set successfully.
+ //! \retval false There is no field with the provided name.
+ bool setFieldByName(const std::string & name, uint32_t value);
+
+ //! \brief Returns a reference to the IVT structure.
+ hab_ivt_t & getIVT() { return m_ivt; }
+
+ //@}
+
+protected:
+ hab_ivt_t m_ivt; //!< The IVT structure.
+ bool m_isSelfSet; //!< True if the IVT self pointer was explicitly set.
+};
+
+} // elftosb
+
+#endif // _IVTDataSource_h_
diff --git a/common/Logging.cpp b/common/Logging.cpp
new file mode 100644
index 0000000..f6d3906
--- /dev/null
+++ b/common/Logging.cpp
@@ -0,0 +1,91 @@
+/*
+ * File: Logging.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Logging.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "smart_ptr.h"
+
+// init global logger to null
+Logger * Log::s_logger = NULL;
+
+void Logger::log(const char * fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ log(m_level, fmt, args);
+ va_end(args);
+}
+
+void Logger::log(log_level_t level, const char * fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ log(level, fmt, args);
+ va_end(args);
+}
+
+void Logger::log(const char * fmt, va_list args)
+{
+ log(m_level, fmt, args);
+}
+
+//! Allocates a temporary 1KB buffer which is used to hold the
+//! formatted string.
+void Logger::log(log_level_t level, const char * fmt, va_list args)
+{
+ smart_array_ptr<char> buffer = new char[1024];
+ vsprintf(buffer, fmt, args);
+ if (level <= m_filter)
+ {
+ _log(buffer);
+ }
+}
+
+void Log::log(const char * fmt, ...)
+{
+ if (s_logger)
+ {
+ va_list args;
+ va_start(args, fmt);
+ s_logger->log(fmt, args);
+ va_end(args);
+ }
+}
+
+void Log::log(const std::string & msg)
+{
+ if (s_logger)
+ {
+ s_logger->log(msg);
+ }
+}
+
+void Log::log(Logger::log_level_t level, const char * fmt, ...)
+{
+ if (s_logger)
+ {
+ va_list args;
+ va_start(args, fmt);
+ s_logger->log(level, fmt, args);
+ va_end(args);
+ }
+}
+
+void Log::log(Logger::log_level_t level, const std::string & msg)
+{
+ if (s_logger)
+ {
+ s_logger->log(level, msg);
+ }
+}
+
+void StdoutLogger::_log(const char * msg)
+{
+ printf(msg);
+}
+
diff --git a/common/Logging.h b/common/Logging.h
new file mode 100644
index 0000000..a8e7bed
--- /dev/null
+++ b/common/Logging.h
@@ -0,0 +1,226 @@
+/*
+ * File: Logging.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Logging_h_)
+#define _Logging_h_
+
+#include <string>
+#include <assert.h>
+#include <stdarg.h>
+
+/*!
+ * \brief Base logger class.
+ *
+ * There are two types of logging levels that are used by this class. First
+ * there is the filter level. Any log message that is assigned a level
+ * higher than the current filter level is discarded. Secondly there is the
+ * current output level. Log messages that do not have their own level
+ * use the current output level to determine if they should be shown or
+ * not.
+ *
+ * The two methods setFilterLevel() and setOutputLevel() set the filter
+ * and default output logging levels, respectively. There are corresponding
+ * getter methods as well. Both the filter and output levels are
+ * initialized to #INFO during object construction.
+ *
+ * Most use of the logger classes is expected to be through the Log
+ * class. It provides static logging methods that call through to a global
+ * singleton logger instance. There is also a Log::SetOutputLevel utility
+ * class that makes it extremely easiy to temporarily change the default
+ * output logging level.
+ *
+ * Of all the overloaded log() methods in this class, none of them are
+ * really expected to be reimplemented by subclasses. Instead, there is
+ * the single protected _log() method that takes a simple string pointer.
+ * The other log methods all wind up calling _log(), so it provides a
+ * single point to override. In fact, _log() is pure virtual, so subclasses
+ * must implement it.
+ *
+ * \see Log
+ */
+class Logger
+{
+public:
+ //! \brief Logging levels.
+ enum log_level_t
+ {
+ URGENT = 0, //!< The lowest level, for messages that must always be logged.
+ ERROR, //!< For fatal error messages.
+ WARNING, //!< For non-fatal warning messages.
+ INFO, //!< The normal log level, for status messages.
+ INFO2, //!< For verbose status messages.
+ DEBUG, //!< For internal reporting.
+ DEBUG2 //!< Highest log level; verbose debug logging.
+ };
+
+public:
+ //! \brief Default constructor.
+ Logger() : m_filter(INFO), m_level(INFO) {}
+
+ //! \brief Destructor.
+ virtual ~Logger() {}
+
+ //! \name Logging levels
+ //@{
+ //! \brief Changes the logging level to \a level.
+ inline void setFilterLevel(log_level_t level) { m_filter = level; }
+
+ //! \brief Returns the current logging filter level.
+ inline log_level_t getFilterLevel() const { return m_filter; }
+
+ //! \brief Changes the logging output level to \a level.
+ inline void setOutputLevel(log_level_t level) { m_level = level; }
+
+ //! \brief Returns the current logging output level.
+ inline log_level_t getOutputLevel() const { return m_level; }
+ //@}
+
+ //! \name Logging
+ //@{
+ //! \brief Log with format.
+ virtual void log(const char * fmt, ...);
+
+ //! \brief Log a string object.
+ virtual void log(const std::string & msg) { log(msg.c_str()); }
+
+ //! \brief Log with format at a specific output level.
+ virtual void log(log_level_t level, const char * fmt, ...);
+
+ //! \brief Log a string output at a specific output level.
+ virtual void log(log_level_t level, const std::string & msg) { log(level, msg.c_str()); }
+
+ //! \brief Log with format using an argument list.
+ virtual void log(const char * fmt, va_list args);
+
+ //! \brief Log with format using an argument with a specific output level.
+ virtual void log(log_level_t level, const char * fmt, va_list args);
+ //@}
+
+protected:
+ log_level_t m_filter; //!< The current logging filter level.
+ log_level_t m_level; //!< The current log output level.
+
+protected:
+ //! \brief The base pure virtual logging function implemented by subclasses.
+ virtual void _log(const char * msg)=0;
+};
+
+/*!
+ * \brief Wraps a set of static functions for easy global logging access.
+ *
+ * This class has a set of static methods that make it easy to access a global
+ * logger instance without having to worry about extern symbols. It does this
+ * by keeping a static member variable pointing at the singleton logger instance,
+ * which is set with the setLogger() static method.
+ *
+ * There is also an inner utility class called SetOutputLevel that uses
+ * C++ scoping rules to temporarily change the output logging level. When the
+ * SetOutputLevel instance falls out of scope the output level is restored
+ * to the previous value.
+ */
+class Log
+{
+public:
+ //! \name Singleton logger access
+ //@{
+ //! \brief Returns the current global logger singleton.
+ static inline Logger * getLogger() { return s_logger; }
+
+ //! \brief Sets the global logger singleton instance.
+ static inline void setLogger(Logger * logger) { s_logger = logger; }
+ //@}
+
+ //! \name Logging
+ //@{
+ //! \brief Log with format.
+ static void log(const char * fmt, ...);
+
+ //! \brief Log a string object.
+ static void log(const std::string & msg);
+
+ //! \brief Log with format at a specific output level.
+ static void log(Logger::log_level_t level, const char * fmt, ...);
+
+ //! \brief Log a string output at a specific output level.
+ static void log(Logger::log_level_t level, const std::string & msg);
+ //@}
+
+protected:
+ static Logger * s_logger; //!< The single global logger instance.
+
+public:
+ /*!
+ * \brief Utility class to temporarily change the logging output level.
+ *
+ * This class will change the current logging output level of a given
+ * logger instance. Then when it falls out of scope it will set the
+ * level back to what it was originally.
+ *
+ * Use like this:
+ * \code
+ * // output level is some value here
+ * {
+ * Log::SetOutputLevel leveler(Logger::DEBUG);
+ * // now output level is DEBUG
+ * Log::log("my debug message 1");
+ * Log::log("my debug message 2");
+ * }
+ * // output level is restored to previous value
+ * \endcode
+ */
+ class SetOutputLevel
+ {
+ public:
+ //! \brief Default constructor.
+ //!
+ //! Saves the current logging output level of the global logger,
+ //! as managed by the Log class, and sets the new level to \a level.
+ SetOutputLevel(Logger::log_level_t level)
+ : m_logger(Log::getLogger()), m_saved(Logger::INFO)
+ {
+ assert(m_logger);
+ m_saved = m_logger->getOutputLevel();
+ m_logger->setOutputLevel(level);
+ }
+
+ //! \brief Constructor.
+ //!
+ //! Saves the current logging output level of \a logger and sets
+ //! the new level to \a level.
+ SetOutputLevel(Logger * logger, Logger::log_level_t level)
+ : m_logger(logger), m_saved(logger->getOutputLevel())
+ {
+ assert(m_logger);
+ m_logger->setOutputLevel(level);
+ }
+
+ //! \brief Destructor.
+ //!
+ //! Restores the saved logging output level.
+ ~SetOutputLevel()
+ {
+ m_logger->setOutputLevel(m_saved);
+ }
+
+ protected:
+ Logger * m_logger; //!< The logger instance we're controlling.
+ Logger::log_level_t m_saved; //!< Original logging output level.
+ };
+
+};
+
+
+/*!
+ * \brief Simple logger that writes to stdout.
+ */
+class StdoutLogger : public Logger
+{
+protected:
+ //! \brief Logs the message to stdout.
+ virtual void _log(const char * msg);
+};
+
+#endif // _Logging_h_
diff --git a/common/Operation.cpp b/common/Operation.cpp
new file mode 100644
index 0000000..79fd6d4
--- /dev/null
+++ b/common/Operation.cpp
@@ -0,0 +1,63 @@
+/*
+ * File: Operation.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Operation.h"
+
+using namespace elftosb;
+
+//! The operation object takes ownership of \a source.
+//!
+//! Cross references between the target and source are updated.
+void LoadOperation::setSource(DataSource * source)
+{
+ m_source = source;
+
+ if (m_target)
+ {
+ m_target->setSource(m_source);
+ }
+ if (m_source)
+ {
+ m_source->setTarget(m_target);
+ }
+}
+
+//! The operation object takes ownership of \a target.
+//!
+//! Cross references between the target and source are updated.
+void LoadOperation::setTarget(DataTarget * target)
+{
+ m_target = target;
+
+ if (m_target)
+ {
+ m_target->setSource(m_source);
+ }
+ if (m_source)
+ {
+ m_source->setTarget(m_target);
+ }
+}
+
+//! Disposes of operations objects in the sequence.
+OperationSequence::~OperationSequence()
+{
+// iterator_t it = begin();
+// for (; it != end(); ++it)
+// {
+// delete it->second;
+// }
+}
+
+void OperationSequence::append(const OperationSequence * other)
+{
+ const_iterator_t it = other->begin();
+ for (; it != other->end(); ++it)
+ {
+ m_operations.push_back(*it);
+ }
+}
diff --git a/common/Operation.h b/common/Operation.h
new file mode 100644
index 0000000..2b184e3
--- /dev/null
+++ b/common/Operation.h
@@ -0,0 +1,168 @@
+/*
+ * File: Operation.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Operation_h_)
+#define _Operation_h_
+
+#include "stdafx.h"
+#include <vector>
+#include "DataSource.h"
+#include "DataTarget.h"
+#include "smart_ptr.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract base class for all boot operations.
+ */
+class Operation
+{
+public:
+ Operation() {}
+ virtual ~Operation() {}
+};
+
+/*!
+ * \brief Load data into memory operation.
+ */
+class LoadOperation : public Operation
+{
+public:
+ LoadOperation() : Operation(), m_source(), m_target() {}
+
+ void setSource(DataSource * source);
+ inline DataSource * getSource() { return m_source; }
+
+ void setTarget(DataTarget * target);
+ inline DataTarget * getTarget() { return m_target; }
+
+ inline void setDCDLoad(bool isDCD) { m_isDCDLoad = isDCD; }
+ inline bool isDCDLoad() const { return m_isDCDLoad; }
+
+protected:
+ smart_ptr<DataSource> m_source;
+ smart_ptr<DataTarget> m_target;
+ bool m_isDCDLoad;
+};
+
+/*!
+ * \brief Operation to execute code at a certain address.
+ */
+class ExecuteOperation : public Operation
+{
+public:
+ enum execute_type_t
+ {
+ kJump,
+ kCall
+ };
+
+public:
+ ExecuteOperation() : Operation(), m_target(), m_argument(0), m_type(kCall), m_isHAB(false) {}
+
+ inline void setTarget(DataTarget * target) { m_target = target; }
+ inline DataTarget * getTarget() { return m_target; }
+
+ inline void setArgument(uint32_t arg) { m_argument = arg; }
+ inline uint32_t getArgument() { return m_argument; }
+
+ inline void setExecuteType(execute_type_t type) { m_type = type; }
+ inline execute_type_t getExecuteType() { return m_type; }
+
+ inline void setIsHAB(bool isHAB) { m_isHAB = isHAB; }
+ inline bool isHAB() const { return m_isHAB; }
+
+protected:
+ smart_ptr<DataTarget> m_target;
+ uint32_t m_argument;
+ execute_type_t m_type;
+ bool m_isHAB;
+};
+
+/*!
+ * \brief Authenticate with HAB and execute the entry point.
+ */
+class HABExecuteOperation : public ExecuteOperation
+{
+public:
+ HABExecuteOperation() : ExecuteOperation() {}
+};
+
+/*!
+ * \brief Operation to switch boot modes.
+ */
+class BootModeOperation : public Operation
+{
+public:
+ BootModeOperation() : Operation() {}
+
+ inline void setBootMode(uint32_t mode) { m_bootMode = mode; }
+ inline uint32_t getBootMode() const { return m_bootMode; }
+
+protected:
+ uint32_t m_bootMode; //!< The new boot mode value.
+};
+
+/*!
+ * \brief Ordered sequence of operations.
+ *
+ * The operation objects owned by the sequence are \e not deleted when the
+ * sequence is destroyed. The owner of the sequence must manually delete
+ * the operation objects.
+ */
+class OperationSequence
+{
+public:
+ typedef std::vector<Operation*> operation_list_t; //!< Type for a list of operation objects.
+ typedef operation_list_t::iterator iterator_t; //!< Iterator over operations.
+ typedef operation_list_t::const_iterator const_iterator_t; //!< Const iterator over operations.
+
+public:
+ //! \brief Default constructor.
+ OperationSequence() {}
+
+ //! \brief Constructor. Makes a one-element sequence from \a soleElement.
+ OperationSequence(Operation * soleElement) { m_operations.push_back(soleElement); }
+
+ //! \brief Destructor.
+ virtual ~OperationSequence();
+
+ //! \name Iterators
+ //@{
+ inline iterator_t begin() { return m_operations.begin(); }
+ inline const_iterator_t begin() const { return m_operations.begin(); }
+ inline iterator_t end() { return m_operations.end(); }
+ inline const_iterator_t end() const { return m_operations.end(); }
+ //@}
+
+ inline Operation * operator [] (unsigned index) const { return m_operations[index]; }
+
+ //! \name Status
+ //@{
+ //! \brief Returns the number of operations in the sequence.
+ inline unsigned getCount() const { return m_operations.size(); }
+ //@}
+
+ //! \name Operations
+ //@{
+ //! \brief Append one operation object to the sequence.
+ inline void append(Operation * op) { m_operations.push_back(op); }
+
+ //! \brief Append the contents of \a other onto this sequence.
+ void append(const OperationSequence * other);
+
+ //! \brief Appends \a other onto this sequence.
+ OperationSequence & operator += (const OperationSequence * other) { append(other); return *this; }
+ //@}
+
+protected:
+ operation_list_t m_operations; //!< The list of operations.
+};
+
+}; // namespace elftosb
+
+#endif // _Operation_h_
diff --git a/common/OptionContext.h b/common/OptionContext.h
new file mode 100644
index 0000000..d005164
--- /dev/null
+++ b/common/OptionContext.h
@@ -0,0 +1,50 @@
+/*
+ * File: OptionContext.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_OptionContext_h_)
+#define _OptionContext_h_
+
+#include <string>
+#include "Value.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Pure abstract interface class to a table of options.
+ */
+class OptionContext
+{
+public:
+ //! \brief Detemine whether the named option is present in the table.
+ //! \param name The name of the option to query.
+ //! \retval true The option is present and has a value.
+ //! \retval false No option with that name is in the table.
+ virtual bool hasOption(const std::string & name) const=0;
+
+ //! \brief Returns the option's value.
+ //! \param name The name of the option.
+ //! \return The value for the option named \a name.
+ //! \retval NULL No option is in the table with that name.
+ virtual const Value * getOption(const std::string & name) const=0;
+
+ //! \brief Adds or changes an option's value.
+ //!
+ //! If the option was not already present in the table, it is added.
+ //! Otherwise the old value is replaced.
+ //!
+ //! \param name The option's name.
+ //! \param value New value for the option.
+ virtual void setOption(const std::string & name, Value * value)=0;
+
+ //! \brief Removes an option from the table.
+ //! \param name The name of the option to remove.
+ virtual void deleteOption(const std::string & name)=0;
+};
+
+}; // namespace elftosb
+
+#endif // _OptionContext_h_
diff --git a/common/OptionDictionary.cpp b/common/OptionDictionary.cpp
new file mode 100644
index 0000000..a9acec7
--- /dev/null
+++ b/common/OptionDictionary.cpp
@@ -0,0 +1,170 @@
+/*
+ * File: OptionDictionary.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "OptionDictionary.h"
+
+using namespace elftosb;
+
+//! Deletes all of the option values that have been assigned locally.
+//!
+OptionDictionary::~OptionDictionary()
+{
+ option_map_t::iterator it = m_options.begin();
+ for (; it != m_options.end(); ++it)
+ {
+ if (it->second.m_value)
+ {
+ delete it->second.m_value;
+ }
+ }
+}
+
+//! If a parent context has been set and the option does not exist in
+//! this instance, then the parent is asked if it contains the option.
+//!
+//! \param name The name of the option to query.
+//! \retval true The option is present in this instance or one of the parent.
+//! \retval false No option with that name is in the dictionary, or any parent
+bool OptionDictionary::hasOption(const std::string & name) const
+{
+ bool hasIt = (m_options.find(name) != m_options.end());
+ if (!hasIt && m_parent)
+ {
+ return m_parent->hasOption(name);
+ }
+ return hasIt;
+}
+
+//! If this object does not contain an option with the name of \a name,
+//! then the parent is asked for the value (if a parent has been set).
+//!
+//! \param name The name of the option.
+//! \return The value for the option named \a name.
+//! \retval NULL No option is in the table with that name. An option may also
+//! explicitly be set to a NULL value. The only way to tell the difference
+//! is to use the hasOption() method.
+const Value * OptionDictionary::getOption(const std::string & name) const
+{
+ option_map_t::const_iterator it = m_options.find(name);
+ if (it == m_options.end())
+ {
+ if (m_parent)
+ {
+ return m_parent->getOption(name);
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ return it->second.m_value;
+}
+
+//! If the option was not already present in the table, it is added.
+//! Otherwise the old value is replaced. The option is always set locally;
+//! parent objects are never modified.
+//!
+//! If the option has been locked with a call to lockOption() before trying
+//! to set its value, the setOption() is effectively ignored. To tell if
+//! an option is locked, use the isOptionLocked() method.
+//!
+//! \warning If the option already had a value, that previous value is deleted.
+//! This means that it cannot currently be in use by another piece of code.
+//! See the note in getOption().
+//!
+//! \param name The option's name.
+//! \param value New value for the option.
+void OptionDictionary::setOption(const std::string & name, Value * value)
+{
+ option_map_t::iterator it = m_options.find(name);
+ OptionValue newValue;
+
+ // delete the option value instance before replacing it
+ if (it != m_options.end())
+ {
+ // Cannot modify value if locked.
+ if (it->second.m_isLocked)
+ {
+ return;
+ }
+
+ if (it->second.m_value)
+ {
+ delete it->second.m_value;
+ }
+
+ // save previous locked value
+ newValue.m_isLocked = it->second.m_isLocked;
+ }
+
+ // set new option value
+ newValue.m_value = value;
+ m_options[name] = newValue;
+}
+
+//! \param name The name of the option to remove.
+//!
+void OptionDictionary::deleteOption(const std::string & name)
+{
+ if (m_options.find(name) != m_options.end())
+ {
+ if (m_options[name].m_value)
+ {
+ delete m_options[name].m_value;
+ }
+ m_options.erase(name);
+ }
+}
+
+//! \param name Name of the option to query.
+//!
+//! \return True if the option is locked, false if unlocked or not present.
+//!
+bool OptionDictionary::isOptionLocked(const std::string & name) const
+{
+ option_map_t::const_iterator it = m_options.find(name);
+ if (it != m_options.end())
+ {
+ return it->second.m_isLocked;
+ }
+
+ return false;
+}
+
+//! \param name Name of the option to lock.
+//!
+void OptionDictionary::lockOption(const std::string & name)
+{
+ if (!hasOption(name))
+ {
+ m_options[name].m_value = 0;
+ }
+
+ m_options[name].m_isLocked = true;
+}
+
+//! \param name Name of the option to unlock.
+//!
+void OptionDictionary::unlockOption(const std::string & name)
+{
+ if (!hasOption(name))
+ {
+ m_options[name].m_value = 0;
+ }
+
+ m_options[name].m_isLocked = false;
+}
+
+
+//! Simply calls getOption().
+//!
+const Value * OptionDictionary::operator [] (const std::string & name) const
+{
+ return getOption(name);
+}
+
diff --git a/common/OptionDictionary.h b/common/OptionDictionary.h
new file mode 100644
index 0000000..275bd01
--- /dev/null
+++ b/common/OptionDictionary.h
@@ -0,0 +1,107 @@
+/*
+ * File: OptionDictionary.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_OptionDictionary_h_)
+#define _OptionDictionary_h_
+
+#include "OptionContext.h"
+#include <map>
+
+namespace elftosb
+{
+
+/*!
+ * \brief Concrete implementation of OptionContext.
+ *
+ * This context subclass supports having a parent context. If an option is not
+ * found in the receiving instance, the request is passed to the parent.
+ * The hasOption() and getOption() methods will ask up the parent chain
+ * if the requested option does not exist in the receiving instance.
+ * But the setOption() and deleteOption() methods only operate locally,
+ * on the instance on which they were called. This allows a caller to
+ * locally override an option value without affecting any of the parent
+ * contexts.
+ */
+class OptionDictionary : public OptionContext
+{
+public:
+ //! \brief Default constructor.
+ OptionDictionary() : m_parent(0) {}
+
+ //! \brief Constructor taking a parent context.
+ OptionDictionary(OptionContext * parent) : m_parent(parent) {}
+
+ //! \brief Destructor.
+ ~OptionDictionary();
+
+ //! \name Parents
+ //@{
+ //! \brief Returns the current parent context.
+ //! \return The current parent context instance.
+ //! \retval NULL No parent has been set.
+ inline OptionContext * getParent() const { return m_parent; }
+
+ //! \brief Change the parent context.
+ //! \param newParent The parent context object. May be NULL, in which case
+ //! the object will no longer have a parent context.
+ inline void setParent(OptionContext * newParent) { m_parent = newParent; }
+ //@}
+
+ //! \name Options
+ //@{
+ //! \brief Detemine whether the named option is present in the table.
+ virtual bool hasOption(const std::string & name) const;
+
+ //! \brief Returns the option's value.
+ virtual const Value * getOption(const std::string & name) const;
+
+ //! \brief Adds or changes an option's value.
+ virtual void setOption(const std::string & name, Value * value);
+
+ //! \brief Removes an option from the table.
+ virtual void deleteOption(const std::string & name);
+ //@}
+
+ //! \name Locking
+ //@{
+ //! \brief Returns true if the specified option is locked from further changes.
+ bool isOptionLocked(const std::string & name) const;
+
+ //! \brief Prevent further modifications of an option's value.
+ void lockOption(const std::string & name);
+
+ //! \brief Allow an option to be changed.
+ void unlockOption(const std::string & name);
+ //@}
+
+ //! \name Operators
+ //@{
+ //! \brief Indexing operator; returns the value for the option \a name.
+ const Value * operator [] (const std::string & name) const;
+ //@}
+
+protected:
+ OptionContext * m_parent; //!< Our parent context.
+
+ /*!
+ * \brief Information about one option's value.
+ */
+ struct OptionValue
+ {
+ Value * m_value; //!< The object for this option's value.
+ bool m_isLocked; //!< True if this value is locked from further changes.
+
+ //! \brief Constructor.
+ OptionValue() : m_value(0), m_isLocked(false) {}
+ };
+
+ typedef std::map<std::string, OptionValue> option_map_t; //!< Map from option name to value.
+ option_map_t m_options; //!< The option dictionary.
+};
+
+}; // namespace elftosb
+
+#endif // _OptionDictionary_h_
diff --git a/common/OutputSection.cpp b/common/OutputSection.cpp
new file mode 100644
index 0000000..a6cb622
--- /dev/null
+++ b/common/OutputSection.cpp
@@ -0,0 +1,9 @@
+/*
+ * File: OutputSection.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "OutputSection.h"
+
diff --git a/common/OutputSection.h b/common/OutputSection.h
new file mode 100644
index 0000000..702a52b
--- /dev/null
+++ b/common/OutputSection.h
@@ -0,0 +1,72 @@
+/*
+ * File: OutputSection.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_OutputSection_h_)
+#define _OutputSection_h_
+
+#include "Operation.h"
+#include "smart_ptr.h"
+#include "Blob.h"
+#include "OptionContext.h"
+
+namespace elftosb
+{
+
+/*!
+ * @brief Base class for data model of sections of the output file.
+ */
+class OutputSection
+{
+public:
+ OutputSection() : m_id(0), m_options(0) {}
+ OutputSection(uint32_t identifier) : m_id(identifier), m_options(0) {}
+ virtual ~OutputSection() {}
+
+ void setIdentifier(uint32_t identifier) { m_id = identifier; }
+ uint32_t getIdentifier() const { return m_id; }
+
+ //! \brief Set the option context.
+ //!
+ //! The output section object will assume ownership of the option context
+ //! and delete it when the section is deleted.
+ inline void setOptions(OptionContext * context) { m_options = context; }
+
+ //! \brief Return the option context.
+ inline const OptionContext * getOptions() const { return m_options; }
+
+protected:
+ uint32_t m_id; //!< Unique identifier.
+ smart_ptr<OptionContext> m_options; //!< Options associated with just this section.
+};
+
+/*!
+ * @brief A section of the output that contains boot operations.
+ */
+class OperationSequenceSection : public OutputSection
+{
+public:
+ OperationSequenceSection() : OutputSection() {}
+ OperationSequenceSection(uint32_t identifier) : OutputSection(identifier) {}
+
+ OperationSequence & getSequence() { return m_sequence; }
+
+protected:
+ OperationSequence m_sequence;
+};
+
+/*!
+ * @brief A section of the output file that contains arbitrary binary data.
+ */
+class BinaryDataSection : public OutputSection, public Blob
+{
+public:
+ BinaryDataSection() : OutputSection(), Blob() {}
+ BinaryDataSection(uint32_t identifier) : OutputSection(identifier), Blob() {}
+};
+
+}; // namespace elftosb
+
+#endif // _OutputSection_h_
diff --git a/common/Random.cpp b/common/Random.cpp
new file mode 100644
index 0000000..e9785aa
--- /dev/null
+++ b/common/Random.cpp
@@ -0,0 +1,85 @@
+/*
+ * File: Random.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Random.h"
+#include <stdexcept>
+
+#ifdef WIN32
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0400
+ #endif
+ #include <windows.h>
+ #include <wincrypt.h>
+#else // WIN32
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+#endif // WIN32
+
+
+
+#ifdef WIN32
+
+MicrosoftCryptoProvider::MicrosoftCryptoProvider()
+{
+ if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ throw std::runtime_error("CryptAcquireContext");
+ }
+}
+
+MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
+{
+ CryptReleaseContext(m_hProvider, 0);
+}
+
+#endif // WIN32
+
+RandomNumberGenerator::RandomNumberGenerator()
+{
+#ifndef WIN32
+ m_fd = open("/dev/urandom",O_RDONLY);
+ if (m_fd == -1)
+ {
+ throw std::runtime_error("open /dev/urandom");
+ }
+#endif // WIN32
+}
+
+RandomNumberGenerator::~RandomNumberGenerator()
+{
+#ifndef WIN32
+ close(m_fd);
+#endif // WIN32
+}
+
+uint8_t RandomNumberGenerator::generateByte()
+{
+ uint8_t result;
+ generateBlock(&result, 1);
+ return result;
+}
+
+void RandomNumberGenerator::generateBlock(uint8_t * output, unsigned count)
+{
+#ifdef WIN32
+# ifdef WORKAROUND_MS_BUG_Q258000
+ static MicrosoftCryptoProvider m_provider;
+# endif
+ if (!CryptGenRandom(m_provider.GetProviderHandle(), count, output))
+ {
+ throw std::runtime_error("CryptGenRandom");
+ }
+#else // WIN32
+ if (read(m_fd, output, count) != count)
+ {
+ throw std::runtime_error("read /dev/urandom");
+ }
+#endif // WIN32
+}
+
+
diff --git a/common/Random.h b/common/Random.h
new file mode 100644
index 0000000..5aac6ab
--- /dev/null
+++ b/common/Random.h
@@ -0,0 +1,57 @@
+/*
+ * File: Random.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Random_h_)
+#define _Random_h_
+
+#include "stdafx.h"
+
+#ifdef WIN32
+/*!
+ * This class is from the crypto++ library.
+ */
+class MicrosoftCryptoProvider
+{
+public:
+ MicrosoftCryptoProvider();
+ ~MicrosoftCryptoProvider();
+#if defined(_WIN64)
+ typedef unsigned __int64 ProviderHandle; // type HCRYPTPROV, avoid #include <windows.h>
+#else
+ typedef unsigned long ProviderHandle;
+#endif
+ ProviderHandle GetProviderHandle() const {return m_hProvider;}
+private:
+ ProviderHandle m_hProvider;
+};
+
+#pragma comment(lib, "advapi32.lib")
+#endif // WIN32
+
+/*!
+ * Encapsulates the Windows CryptoAPI's CryptGenRandom or /dev/urandom on Unix systems.
+ */
+class RandomNumberGenerator
+{
+public:
+ RandomNumberGenerator();
+ ~RandomNumberGenerator();
+
+ uint8_t generateByte();
+ void generateBlock(uint8_t * output, unsigned count);
+
+protected:
+#ifdef WIN32
+# ifndef WORKAROUND_MS_BUG_Q258000
+ MicrosoftCryptoProvider m_provider;
+# endif
+#else // WIN32
+ int m_fd;
+#endif // WIN32
+};
+
+
+#endif // _Random_h_
diff --git a/common/RijndaelCBCMAC.cpp b/common/RijndaelCBCMAC.cpp
new file mode 100644
index 0000000..fad0339
--- /dev/null
+++ b/common/RijndaelCBCMAC.cpp
@@ -0,0 +1,86 @@
+/*
+ * File: RijndaelCBCMAC.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "RijndaelCBCMAC.h"
+#include "rijndael.h"
+#include <assert.h>
+#include "Logging.h"
+
+void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count);
+
+//! \param key The key to use as the CBC-MAC secret.
+//! \param iv Initialization vector. Defaults to zero if not provided.
+RijndaelCBCMAC::RijndaelCBCMAC(const AESKey<128> & key, const uint8_t * iv)
+: m_key(key)
+{
+ if (iv)
+ {
+ memcpy(m_mac, iv, sizeof(m_mac));
+ }
+ else
+ {
+ memset(m_mac, 0, sizeof(m_mac));
+ }
+}
+
+//! \param data Pointer to data to process.
+//! \param length Number of bytes to process. Must be evenly divisible by #BLOCK_SIZE.
+void RijndaelCBCMAC::update(const uint8_t * data, unsigned length)
+{
+ assert(length % BLOCK_SIZE == 0);
+ unsigned blocks = length / BLOCK_SIZE;
+ while (blocks--)
+ {
+ updateOneBlock(data);
+ data += BLOCK_SIZE;
+ }
+}
+
+//! It appears that some forms of CBC-MAC encrypt the final output block again in
+//! order to protect against a plaintext attack. This method is a placeholder for
+//! such an operation, but it currently does nothing.
+void RijndaelCBCMAC::finalize()
+{
+}
+
+//! On entry the current value of m_mac becomes the initialization vector
+//! for the CBC encryption of this block. The output of the encryption then
+//! becomes the new MAC, which is stored in m_mac.
+void RijndaelCBCMAC::updateOneBlock(const uint8_t * data)
+{
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes, m_mac);
+ cipher.blockEncrypt(data, BLOCK_SIZE * 8, m_mac); // size is in bits
+
+// Log::log(Logger::DEBUG2, "CBC-MAC output block:\n");
+// logHexArray(Logger::DEBUG2, (const uint8_t *)&m_mac, sizeof(m_mac));
+}
+
+/*!
+ * \brief Log an array of bytes as hex.
+ */
+void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count)
+{
+ Log::SetOutputLevel leveler(level);
+// Log::log(" ");
+ unsigned i;
+ for (i = 0; i < count; ++i, ++bytes)
+ {
+ if ((i % 16 == 0) && (i < count - 1))
+ {
+ if (i != 0)
+ {
+ Log::log("\n");
+ }
+ Log::log(" 0x%04x: ", i);
+ }
+ Log::log("%02x ", *bytes & 0xff);
+ }
+
+ Log::log("\n");
+}
+
diff --git a/common/RijndaelCBCMAC.h b/common/RijndaelCBCMAC.h
new file mode 100644
index 0000000..97e1f47
--- /dev/null
+++ b/common/RijndaelCBCMAC.h
@@ -0,0 +1,62 @@
+/*
+ * File: RijndaelCBCMAC.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_RijndaelCBCMAC_h_)
+#define _RijndaelCBCMAC_h_
+
+#include "AESKey.h"
+#include <string.h>
+
+/*!
+ * \brief Class to compute CBC-MAC using the AES/Rijndael cipher.
+ *
+ * Currently only supports 128-bit keys and block sizes.
+ */
+class RijndaelCBCMAC
+{
+public:
+ enum
+ {
+ BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
+ };
+
+ //! The cipher block data type.
+ typedef uint8_t block_t[BLOCK_SIZE];
+
+public:
+ //! \brief Default constructor.
+ //!
+ //! The key and IV are both set to zero.
+ RijndaelCBCMAC() {}
+
+ //! \brief Constructor.
+ RijndaelCBCMAC(const AESKey<128> & key, const uint8_t * iv=0);
+
+ //! \brief Process data.
+ void update(const uint8_t * data, unsigned length);
+
+ //! \brief Signal that all data has been processed.
+ void finalize();
+
+ //! \brief Returns a reference to the current MAC value.
+ const block_t & getMAC() const { return m_mac; }
+
+ //! \brief Assignment operator.
+ RijndaelCBCMAC & operator = (const RijndaelCBCMAC & other)
+ {
+ m_key = other.m_key;
+ memcpy(m_mac, other.m_mac, sizeof(m_mac));
+ return *this;
+ }
+
+protected:
+ AESKey<128> m_key; //!< 128-bit key to use for the CBC-MAC.
+ block_t m_mac; //!< Current message authentication code value.
+
+ void updateOneBlock(const uint8_t * data);
+};
+
+#endif // _RijndaelCBCMAC_h_
diff --git a/common/SHA1.cpp b/common/SHA1.cpp
new file mode 100644
index 0000000..93b9a99
--- /dev/null
+++ b/common/SHA1.cpp
@@ -0,0 +1,274 @@
+/*
+ 100% free public domain implementation of the SHA-1 algorithm
+ by Dominik Reichl <dominik.reichl@t-online.de>
+ Web: http://www.dominik-reichl.de/
+
+ Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
+ - You can set the endianness in your files, no need to modify the
+ header file of the CSHA1 class any more
+ - Aligned data support
+ - Made support/compilation of the utility functions (ReportHash
+ and HashFile) optional (useful, if bytes count, for example in
+ embedded environments)
+
+ Version 1.5 - 2005-01-01
+ - 64-bit compiler compatibility added
+ - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
+ - Removed unnecessary variable initializations
+ - ROL32 improvement for the Microsoft compiler (using _rotl)
+
+ ======== Test Vectors (from FIPS PUB 180-1) ========
+
+ SHA1("abc") =
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+
+ SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+
+ SHA1(A million repetitions of "a") =
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include "SHA1.h"
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+#define SHA1_MAX_FILE_BUFFER 8000
+#endif
+
+// Rotate x bits to the left
+#ifndef ROL32
+#ifdef _MSC_VER
+#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
+#else
+#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
+#endif
+#endif
+
+#ifdef SHA1_LITTLE_ENDIAN
+#define SHABLK0(i) (m_block->l[i] = \
+ (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
+#else
+#define SHABLK0(i) (m_block->l[i])
+#endif
+
+#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
+ ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
+
+// SHA-1 rounds
+#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
+#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
+#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
+#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
+#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
+
+CSHA1::CSHA1()
+{
+ m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
+
+ Reset();
+}
+
+CSHA1::~CSHA1()
+{
+ Reset();
+}
+
+void CSHA1::Reset()
+{
+ // SHA1 initialization constants
+ m_state[0] = 0x67452301;
+ m_state[1] = 0xEFCDAB89;
+ m_state[2] = 0x98BADCFE;
+ m_state[3] = 0x10325476;
+ m_state[4] = 0xC3D2E1F0;
+
+ m_count[0] = 0;
+ m_count[1] = 0;
+}
+
+void CSHA1::Transform(uint32_t *state, const uint8_t *buffer)
+{
+ // Copy state[] to working vars
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
+
+ memcpy(m_block, buffer, 64);
+
+ // 4 rounds of 20 operations each. Loop unrolled.
+ _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
+ _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
+ _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
+ _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
+ _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
+ _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
+ _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
+ _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
+ _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
+ _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
+ _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
+ _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
+ _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
+ _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
+ _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
+ _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
+ _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
+ _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
+ _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
+ _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
+
+ // Add the working vars back into state
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ // Wipe variables
+#ifdef SHA1_WIPE_VARIABLES
+ a = b = c = d = e = 0;
+#endif
+}
+
+// Use this function to hash in binary data and strings
+void CSHA1::Update(const uint8_t *data, uint32_t len)
+{
+ uint32_t i, j;
+
+ j = (m_count[0] >> 3) & 63;
+
+ if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
+
+ m_count[1] += (len >> 29);
+
+ if((j + len) > 63)
+ {
+ i = 64 - j;
+ memcpy(&m_buffer[j], data, i);
+ Transform(m_state, m_buffer);
+
+ for( ; i + 63 < len; i += 64) Transform(m_state, &data[i]);
+
+ j = 0;
+ }
+ else i = 0;
+
+ memcpy(&m_buffer[j], &data[i], len - i);
+}
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+// Hash in file contents
+bool CSHA1::HashFile(char *szFileName)
+{
+ unsigned long ulFileSize, ulRest, ulBlocks;
+ unsigned long i;
+ uint8_t uData[SHA1_MAX_FILE_BUFFER];
+ FILE *fIn;
+
+ if(szFileName == NULL) return false;
+
+ fIn = fopen(szFileName, "rb");
+ if(fIn == NULL) return false;
+
+ fseek(fIn, 0, SEEK_END);
+ ulFileSize = (unsigned long)ftell(fIn);
+ fseek(fIn, 0, SEEK_SET);
+
+ if(ulFileSize != 0)
+ {
+ ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
+ ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
+ }
+ else
+ {
+ ulBlocks = 0;
+ ulRest = 0;
+ }
+
+ for(i = 0; i < ulBlocks; i++)
+ {
+ fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
+ Update((uint8_t *)uData, SHA1_MAX_FILE_BUFFER);
+ }
+
+ if(ulRest != 0)
+ {
+ fread(uData, 1, ulRest, fIn);
+ Update((uint8_t *)uData, ulRest);
+ }
+
+ fclose(fIn); fIn = NULL;
+ return true;
+}
+#endif
+
+void CSHA1::Final()
+{
+ uint32_t i;
+ uint8_t finalcount[8];
+
+ for(i = 0; i < 8; i++)
+ finalcount[i] = (uint8_t)((m_count[((i >= 4) ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
+
+ Update((uint8_t *)"\200", 1);
+
+ while ((m_count[0] & 504) != 448)
+ Update((uint8_t *)"\0", 1);
+
+ Update(finalcount, 8); // Cause a SHA1Transform()
+
+ for(i = 0; i < 20; i++)
+ {
+ m_digest[i] = (uint8_t)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
+ }
+
+ // Wipe variables for security reasons
+#ifdef SHA1_WIPE_VARIABLES
+ i = 0;
+ memset(m_buffer, 0, 64);
+ memset(m_state, 0, 20);
+ memset(m_count, 0, 8);
+ memset(finalcount, 0, 8);
+ Transform(m_state, m_buffer);
+#endif
+}
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+// Get the final hash as a pre-formatted string
+void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
+{
+ unsigned char i;
+ char szTemp[16];
+
+ if(szReport == NULL) return;
+
+ if(uReportType == REPORT_HEX)
+ {
+ sprintf(szTemp, "%02X", m_digest[0]);
+ strcat(szReport, szTemp);
+
+ for(i = 1; i < 20; i++)
+ {
+ sprintf(szTemp, " %02X", m_digest[i]);
+ strcat(szReport, szTemp);
+ }
+ }
+ else if(uReportType == REPORT_DIGIT)
+ {
+ sprintf(szTemp, "%u", m_digest[0]);
+ strcat(szReport, szTemp);
+
+ for(i = 1; i < 20; i++)
+ {
+ sprintf(szTemp, " %u", m_digest[i]);
+ strcat(szReport, szTemp);
+ }
+ }
+ else strcpy(szReport, "Error: Unknown report type!");
+}
+#endif
+
+// Get the raw message digest
+void CSHA1::GetHash(uint8_t *puDest)
+{
+ memcpy(puDest, m_digest, 20);
+}
diff --git a/common/SHA1.h b/common/SHA1.h
new file mode 100644
index 0000000..114ece4
--- /dev/null
+++ b/common/SHA1.h
@@ -0,0 +1,149 @@
+/*
+ 100% free public domain implementation of the SHA-1 algorithm
+ by Dominik Reichl <dominik.reichl@t-online.de>
+ Web: http://www.dominik-reichl.de/
+
+ Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
+ - You can set the endianness in your files, no need to modify the
+ header file of the CSHA1 class any more
+ - Aligned data support
+ - Made support/compilation of the utility functions (ReportHash
+ and HashFile) optional (useful, if bytes count, for example in
+ embedded environments)
+
+ Version 1.5 - 2005-01-01
+ - 64-bit compiler compatibility added
+ - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
+ - Removed unnecessary variable initializations
+ - ROL32 improvement for the Microsoft compiler (using _rotl)
+
+ ======== Test Vectors (from FIPS PUB 180-1) ========
+
+ SHA1("abc") =
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+
+ SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+
+ SHA1(A million repetitions of "a") =
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#ifndef ___SHA1_HDR___
+#define ___SHA1_HDR___
+
+#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
+#define SHA1_UTILITY_FUNCTIONS
+#endif
+
+#include <memory.h> // Needed for memset and memcpy
+#include "stdafx.h"
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+#include <stdio.h> // Needed for file access and sprintf
+#include <string.h> // Needed for strcat and strcpy
+#endif
+
+#ifdef _MSC_VER
+#include <stdlib.h>
+#endif
+
+// You can define the endian mode in your files, without modifying the SHA1
+// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
+// in your files, before including the SHA1.h header file. If you don't
+// define anything, the class defaults to little endian.
+
+#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
+#define SHA1_LITTLE_ENDIAN
+#endif
+
+// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
+// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
+// defaults to wiping.
+
+#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
+#define SHA1_WIPE_VARIABLES
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Define 8- and 32-bit variables
+
+//#ifndef uint32_t
+//
+//#ifdef _MSC_VER
+//
+//#define uint8_t unsigned __int8
+//#define uint32_t unsigned __int32
+//
+//#else
+//
+//#define uint8_t unsigned char
+//
+//#if (ULONG_MAX == 0xFFFFFFFF)
+//#define uint32_t unsigned long
+//#else
+//#define uint32_t unsigned int
+//#endif
+//
+//#endif
+//#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Declare SHA1 workspace
+
+typedef union
+{
+ uint8_t c[64];
+ uint32_t l[16];
+} SHA1_WORKSPACE_BLOCK;
+
+class CSHA1
+{
+public:
+#ifdef SHA1_UTILITY_FUNCTIONS
+ // Two different formats for ReportHash(...)
+ enum
+ {
+ REPORT_HEX = 0,
+ REPORT_DIGIT = 1
+ };
+#endif
+
+ // Constructor and Destructor
+ CSHA1();
+ ~CSHA1();
+
+ uint32_t m_state[5];
+ uint32_t m_count[2];
+ uint32_t __reserved1[1];
+ uint8_t m_buffer[64];
+ uint8_t m_digest[20];
+ uint32_t __reserved2[3];
+
+ void Reset();
+
+ // Update the hash value
+ void Update(const uint8_t *data, uint32_t len);
+#ifdef SHA1_UTILITY_FUNCTIONS
+ bool HashFile(char *szFileName);
+#endif
+
+ // Finalize hash and report
+ void Final();
+
+ // Report functions: as pre-formatted and raw data
+#ifdef SHA1_UTILITY_FUNCTIONS
+ void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
+#endif
+ void GetHash(uint8_t *puDest);
+
+private:
+ // Private SHA-1 transformation
+ void Transform(uint32_t *state, const uint8_t *buffer);
+
+ // Member variables
+ uint8_t m_workspace[64];
+ SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
+};
+
+#endif
diff --git a/common/SRecordSourceFile.cpp b/common/SRecordSourceFile.cpp
new file mode 100644
index 0000000..3521c69
--- /dev/null
+++ b/common/SRecordSourceFile.cpp
@@ -0,0 +1,176 @@
+/*
+ * File: SRecordSourceFile.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "SRecordSourceFile.h"
+#include "Logging.h"
+#include "smart_ptr.h"
+#include <assert.h>
+#include <string.h>
+enum
+{
+ //! Size in bytes of the buffer used to collect S-record data records
+ //! before adding them to the executable image. Currently 64KB.
+ COLLECTION_BUFFER_SIZE = 64 * 1024
+};
+
+using namespace elftosb;
+
+SRecordSourceFile::SRecordSourceFile(const std::string & path)
+: SourceFile(path), m_image(0), m_hasEntryRecord(false)
+{
+}
+
+bool SRecordSourceFile::isSRecordFile(std::istream & stream)
+{
+ StSRecordFile srec(stream);
+ return srec.isSRecordFile();
+}
+
+void SRecordSourceFile::open()
+{
+ SourceFile::open();
+
+ // create file parser and examine file
+ m_file = new StSRecordFile(*m_stream);
+ m_file->parse();
+
+ // build an image of the file
+ m_image = new StExecutableImage();
+ buildMemoryImage();
+
+ // dispose of file parser object
+ delete m_file;
+ m_file = 0;
+}
+
+void SRecordSourceFile::close()
+{
+ assert(m_image);
+
+ SourceFile::close();
+
+ // dispose of memory image
+ delete m_image;
+ m_image = 0;
+}
+
+//! \pre The file must be open before this method can be called.
+//!
+DataSource * SRecordSourceFile::createDataSource()
+{
+ assert(m_image);
+ return new MemoryImageDataSource(m_image);
+}
+
+//! \retval true The file has an S7, S8, or S9 record.
+//! \retval false No entry point is available.
+bool SRecordSourceFile::hasEntryPoint()
+{
+ return m_hasEntryRecord;
+}
+
+//! If no entry point is available then 0 is returned instead. The method scans
+//! the records in the file looking for S7, S8, or S9 records. Thus, 16-bit,
+//! 24-bit, and 32-bit entry point records are supported.
+//!
+//! \return Entry point address.
+//! \retval 0 No entry point is available.
+uint32_t SRecordSourceFile::getEntryPointAddress()
+{
+ if (m_hasEntryRecord)
+ {
+ // the address in the record is the entry point
+ Log::log(Logger::DEBUG2, "entry point address is 0x%08x\n", m_entryRecord.m_address);
+ return m_entryRecord.m_address;
+ }
+
+ return 0;
+}
+
+//! Scans the S-records of the file looking for data records. These are S3, S2, or
+//! S1 records. The contents of these records are added to an StExecutableImage
+//! object, which coalesces the individual records into contiguous regions of
+//! memory.
+//!
+//! Also looks for S7, S8, or S9 records that contain the entry point. The first
+//! match of one of these records is saved off into the #m_entryRecord member.
+//!
+//! \pre The #m_file member must be valid.
+//! \pre The #m_image member variable must have been instantiated.
+void SRecordSourceFile::buildMemoryImage()
+{
+ assert(m_file);
+ assert(m_image);
+
+ // Clear the entry point related members.
+ m_hasEntryRecord = false;
+ memset(&m_entryRecord, 0, sizeof(m_entryRecord));
+
+ // Allocate buffer to hold data before adding it to the executable image.
+ // Contiguous records are added to this buffer. When overflowed or when a
+ // non-contiguous record is encountered the buffer is added to the executable
+ // image where it will be coalesced further. We don't add records individually
+ // to the image because coalescing record by record is very slow.
+ smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE];
+ unsigned startAddress;
+ unsigned nextAddress;
+ unsigned dataLength = 0;
+
+ // process SRecords
+ StSRecordFile::const_iterator it = m_file->getBegin();
+ for (; it != m_file->getEnd(); it++)
+ {
+ const StSRecordFile::SRecord & theRecord = *it;
+
+ // only handle S3,2,1 records
+ bool isDataRecord = theRecord.m_type == 3 || theRecord.m_type == 2 || theRecord.m_type == 1;
+ bool hasData = theRecord.m_data && theRecord.m_dataCount;
+ if (isDataRecord && hasData)
+ {
+ // If this record's data would overflow the collection buffer, or if the
+ // record is not contiguous with the rest of the data in the collection
+ // buffer, then flush the buffer to the executable image and restart.
+ if (dataLength && ((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress)))
+ {
+ m_image->addTextRegion(startAddress, buffer, dataLength);
+
+ dataLength = 0;
+ }
+
+ // Capture addresses when starting an empty buffer.
+ if (dataLength == 0)
+ {
+ startAddress = theRecord.m_address;
+ nextAddress = startAddress;
+ }
+
+ // Copy record data into place in the collection buffer and update
+ // size and address.
+ memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
+ dataLength += theRecord.m_dataCount;
+ nextAddress += theRecord.m_dataCount;
+ }
+ else if (!m_hasEntryRecord)
+ {
+ // look for S7,8,9 records
+ bool isEntryPointRecord = theRecord.m_type == 7 || theRecord.m_type == 8 || theRecord.m_type == 9;
+ if (isEntryPointRecord)
+ {
+ // save off the entry point record so we don't have to scan again
+ memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord));
+ m_hasEntryRecord = true;
+ }
+ }
+ }
+
+ // Add any leftover data in the collection buffer to the executable image.
+ if (dataLength)
+ {
+ m_image->addTextRegion(startAddress, buffer, dataLength);
+ }
+}
+
diff --git a/common/SRecordSourceFile.h b/common/SRecordSourceFile.h
new file mode 100644
index 0000000..c0bc2a9
--- /dev/null
+++ b/common/SRecordSourceFile.h
@@ -0,0 +1,83 @@
+/*
+ * File: SRecordSourceFile.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_SRecordSourceFile_h_)
+#define _SRecordSourceFile_h_
+
+#include "SourceFile.h"
+#include "StSRecordFile.h"
+#include "StExecutableImage.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Executable file in the Motorola S-record format.
+ *
+ * Instead of presenting each S-record in the file separately, this class
+ * builds up a memory image of all of the records. Records next to each other
+ * in memory are coalesced into a single memory region. The data source that
+ * is returned from createDataSource() exposes these regions as its segments.
+ *
+ * Because the S-record format does not support the concepts, no support is
+ * provided for named sections or symbols.
+ */
+class SRecordSourceFile : public SourceFile
+{
+public:
+ //! \brief Default constructor.
+ SRecordSourceFile(const std::string & path);
+
+ //! \brief Destructor.
+ virtual ~SRecordSourceFile() {}
+
+ //! \brief Test whether the \a stream contains a valid S-record file.
+ static bool isSRecordFile(std::istream & stream);
+
+ //! \name Opening and closing
+ //@{
+ //! \brief Opens the file.
+ virtual void open();
+
+ //! \brief Closes the file.
+ virtual void close();
+ //@}
+
+ //! \name Format capabilities
+ //@{
+ virtual bool supportsNamedSections() const { return false; }
+ virtual bool supportsNamedSymbols() const { return false; }
+ //@}
+
+ //! \name Data sources
+ //@{
+ //! \brief Returns data source for the entire file.
+ virtual DataSource * createDataSource();
+ //@}
+
+ //! \name Entry point
+ //@{
+ //! \brief Returns true if an entry point was set in the file.
+ virtual bool hasEntryPoint();
+
+ //! \brief Returns the entry point address.
+ virtual uint32_t getEntryPointAddress();
+ //@}
+
+protected:
+ StSRecordFile * m_file; //!< S-record parser instance.
+ StExecutableImage * m_image; //!< Memory image of the S-record file.
+ bool m_hasEntryRecord; //!< Whether an S7,8,9 record was found.
+ StSRecordFile::SRecord m_entryRecord; //!< Record for the entry point.
+
+protected:
+ //! \brief Build memory image of the S-record file.
+ void buildMemoryImage();
+};
+
+}; // namespace elftosb
+
+#endif // _SRecordSourceFile_h_
diff --git a/common/SearchPath.cpp b/common/SearchPath.cpp
new file mode 100644
index 0000000..8a8a742
--- /dev/null
+++ b/common/SearchPath.cpp
@@ -0,0 +1,121 @@
+/*
+ * File: SearchPath.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "SearchPath.h"
+#include <stdio.h>
+
+#if defined(WIN32)
+ #define PATH_SEP_CHAR '\\'
+ #define PATH_SEP_STRING "\\"
+#else
+ #define PATH_SEP_CHAR '/'
+ #define PATH_SEP_STRING "/"
+#endif
+
+PathSearcher * PathSearcher::s_searcher = NULL;
+
+//! This function will create the global path search object if it has
+//! not already been created.
+PathSearcher & PathSearcher::getGlobalSearcher()
+{
+ if (!s_searcher)
+ {
+ s_searcher = new PathSearcher;
+ }
+
+ return *s_searcher;
+}
+
+void PathSearcher::addSearchPath(std::string & path)
+{
+ m_paths.push_back(path);
+}
+
+//! The \a base path argument can be either a relative or absolute path. If the path
+//! is relative, then it is joined with search paths one after another until a matching
+//! file is located or all search paths are exhausted. If the \a base is absolute,
+//! only that path is tested and if invalid false is returned.
+//!
+//! \param base A path to the file that is to be found.
+//! \param targetType Currently ignored. In the future it will let you select whether to
+//! find a file or directory.
+//! \param searchCwd If set to true, the current working directory is searched before using
+//! any of the search paths. Otherwise only the search paths are considered.
+//! \param[out] result When true is returned this string is set to the first path at which
+//! a valid file was found.
+//!
+//! \retval true A matching file was found among the search paths. The contents of \a result
+//! are a valid path.
+//! \retval false No match could be made. \a result has been left unmodified.
+bool PathSearcher::search(const std::string & base, target_type_t targetType, bool searchCwd, std::string & result)
+{
+ FILE * tempFile;
+ bool absolute = isAbsolute(base);
+
+ // Try cwd first if requested. Same process applies to absolute paths.
+ if (absolute || searchCwd)
+ {
+ tempFile = fopen(base.c_str(), "r");
+ if (tempFile)
+ {
+ fclose(tempFile);
+ result = base;
+ return true;
+ }
+ }
+
+ // If the base path is absolute and the previous test failed, then we don't go any further.
+ if (absolute)
+ {
+ return false;
+ }
+
+ // Iterate over all search paths.
+ string_list_t::const_iterator it = m_paths.begin();
+ for (; it != m_paths.end(); ++it)
+ {
+ std::string searchPath = joinPaths(*it, base);
+
+ tempFile = fopen(searchPath.c_str(), "r");
+ if (tempFile)
+ {
+ fclose(tempFile);
+ result = searchPath;
+ return true;
+ }
+ }
+
+ // Couldn't find anything matching the base path.
+ return false;
+}
+
+bool PathSearcher::isAbsolute(const std::string & path)
+{
+#if __WIN32__
+ return path.size() >= 3 && path[1] == ':' && path[2] == '\\';
+#else
+ return path.size() >= 1 && path[0] == '/';
+#endif
+}
+
+std::string PathSearcher::joinPaths(const std::string & first, const std::string & second)
+{
+ // Start with first string.
+ std::string result = first;
+
+ // Add path separator if needed
+ if ((first[first.size() - 1] != PATH_SEP_CHAR) && (second[0] != PATH_SEP_CHAR))
+ {
+ result += PATH_SEP_STRING;
+ }
+
+ // Append the second string.
+ result += second;
+
+ // And return the whole mess.
+ return result;
+}
diff --git a/common/SearchPath.h b/common/SearchPath.h
new file mode 100644
index 0000000..4ae6018
--- /dev/null
+++ b/common/SearchPath.h
@@ -0,0 +1,58 @@
+/*
+ * File: SearchPath.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_searchpath_h_)
+#define _searchpath_h_
+
+#include <string>
+#include <list>
+
+/*!
+ * \brief Handles searching a list of paths for a file.
+ */
+class PathSearcher
+{
+public:
+ //!
+ enum _target_type
+ {
+ kFindFile,
+ kFindDirectory
+ };
+
+ //!
+ typedef enum _target_type target_type_t;
+
+protected:
+ //! Global search object singleton.
+ static PathSearcher * s_searcher;
+
+public:
+ //! \brief Access global path searching object.
+ static PathSearcher & getGlobalSearcher();
+
+public:
+ //! \brief Constructor.
+ PathSearcher() {}
+
+ //! \brief Add a new search path to the end of the list.
+ void addSearchPath(std::string & path);
+
+ //! \brief Attempts to locate a file by using the search paths.
+ bool search(const std::string & base, target_type_t targetType, bool searchCwd, std::string & result);
+
+protected:
+ typedef std::list<std::string> string_list_t; //!< Linked list of strings.
+ string_list_t m_paths; //!< Ordered list of paths to search.
+
+ //! \brief Returns whether \a path is absolute.
+ bool isAbsolute(const std::string & path);
+
+ //! \brief Combines two paths into a single one.
+ std::string joinPaths(const std::string & first, const std::string & second);
+};
+
+#endif // _searchpath_h_
diff --git a/common/SourceFile.cpp b/common/SourceFile.cpp
new file mode 100644
index 0000000..947ae17
--- /dev/null
+++ b/common/SourceFile.cpp
@@ -0,0 +1,178 @@
+/*
+ * File: SourceFile.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "SourceFile.h"
+#include "ELFSourceFile.h"
+#include "SRecordSourceFile.h"
+#include <assert.h>
+#include "format_string.h"
+#include "SearchPath.h"
+
+using namespace elftosb;
+
+//! The supported file types are currently:
+//! - ELF files
+//! - Motorola S-record files
+//! - Binary files
+//!
+//! Any file that is not picked up by the other subclasses will result in a
+//! an instance of BinaryDataFile.
+//!
+//! \return An instance of the correct subclass of SourceFile for the given path.
+//!
+//! \exception std::runtime_error Thrown if the file cannot be opened.
+//!
+//! \see elftosb::ELFSourceFile
+//! \see elftosb::SRecordSourceFile
+//! \see elftosb::BinarySourceFile
+SourceFile * SourceFile::openFile(const std::string & path)
+{
+ // Search for file using search paths
+ std::string actualPath;
+ bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath);
+ if (!found)
+ {
+ throw std::runtime_error(format_string("unable to find file %s\n", path.c_str()));
+ }
+
+ std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (!testStream.is_open())
+ {
+ throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str()));
+ }
+
+ // catch exceptions so we can close the file stream
+ try
+ {
+ if (ELFSourceFile::isELFFile(testStream))
+ {
+ testStream.close();
+ return new ELFSourceFile(actualPath);
+ }
+ else if (SRecordSourceFile::isSRecordFile(testStream))
+ {
+ testStream.close();
+ return new SRecordSourceFile(actualPath);
+ }
+
+ // treat it as a binary file
+ testStream.close();
+ return new BinarySourceFile(actualPath);
+ }
+ catch (...)
+ {
+ testStream.close();
+ throw;
+ }
+}
+
+SourceFile::SourceFile(const std::string & path)
+: m_path(path), m_stream()
+{
+}
+
+//! The file is closed if it had been left opened.
+//!
+SourceFile::~SourceFile()
+{
+ if (isOpen())
+ {
+ m_stream->close();
+ }
+}
+
+//! \exception std::runtime_error Raised if the file could not be opened successfully.
+void SourceFile::open()
+{
+ assert(!isOpen());
+ m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (!m_stream->is_open())
+ {
+ throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str()));
+ }
+}
+
+void SourceFile::close()
+{
+ assert(isOpen());
+
+ m_stream->close();
+ m_stream.safe_delete();
+}
+
+unsigned SourceFile::getSize()
+{
+ bool wasOpen = isOpen();
+ std::ifstream::pos_type oldPosition;
+
+ if (!wasOpen)
+ {
+ open();
+ }
+
+ assert(m_stream);
+ oldPosition = m_stream->tellg();
+ m_stream->seekg(0, std::ios_base::end);
+ unsigned resultSize = m_stream->tellg();
+ m_stream->seekg(oldPosition);
+
+ if (!wasOpen)
+ {
+ close();
+ }
+
+ return resultSize;
+}
+
+//! If the file does not support named sections, or if there is not a
+//! section with the given name, this method may return NULL.
+//!
+//! This method is just a small wrapper that creates an
+//! FixedMatcher string matcher instance and uses the createDataSource()
+//! that takes a reference to a StringMatcher.
+DataSource * SourceFile::createDataSource(const std::string & section)
+{
+ FixedMatcher matcher(section);
+ return createDataSource(matcher);
+}
+
+DataTarget * SourceFile::createDataTargetForEntryPoint()
+{
+ if (!hasEntryPoint())
+ {
+ return NULL;
+ }
+
+ return new ConstantDataTarget(getEntryPointAddress());
+}
+
+DataSource * BinarySourceFile::createDataSource()
+{
+ std::istream * fileStream = getStream();
+ assert(fileStream);
+
+ // get stream size
+ fileStream->seekg(0, std::ios_base::end);
+ int length = fileStream->tellg();
+
+ // allocate buffer
+ smart_array_ptr<uint8_t> data = new uint8_t[length];
+// if (!data)
+// {
+// throw std::bad_alloc();
+// }
+
+ // read entire file into the buffer
+ fileStream->seekg(0, std::ios_base::beg);
+ if (fileStream->read((char *)data.get(), length).bad())
+ {
+ throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str()));
+ }
+
+ // create the data source. the buffer is copied, so we can dispose of it.
+ return new UnmappedDataSource(data, length);
+}
diff --git a/common/SourceFile.h b/common/SourceFile.h
new file mode 100644
index 0000000..773dd5b
--- /dev/null
+++ b/common/SourceFile.h
@@ -0,0 +1,156 @@
+/*
+ * File: SourceFile.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_SourceFile_h_)
+#define _SourceFile_h_
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "smart_ptr.h"
+#include "DataSource.h"
+#include "DataTarget.h"
+#include "StringMatcher.h"
+#include "OptionContext.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract base class for a source file containing executable code.
+ *
+ * The purpose of this class cluster is to provide a common interface for
+ * accessing the contents of different file formats. This is accomplished
+ * through several small sets of methods along with the DataSource and
+ * DataTarget classes.
+ *
+ * The primary interface for creating instances of SourceFile is the static
+ * SourceFile::openFile() function. It will create the correct subclass of
+ * SourceFile by inspecting the file to determine its type.
+ */
+class SourceFile
+{
+public:
+ // \brief Factory function that creates the correct subclass of SourceFile.
+ static SourceFile * openFile(const std::string & path);
+
+public:
+ //! \brief Default constructor.
+ SourceFile(const std::string & path);
+
+ //! \brief Destructor.
+ virtual ~SourceFile();
+
+ //! \brief Set the option context.
+ //!
+ //! The source file will take ownership of the @a context and delete it
+ //! when the source file is itself deleted.
+ inline void setOptions(OptionContext * context) { m_options = context; }
+
+ //! \brief Return the option context.
+ inline const OptionContext * getOptions() const { return m_options; }
+
+ //! \brief Returns the path to the file.
+ inline const std::string & getPath() const { return m_path; }
+
+ //! \brief Get the size in bytes of the file.
+ unsigned getSize();
+
+ //! \name Opening and closing
+ //@{
+ //! \brief Opens the file.
+ virtual void open();
+
+ //! \brief Closes the file.
+ virtual void close();
+
+ //! \brief Returns whether the file is already open.
+ virtual bool isOpen() const { return (bool)m_stream && const_cast<std::ifstream*>(m_stream.get())->is_open(); }
+ //@}
+
+ //! \name Format capabilities
+ //@{
+ virtual bool supportsNamedSections() const=0;
+ virtual bool supportsNamedSymbols() const=0;
+ //@}
+
+ //! \name Data source creation
+ //@{
+ //! \brief Creates a data source from the entire file.
+ virtual DataSource * createDataSource()=0;
+
+ //! \brief Creates a data source out of one or more sections of the file.
+ //!
+ //! The \a selector object is used to perform the section name comparison.
+ //! If the file does not support named sections, or if there is not a
+ //! section with the given name, this method may return NULL.
+ virtual DataSource * createDataSource(StringMatcher & matcher) { return NULL; }
+
+ //! \brief Creates a data source out of one section of the file.
+ virtual DataSource * createDataSource(const std::string & section);
+ //@}
+
+ //! \name Entry point
+ //@{
+ //! \brief Returns true if an entry point was set in the file.
+ virtual bool hasEntryPoint()=0;
+
+ //! \brief Returns the entry point address.
+ virtual uint32_t getEntryPointAddress() { return 0; }
+ //@}
+
+ //! \name Data target creation
+ //@{
+ virtual DataTarget * createDataTargetForSection(const std::string & section) { return NULL; }
+ virtual DataTarget * createDataTargetForSymbol(const std::string & symbol) { return NULL; }
+ virtual DataTarget * createDataTargetForEntryPoint();
+ //@}
+
+ //! \name Symbols
+ //@{
+ //! \brief Returns whether a symbol exists in the source file.
+ virtual bool hasSymbol(const std::string & name) { return false; }
+
+ //! \brief Returns the value of a symbol.
+ virtual uint32_t getSymbolValue(const std::string & name) { return 0; }
+
+ //! \brief Returns the size of a symbol.
+ virtual unsigned getSymbolSize(const std::string & name) { return 0; }
+ //@}
+
+protected:
+ std::string m_path; //!< Path to the file.
+ smart_ptr<std::ifstream> m_stream; //!< File stream, or NULL if file is closed.
+ smart_ptr<OptionContext> m_options; //!< Table of option values.
+
+ //! \brief Internal access to the input stream object.
+ inline std::ifstream * getStream() { return m_stream; }
+};
+
+/*!
+ * \brief Binary data file.
+ */
+class BinarySourceFile : public SourceFile
+{
+public:
+ //! \brief Default constructor.
+ BinarySourceFile(const std::string & path) : SourceFile(path) {}
+
+ //! \name Format capabilities
+ //@{
+ virtual bool supportsNamedSections() const { return false; }
+ virtual bool supportsNamedSymbols() const { return false; }
+ //@}
+
+ //! \brief Creates an unmapped data source from the entire file.
+ virtual DataSource * createDataSource();
+
+ virtual bool hasEntryPoint() { return false; }
+};
+
+}; // namespace elftosb
+
+#endif // _SourceFile_h_
diff --git a/common/StELFFile.cpp b/common/StELFFile.cpp
new file mode 100644
index 0000000..3b4b568
--- /dev/null
+++ b/common/StELFFile.cpp
@@ -0,0 +1,531 @@
+/*
+ * File: StELFFile.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "StELFFile.h"
+#include <ios>
+#include <stdexcept>
+#include <stdio.h>
+#include "EndianUtilities.h"
+
+//! \exception StELFFileException is thrown if there is a problem with the file format.
+//!
+StELFFile::StELFFile(std::istream & inStream)
+: m_stream(inStream)
+{
+ readFileHeaders();
+}
+
+//! Disposes of the string table data.
+StELFFile::~StELFFile()
+{
+ SectionDataMap::iterator it = m_sectionDataCache.begin();
+ for (; it != m_sectionDataCache.end(); ++it)
+ {
+ SectionDataInfo & info = it->second;
+ if (info.m_data != NULL)
+ {
+ delete [] info.m_data;
+ }
+ }
+}
+
+//! \exception StELFFileException is thrown if the file is not an ELF file.
+//!
+void StELFFile::readFileHeaders()
+{
+ // move read head to beginning of stream
+ m_stream.seekg(0, std::ios_base::beg);
+
+ // read ELF header
+ m_stream.read(reinterpret_cast<char *>(&m_header), sizeof(m_header));
+ if (m_stream.bad())
+ {
+ throw StELFFileException("could not read file header");
+ }
+
+ // convert endianness
+ m_header.e_type = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_type);
+ m_header.e_machine = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_machine);
+ m_header.e_version = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_version);
+ m_header.e_entry = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_entry);
+ m_header.e_phoff = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_phoff);
+ m_header.e_shoff = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_shoff);
+ m_header.e_flags = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_flags);
+ m_header.e_ehsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_ehsize);
+ m_header.e_phentsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_phentsize);
+ m_header.e_phnum = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_phnum);
+ m_header.e_shentsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shentsize);
+ m_header.e_shnum = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shnum);
+ m_header.e_shstrndx = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shstrndx);
+
+ // check magic number
+ if (!(m_header.e_ident[EI_MAG0] == ELFMAG0 && m_header.e_ident[EI_MAG1] == ELFMAG1 && m_header.e_ident[EI_MAG2] == ELFMAG2 && m_header.e_ident[EI_MAG3] == ELFMAG3))
+ {
+ throw StELFFileException("invalid magic number in ELF header");
+ }
+
+ try
+ {
+ int i;
+
+ // read section headers
+ if (m_header.e_shoff != 0 && m_header.e_shnum > 0)
+ {
+ Elf32_Shdr sectionHeader;
+ for (i=0; i < m_header.e_shnum; ++i)
+ {
+ m_stream.seekg(m_header.e_shoff + m_header.e_shentsize * i, std::ios::beg);
+ m_stream.read(reinterpret_cast<char *>(&sectionHeader), sizeof(sectionHeader));
+ if (m_stream.bad())
+ {
+ throw StELFFileException("could not read section header");
+ }
+
+ // convert endianness
+ sectionHeader.sh_name = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_name);
+ sectionHeader.sh_type = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_type);
+ sectionHeader.sh_flags = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_flags);
+ sectionHeader.sh_addr = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_addr);
+ sectionHeader.sh_offset = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_offset);
+ sectionHeader.sh_size = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_size);
+ sectionHeader.sh_link = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_link);
+ sectionHeader.sh_info = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_info);
+ sectionHeader.sh_addralign = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_addralign);
+ sectionHeader.sh_entsize = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_entsize);
+
+ m_sectionHeaders.push_back(sectionHeader);
+ }
+ }
+
+ // read program headers
+ if (m_header.e_phoff != 0 && m_header.e_phnum > 0)
+ {
+ Elf32_Phdr programHeader;
+ for (i=0; i < m_header.e_phnum; ++i)
+ {
+ m_stream.seekg(m_header.e_phoff + m_header.e_phentsize * i, std::ios::beg);
+ m_stream.read(reinterpret_cast<char *>(&programHeader), sizeof(programHeader));
+ if (m_stream.bad())
+ {
+ throw StELFFileException("could not read program header");
+ }
+
+ // convert endianness
+ programHeader.p_type = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_type);
+ programHeader.p_offset = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_type);
+ programHeader.p_vaddr = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_vaddr);
+ programHeader.p_paddr = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_paddr);
+ programHeader.p_filesz = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_filesz);
+ programHeader.p_memsz = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_memsz);
+ programHeader.p_flags = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_flags);
+ programHeader.p_align = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_align);
+
+ m_programHeaders.push_back(programHeader);
+ }
+ }
+
+ // look up symbol table section index
+ {
+ std::string symtab_section_name(SYMTAB_SECTION_NAME);
+ m_symbolTableIndex = getIndexOfSectionWithName(symtab_section_name);
+ }
+ }
+ catch (...)
+ {
+ throw StELFFileException("error reading file");
+ }
+}
+
+const Elf32_Shdr & StELFFile::getSectionAtIndex(unsigned inIndex) const
+{
+ if (inIndex > m_sectionHeaders.size())
+ throw std::invalid_argument("inIndex");
+
+ return m_sectionHeaders[inIndex];
+}
+
+//! If there is not a matching section, then #SHN_UNDEF is returned instead.
+//!
+unsigned StELFFile::getIndexOfSectionWithName(const std::string & inName)
+{
+ unsigned sectionIndex = 0;
+ const_section_iterator it = getSectionBegin();
+ for (; it != getSectionEnd(); ++it, ++sectionIndex)
+ {
+ const Elf32_Shdr & header = *it;
+ if (header.sh_name != 0)
+ {
+ std::string sectionName = getSectionNameAtIndex(header.sh_name);
+ if (inName == sectionName)
+ return sectionIndex;
+ }
+ }
+
+ // no matching section
+ return SHN_UNDEF;
+}
+
+//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
+//! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
+//! be returned instead.
+//!
+//! The data is read directly from the input stream passed into the constructor. The stream must
+//! still be open, or an exception will be thrown.
+//!
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::getSectionDataAtIndex(unsigned inIndex)
+{
+ return readSectionData(m_sectionHeaders[inIndex]);
+}
+
+//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
+//! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
+//! be returned instead.
+//!
+//! The data is read directly from the input stream passed into the constructor. The stream must
+//! still be open, or an exception will be thrown.
+//!
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::getSectionData(const_section_iterator inSection)
+{
+ return readSectionData(*inSection);
+}
+
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::readSectionData(const Elf32_Shdr & inHeader)
+{
+ // check for empty data
+ if (inHeader.sh_offset == 0 || inHeader.sh_size == 0)
+ return NULL;
+
+ uint8_t * sectionData = new uint8_t[inHeader.sh_size];
+
+ try
+ {
+ m_stream.seekg(inHeader.sh_offset, std::ios::beg);
+ m_stream.read(reinterpret_cast<char *>(sectionData), inHeader.sh_size);
+ if (m_stream.bad())
+ throw StELFFileException("could not read entire section");
+ }
+ catch (StELFFileException)
+ {
+ throw;
+ }
+ catch (...)
+ {
+ throw StELFFileException("error reading section data");
+ }
+
+ return sectionData;
+}
+
+const Elf32_Phdr & StELFFile::getSegmentAtIndex(unsigned inIndex) const
+{
+ if (inIndex > m_programHeaders.size())
+ throw std::invalid_argument("inIndex");
+
+ return m_programHeaders[inIndex];
+}
+
+//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
+//! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
+//! be returned instead.
+//!
+//! The data is read directly from the input stream passed into the constructor. The stream must
+//! still be open, or an exception will be thrown.
+//!
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::getSegmentDataAtIndex(unsigned inIndex)
+{
+ return readSegmentData(m_programHeaders[inIndex]);
+}
+
+//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
+//! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
+//! be returned instead.
+//!
+//! The data is read directly from the input stream passed into the constructor. The stream must
+//! still be open, or an exception will be thrown.
+//!
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::getSegmentData(const_segment_iterator inSegment)
+{
+ return readSegmentData(*inSegment);
+}
+
+//! \exception StELFFileException is thrown if an error occurs while reading the file.
+//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
+uint8_t * StELFFile::readSegmentData(const Elf32_Phdr & inHeader)
+{
+ // check for empty data
+ if (inHeader.p_offset == 0 || inHeader.p_filesz== 0)
+ return NULL;
+
+ uint8_t * segmentData = new uint8_t[inHeader.p_filesz];
+
+ try
+ {
+ m_stream.seekg(inHeader.p_offset, std::ios::beg);
+ m_stream.read(reinterpret_cast<char *>(segmentData), inHeader.p_filesz);
+ if (m_stream.bad())
+ throw StELFFileException("could not read entire segment");
+ }
+ catch (StELFFileException)
+ {
+ throw;
+ }
+ catch (...)
+ {
+ throw StELFFileException("error reading segment data");
+ }
+
+ return segmentData;
+}
+
+//! If the index is out of range, or if there is no string table in the file, then
+//! an empty string will be returned instead. This will also happen when the index
+//! is either 0 or the last byte in the table, since the table begins and ends with
+//! zero bytes.
+std::string StELFFile::getSectionNameAtIndex(unsigned inIndex)
+{
+ // make sure there's a section name string table
+ if (m_header.e_shstrndx == SHN_UNDEF)
+ return std::string("");
+
+ return getStringAtIndex(m_header.e_shstrndx, inIndex);
+}
+
+//! \exception std::invalid_argument is thrown if the section identified by \a
+//! inStringTableSectionIndex is not actually a string table, or if \a
+//! inStringIndex is out of range for the string table.
+std::string StELFFile::getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex)
+{
+ // check section type
+ const Elf32_Shdr & header = getSectionAtIndex(inStringTableSectionIndex);
+ if (header.sh_type != SHT_STRTAB)
+ throw std::invalid_argument("inStringTableSectionIndex");
+
+ if (inStringIndex >= header.sh_size)
+ throw std::invalid_argument("inStringTableSectionIndex");
+
+ // check cache
+ SectionDataInfo & info = getCachedSectionData(inStringTableSectionIndex);
+ return std::string(&reinterpret_cast<char *>(info.m_data)[inStringIndex]);
+}
+
+StELFFile::SectionDataInfo & StELFFile::getCachedSectionData(unsigned inSectionIndex)
+{
+ // check cache
+ SectionDataMap::iterator it = m_sectionDataCache.find(inSectionIndex);
+ if (it != m_sectionDataCache.end())
+ return it->second;
+
+ // not in cache, add it
+ const Elf32_Shdr & header = getSectionAtIndex(inSectionIndex);
+ uint8_t * data = getSectionDataAtIndex(inSectionIndex);
+
+ SectionDataInfo info;
+ info.m_data = data;
+ info.m_size = header.sh_size;
+
+ m_sectionDataCache[inSectionIndex] = info;
+ return m_sectionDataCache[inSectionIndex];
+}
+
+//! The number of entries in the symbol table is the symbol table section size
+//! divided by the size of each symbol entry (the #Elf32_Shdr::sh_entsize field of the
+//! symbol table section header).
+unsigned StELFFile::getSymbolCount()
+{
+ if (m_symbolTableIndex == SHN_UNDEF)
+ return 0;
+
+ const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
+ return header.sh_size / header.sh_entsize;
+}
+
+//! \exception std::invalid_argument is thrown if \a inIndex is out of range.]
+//!
+const Elf32_Sym & StELFFile::getSymbolAtIndex(unsigned inIndex)
+{
+ // get section data
+ const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
+ SectionDataInfo & info = getCachedSectionData(m_symbolTableIndex);
+
+ // has the symbol table been byte swapped yet?
+ if (!info.m_swapped)
+ {
+ byteSwapSymbolTable(header, info);
+ }
+
+ unsigned symbolOffset = header.sh_entsize * inIndex;
+ if (symbolOffset >= info.m_size)
+ {
+ throw std::invalid_argument("inIndex");
+ }
+
+ Elf32_Sym * symbol = reinterpret_cast<Elf32_Sym *>(&info.m_data[symbolOffset]);
+ return *symbol;
+}
+
+void StELFFile::byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info)
+{
+ unsigned symbolCount = getSymbolCount();
+ unsigned i = 0;
+ unsigned symbolOffset = 0;
+
+ for (; i < symbolCount; ++i, symbolOffset += header.sh_entsize)
+ {
+ Elf32_Sym * symbol = reinterpret_cast<Elf32_Sym *>(&info.m_data[symbolOffset]);
+ symbol->st_name = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_name);
+ symbol->st_value = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_value);
+ symbol->st_size = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_size);
+ symbol->st_shndx = ENDIAN_LITTLE_TO_HOST_U16(symbol->st_shndx);
+ }
+
+ // remember that we've byte swapped the symbols
+ info.m_swapped = true;
+}
+
+unsigned StELFFile::getSymbolNameStringTableIndex() const
+{
+ const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
+ return header.sh_link;
+}
+
+std::string StELFFile::getSymbolName(const Elf32_Sym & inSymbol)
+{
+ unsigned symbolStringTableIndex = getSymbolNameStringTableIndex();
+ return getStringAtIndex(symbolStringTableIndex, inSymbol.st_name);
+}
+
+//! Returns STN_UNDEF if it cannot find a symbol at the given \a symbolAddress.
+unsigned StELFFile::getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict)
+{
+ unsigned symbolCount = getSymbolCount();
+ unsigned symbolIndex = 0;
+ for (; symbolIndex < symbolCount; ++symbolIndex)
+ {
+ const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
+
+ // the GHS toolchain puts in STT_FUNC symbols marking the beginning and ending of each
+ // file. if the entry point happens to be at the beginning of the file, the beginning-
+ // of-file symbol will have the same value and type. fortunately, the size of these
+ // symbols is 0 (or seems to be). we also ignore symbols that start with two dots just
+ // in case.
+ if (symbol.st_value == symbolAddress && (strict && ELF32_ST_TYPE(symbol.st_info) == STT_FUNC && symbol.st_size != 0))
+ {
+ std::string symbolName = getSymbolName(symbol);
+
+ // ignore symbols that start with two dots
+ if (symbolName[0] == '.' && symbolName[1] == '.')
+ continue;
+
+ // found the symbol!
+ return symbolIndex;
+ }
+ }
+
+ return STN_UNDEF;
+}
+
+ARMSymbolType_t StELFFile::getTypeOfSymbolAtIndex(unsigned symbolIndex)
+{
+ ARMSymbolType_t symType = eARMSymbol;
+ const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
+
+ if (m_elfVariant == eGHSVariant)
+ {
+ if (symbol.st_other & STO_THUMB)
+ symType = eThumbSymbol;
+ }
+ else
+ {
+ unsigned mappingSymStart = 1;
+ unsigned mappingSymCount = getSymbolCount() - 1; // don't include first undefined symbol
+ bool mapSymsFirst = (m_header.e_flags & EF_ARM_MAPSYMSFIRST) != 0;
+ if (mapSymsFirst)
+ {
+ // first symbol '$m' is number of mapping syms
+ const Elf32_Sym & mappingSymCountSym = getSymbolAtIndex(1);
+ if (getSymbolName(mappingSymCountSym) == MAPPING_SYMBOL_COUNT_TAGSYM)
+ {
+ mappingSymCount = mappingSymCountSym.st_value;
+ mappingSymStart = 2;
+ }
+
+ }
+
+ uint32_t lastMappingSymAddress = 0;
+ unsigned mappingSymIndex = mappingSymStart;
+ for (; mappingSymIndex < mappingSymCount + mappingSymStart; ++mappingSymIndex)
+ {
+ const Elf32_Sym & mappingSym = getSymbolAtIndex(mappingSymIndex);
+ std::string mappingSymName = getSymbolName(mappingSym);
+ ARMSymbolType_t nextSymType = eUnknownSymbol;
+
+ if (mappingSymName == ARM_SEQUENCE_MAPSYM)
+ symType = eARMSymbol;
+ else if (mappingSymName == DATA_SEQUENCE_MAPSYM)
+ symType = eDataSymbol;
+ else if (mappingSymName == THUMB_SEQUENCE_MAPSYM)
+ symType = eThumbSymbol;
+
+ if (nextSymType != eUnknownSymbol)
+ {
+ if (symbol.st_value >= lastMappingSymAddress && symbol.st_value < mappingSym.st_value)
+ break;
+
+ symType = nextSymType;
+ lastMappingSymAddress = mappingSym.st_value;
+ }
+ }
+ }
+
+ return symType;
+}
+
+void StELFFile::dumpSections()
+{
+ unsigned count = getSectionCount();
+ unsigned i = 0;
+
+ const char * sectionTypes[12] = { "NULL", "PROGBITS", "SYMTAB", "STRTAB", "RELA", "HASH", "DYNAMIC", "NOTE", "NOBITS", "REL", "SHLIB", "DYNSYM" };
+
+ for (; i < count; ++i)
+ {
+ const Elf32_Shdr & header = getSectionAtIndex(i);
+ std::string name = getSectionNameAtIndex(header.sh_name);
+
+ printf("%s: %s, 0x%08x, 0x%08x, 0x%08x, %d, %d, %d\n", name.c_str(), sectionTypes[header.sh_type], header.sh_addr, header.sh_offset, header.sh_size, header.sh_link, header.sh_info, header.sh_entsize);
+ }
+}
+
+void StELFFile::dumpSymbolTable()
+{
+ const char * symbolTypes[5] = { "NOTYPE", "OBJECT", "FUNC", "SECTION", "FILE" };
+ const char * symbolBinding[3] = { "LOCAL", "GLOBAL", "WEAK" };
+
+ unsigned count = getSymbolCount();
+ unsigned i = 0;
+
+ for (; i < count; ++i)
+ {
+ const Elf32_Sym & symbol = getSymbolAtIndex(i);
+ std::string name = getSymbolName(symbol);
+
+ printf("'%s': %s, %s, 0x%08x, 0x%08x, %d. 0x%08x\n", name.c_str(), symbolTypes[ELF32_ST_TYPE(symbol.st_info)], symbolBinding[ELF32_ST_BIND(symbol.st_info)], symbol.st_value, symbol.st_size, symbol.st_shndx, symbol.st_other);
+ }
+}
+
+
+
diff --git a/common/StELFFile.h b/common/StELFFile.h
new file mode 100644
index 0000000..3ab9899
--- /dev/null
+++ b/common/StELFFile.h
@@ -0,0 +1,196 @@
+/*
+ * File: StELFFile.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_StELFFile_h_)
+#define _StELFFile_h_
+
+#include "stdafx.h"
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+#include <stdexcept>
+#include "ELF.h"
+
+//! Variations of the ARM ELF format.
+typedef enum {
+ eARMVariant = 1, //!< Standard ARM ELF specification.
+ eGHSVariant, //!< Green Hills Software variant.
+ eGCCVariant //!< GNU Compiler Collection variant.
+} ELFVariant_t;
+
+//! Possible ARM ELF symbol types.
+typedef enum {
+ eUnknownSymbol,
+ eARMSymbol,
+ eThumbSymbol,
+ eDataSymbol
+} ARMSymbolType_t;
+
+/*!
+ * \brief Parser for Executable and Linking Format (ELF) files.
+ *
+ * The stream passed into the constructor needs to stay open for the life
+ * of the object. This is because calls to getSectionDataAtIndex() and
+ * getSegmentDataAtIndex() read the data directly from the input stream.
+ */
+class StELFFile
+{
+public:
+ typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
+ typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
+
+public:
+ //! \brief Constructor.
+ StELFFile(std::istream & inStream);
+
+ //! \brief Destructor.
+ virtual ~StELFFile();
+
+ //! \name File format variant
+ //@{
+ //! \brief Return the ELF format variant to which this file is set.
+ virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
+
+ //! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
+ virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
+ //@}
+
+ //! \name File name
+ //@{
+ virtual void setName(const std::string & inName) { m_name = inName; }
+ virtual std::string getName() const { return m_name; }
+ //@}
+
+ //! \name ELF header
+ //@{
+ //! \brief Returns the ELF file header.
+ inline const Elf32_Ehdr & getFileHeader() const { return m_header; }
+ //@}
+
+ //! \name Sections
+ //! Methods pertaining to the object file's sections.
+ //@{
+ //! \brief Returns the number of sections in the file.
+ inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
+
+ //! \brief Returns a reference to section number \a inIndex.
+ const Elf32_Shdr & getSectionAtIndex(unsigned inIndex) const;
+
+ inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
+ inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
+
+ //! \brief Returns the index of the section with the name \a inName.
+ unsigned getIndexOfSectionWithName(const std::string & inName);
+
+ //! \brief Returns the data for the section.
+ uint8_t * getSectionDataAtIndex(unsigned inIndex);
+
+ //! \brief Returns the data for the section.
+ uint8_t * getSectionData(const_section_iterator inSection);
+ //@}
+
+ //! \name Segments
+ //! Methods for accessing the file's program headers for segments.
+ //@{
+ //! \brief Returns the number of segments, or program headers, in the file.
+ inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
+
+ //! \brief Returns a reference to the given segment.
+ const Elf32_Phdr & getSegmentAtIndex(unsigned inIndex) const;
+
+ inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
+ inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
+
+ //! \brief Returns the data of the specified segment.
+ uint8_t * getSegmentDataAtIndex(unsigned inIndex);
+
+ //! \brief Returns the data of the specified segment.
+ uint8_t * getSegmentData(const_segment_iterator inSegment);
+ //@}
+
+ //! \name String table
+ //! Methods for accessing the string tables.
+ //@{
+ //! \brief Returns a string from the file's section name string table.
+ std::string getSectionNameAtIndex(unsigned inIndex);
+
+ //! \brief Returns a string from any string table in the object file.
+ std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
+ //@}
+
+ //! \name Symbol table
+ //! Methods for accessing the object file's symbol table. Currently only
+ //! a single symbol table with the section name ".symtab" is supported.
+ //@{
+ //! \brief Returns the number of symbols in the default ".symtab" symbol table.
+ unsigned getSymbolCount();
+
+ //! \brief Returns the symbol with index \a inIndex.
+ const Elf32_Sym & getSymbolAtIndex(unsigned inIndex);
+
+ //! \brief Returns the section index of the string table containing symbol names.
+ unsigned getSymbolNameStringTableIndex() const;
+
+ //! \brief Returns the name of the symbol described by \a inSymbol.
+ std::string getSymbolName(const Elf32_Sym & inSymbol);
+
+ unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict=true);
+
+ ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
+ //@}
+
+ //! \name Debugging
+ //@{
+ void dumpSections();
+ void dumpSymbolTable();
+ //@}
+
+protected:
+ std::istream & m_stream; //!< The source stream for the ELF file.
+ ELFVariant_t m_elfVariant; //!< Variant of the ARM ELF format specification.
+ std::string m_name; //!< File name. (optional)
+ Elf32_Ehdr m_header; //!< The ELF file header.
+ std::vector<Elf32_Shdr> m_sectionHeaders; //!< All of the section headers.
+ std::vector<Elf32_Phdr> m_programHeaders; //!< All of the program headers.
+ unsigned m_symbolTableIndex; //!< Index of ".symtab" section, or #SHN_UNDEF if not present.
+
+ /*!
+ * Little structure containing information about cached section data.
+ */
+ struct SectionDataInfo
+ {
+ uint8_t * m_data; //!< Pointer to section data.
+ unsigned m_size; //!< Section data size in bytes.
+ bool m_swapped; //!< Has this section been byte swapped yet? Used for symbol table.
+ };
+ typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
+ SectionDataMap m_sectionDataCache; //!< Cached data of sections.
+
+ //! \brief Reads a section's data either from cache or from disk.
+ SectionDataInfo & getCachedSectionData(unsigned inSectionIndex);
+
+ //! \brief Reads the file, section, and program headers into memory.
+ void readFileHeaders();
+
+ uint8_t * readSectionData(const Elf32_Shdr & inHeader);
+ uint8_t * readSegmentData(const Elf32_Phdr & inHeader);
+
+ //! \brief Byte swaps the symbol table data into host endianness.
+ void byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info);
+};
+
+/*!
+ * \brief Simple exception thrown to indicate an error in the input ELF file format.
+ */
+class StELFFileException : public std::runtime_error
+{
+public:
+ //! \brief Default constructor.
+ StELFFileException(const std::string & inMessage) : std::runtime_error(inMessage) {}
+};
+
+#endif // _StELFFile_h_
diff --git a/common/StExecutableImage.cpp b/common/StExecutableImage.cpp
new file mode 100644
index 0000000..7f5eb0a
--- /dev/null
+++ b/common/StExecutableImage.cpp
@@ -0,0 +1,463 @@
+/*
+ * File: StExecutableImage.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "StExecutableImage.h"
+#include <stdexcept>
+#include <algorithm>
+#include <string.h>
+#include <stdio.h>
+
+StExecutableImage::StExecutableImage(int inAlignment)
+: m_alignment(inAlignment),
+ m_hasEntry(false),
+ m_entry(0)
+{
+}
+
+//! Makes a duplicate of each memory region.
+StExecutableImage::StExecutableImage(const StExecutableImage & inOther)
+: m_name(inOther.m_name),
+ m_alignment(inOther.m_alignment),
+ m_hasEntry(inOther.m_hasEntry),
+ m_entry(inOther.m_entry),
+ m_filters(inOther.m_filters)
+{
+ const_iterator it = inOther.getRegionBegin();
+ for (; it != inOther.getRegionEnd(); ++it)
+ {
+ const MemoryRegion & region = *it;
+
+ MemoryRegion regionCopy(region);
+ if (region.m_type == FILL_REGION && region.m_data != NULL)
+ {
+ regionCopy.m_data = new uint8_t[region.m_length];
+ memcpy(regionCopy.m_data, region.m_data, region.m_length);
+ }
+
+ m_image.push_back(regionCopy);
+ }
+}
+
+//! Disposes of memory allocated for each region.
+StExecutableImage::~StExecutableImage()
+{
+ MemoryRegionList::iterator it;
+ for (it = m_image.begin(); it != m_image.end(); ++it)
+ {
+ if (it->m_data)
+ {
+ delete [] it->m_data;
+ it->m_data = NULL;
+ }
+ }
+}
+
+//! A copy of \a inName is made, so the original may be disposed of by the caller
+//! after this method returns.
+void StExecutableImage::setName(const std::string & inName)
+{
+ m_name = inName;
+}
+
+std::string StExecutableImage::getName() const
+{
+ return m_name;
+}
+
+// The region is added with read and write flags set.
+//! \exception std::runtime_error will be thrown if the new overlaps an
+//! existing region.
+void StExecutableImage::addFillRegion(uint32_t inAddress, unsigned inLength)
+{
+ MemoryRegion region;
+ region.m_type = FILL_REGION;
+ region.m_address = inAddress;
+ region.m_data = NULL;
+ region.m_length = inLength;
+ region.m_flags = REGION_RW_FLAG;
+
+ insertOrMergeRegion(region);
+}
+
+//! A copy of \a inData is made before returning. The copy will be deleted when
+//! the executable image is destructed. Currently, the text region is created with
+//! read, write, and executable flags set.
+//! \exception std::runtime_error will be thrown if the new overlaps an
+//! existing region.
+//! \exception std::bad_alloc is thrown if memory for the copy of \a inData
+//! cannot be allocated.
+void StExecutableImage::addTextRegion(uint32_t inAddress, const uint8_t * inData, unsigned inLength)
+{
+ MemoryRegion region;
+ region.m_type = TEXT_REGION;
+ region.m_address = inAddress;
+ region.m_flags = REGION_RW_FLAG | REGION_EXEC_FLAG;
+
+ // copy the data
+ region.m_data = new uint8_t[inLength];
+ region.m_length = inLength;
+ memcpy(region.m_data, inData, inLength);
+
+ insertOrMergeRegion(region);
+}
+
+//! \exception std::out_of_range is thrown if \a inIndex is out of range.
+//!
+const StExecutableImage::MemoryRegion & StExecutableImage::getRegionAtIndex(unsigned inIndex) const
+{
+ // check bounds
+ if (inIndex >= m_image.size())
+ throw std::out_of_range("inIndex");
+
+ // find region by index
+ MemoryRegionList::const_iterator it = m_image.begin();
+ unsigned i = 0;
+ for (; it != m_image.end(); ++it, ++i)
+ {
+ if (i == inIndex)
+ break;
+ }
+ return *it;
+}
+
+//! The list of address filters is kept sorted as filters are added.
+//!
+void StExecutableImage::addAddressFilter(const AddressFilter & filter)
+{
+ m_filters.push_back(filter);
+ m_filters.sort();
+}
+
+//!
+void StExecutableImage::clearAddressFilters()
+{
+ m_filters.clear();
+}
+
+//! \exception StExecutableImage::address_filter_exception Raised when a filter
+//! with the type #ADDR_FILTER_ERROR or #ADDR_FILTER_WARNING is matched.
+//!
+//! \todo Build a list of all matching filters and then execute them at once.
+//! For the warning and error filters, a single exception should be raised
+//! that identifies all the overlapping errors. Currently the user will only
+//! see the first (lowest address) overlap.
+void StExecutableImage::applyAddressFilters()
+{
+restart_loops:
+ // Iterate over filters.
+ AddressFilterList::const_iterator fit = m_filters.begin();
+ for (; fit != m_filters.end(); ++fit)
+ {
+ const AddressFilter & filter = *fit;
+
+ // Iterator over regions.
+ MemoryRegionList::iterator rit = m_image.begin();
+ for (; rit != m_image.end(); ++rit)
+ {
+ MemoryRegion & region = *rit;
+
+ if (filter.matchesMemoryRegion(region))
+ {
+ switch (filter.m_action)
+ {
+ case ADDR_FILTER_NONE:
+ // Do nothing.
+ break;
+
+ case ADDR_FILTER_ERROR:
+ // throw error exception
+ throw address_filter_exception(true, m_name, filter);
+ break;
+
+ case ADDR_FILTER_WARNING:
+ // throw warning exception
+ throw address_filter_exception(false, m_name, filter);
+ break;
+
+ case ADDR_FILTER_CROP:
+ // Delete the offending portion of the region and restart
+ // the iteration loops.
+ cropRegionToFilter(region, filter);
+ goto restart_loops;
+ break;
+ }
+ }
+ }
+ }
+}
+
+//! There are several possible cases here:
+//! - No overlap at all. Nothing is done.
+//!
+//! - All of the memory region is matched by the \a filter. The region is
+//! removed from #StExecutableImage::m_image and its data memory freed.
+//!
+//! - The remaining portion of the region is one contiguous chunk. In this
+//! case, \a region is simply modified.
+//!
+//! - The region is split in the middle by the filter. The original \a region
+//! is modified to match the first remaining chunk. And a new #StExecutableImage::MemoryRegion
+//! instance is created to hold the other leftover piece.
+void StExecutableImage::cropRegionToFilter(MemoryRegion & region, const AddressFilter & filter)
+{
+ uint32_t firstByte = region.m_address; // first byte occupied by this region
+ uint32_t lastByte = region.endAddress(); // last used byte in this region
+
+ // compute new address range
+ uint32_t cropFrom = filter.m_fromAddress;
+ if (cropFrom < firstByte)
+ {
+ cropFrom = firstByte;
+ }
+
+ uint32_t cropTo = filter.m_toAddress;
+ if (cropTo > lastByte)
+ {
+ cropTo = lastByte;
+ }
+
+ // is there actually a match?
+ if (cropFrom > filter.m_toAddress || cropTo < filter.m_fromAddress)
+ {
+ // nothing to do, so bail
+ return;
+ }
+
+ printf("Deleting region 0x%08x-0x%08x\n", cropFrom, cropTo);
+
+ // handle if the entire region is to be deleted
+ if (cropFrom == firstByte && cropTo == lastByte)
+ {
+ delete [] region.m_data;
+ region.m_data = NULL;
+ m_image.remove(region);
+ }
+
+ // there is at least a little of the original region remaining
+ uint32_t newLength = cropTo - cropFrom + 1;
+ uint32_t leftoverLength = lastByte - cropTo;
+ uint8_t * oldData = region.m_data;
+
+ // update the region
+ region.m_address = cropFrom;
+ region.m_length = newLength;
+
+ // crop data buffer for text regions
+ if (region.m_type == TEXT_REGION && oldData)
+ {
+ region.m_data = new uint8_t[newLength];
+ memcpy(region.m_data, &oldData[cropFrom - firstByte], newLength);
+
+ // dispose of old data
+ delete [] oldData;
+ }
+
+ // create a new region for any part of the original region that was past
+ // the crop to address. this will happen if the filter range falls in the
+ // middle of the region.
+ if (leftoverLength)
+ {
+ MemoryRegion newRegion;
+ newRegion.m_type = region.m_type;
+ newRegion.m_flags = region.m_flags;
+ newRegion.m_address = cropTo + 1;
+ newRegion.m_length = leftoverLength;
+
+ if (region.m_type == TEXT_REGION && oldData)
+ {
+ newRegion.m_data = new uint8_t[leftoverLength];
+ memcpy(newRegion.m_data, &oldData[cropTo - firstByte + 1], leftoverLength);
+ }
+
+ insertOrMergeRegion(newRegion);
+ }
+}
+
+//! \exception std::runtime_error will be thrown if \a inRegion overlaps an
+//! existing region.
+//!
+//! \todo Need to investigate if we can use the STL sort algorithm at all. Even
+//! though we're doing merges too, we could sort first then examine the list
+//! for merges.
+void StExecutableImage::insertOrMergeRegion(MemoryRegion & inRegion)
+{
+ uint32_t newStart = inRegion.m_address;
+ uint32_t newEnd = newStart + inRegion.m_length;
+
+ MemoryRegionList::iterator it = m_image.begin();
+ MemoryRegionList::iterator sortedPosition = m_image.begin();
+ for (; it != m_image.end(); ++it)
+ {
+ MemoryRegion & region = *it;
+ uint32_t thisStart = region.m_address;
+ uint32_t thisEnd = thisStart + region.m_length;
+
+ // keep track of where to insert it to retain sort order
+ if (thisStart >= newEnd)
+ {
+ break;
+ }
+
+ // region types and flags must match in order to merge
+ if (region.m_type == inRegion.m_type && region.m_flags == inRegion.m_flags)
+ {
+ if (newStart == thisEnd || newEnd == thisStart)
+ {
+ mergeRegions(region, inRegion);
+ return;
+ }
+ else if ((newStart >= thisStart && newStart < thisEnd) || (newEnd >= thisStart && newEnd < thisEnd))
+ {
+ throw std::runtime_error("new region overlaps existing region");
+ }
+ }
+ }
+
+ // not merged, so just insert it in the sorted position
+ m_image.insert(it, inRegion);
+}
+
+//! Extends \a inNewRegion to include the data in \a inOldRegion. It is
+//! assumed that the two regions are compatible. The new region may come either
+//! before or after the old region in memory. Note that while the two regions
+//! don't necessarily have to be touching, it's probably a good idea. That's
+//! because any data between the regions will be set to 0.
+//!
+//! For TEXT_REGION types, the two original regions will have their data deleted
+//! during the merge. Thus, this method is not safe if any outside callers may
+//! be accessing the region's data.
+void StExecutableImage::mergeRegions(MemoryRegion & inOldRegion, MemoryRegion & inNewRegion)
+{
+ bool isOldBefore = inOldRegion.m_address < inNewRegion.m_address;
+ uint32_t oldEnd = inOldRegion.m_address + inOldRegion.m_length;
+ uint32_t newEnd = inNewRegion.m_address + inNewRegion.m_length;
+
+ switch (inOldRegion.m_type)
+ {
+ case TEXT_REGION:
+ {
+ // calculate new length
+ unsigned newLength;
+ if (isOldBefore)
+ {
+ newLength = newEnd - inOldRegion.m_address;
+ }
+ else
+ {
+ newLength = oldEnd - inNewRegion.m_address;
+ }
+
+ // alloc memory
+ uint8_t * newData = new uint8_t[newLength];
+ memset(newData, 0, newLength);
+
+ // copy data from the two regions into new block
+ if (isOldBefore)
+ {
+ memcpy(newData, inOldRegion.m_data, inOldRegion.m_length);
+ memcpy(&newData[newLength - inNewRegion.m_length], inNewRegion.m_data, inNewRegion.m_length);
+ }
+ else
+ {
+ memcpy(newData, inNewRegion.m_data, inNewRegion.m_length);
+ memcpy(&newData[newLength - inOldRegion.m_length], inOldRegion.m_data, inOldRegion.m_length);
+
+ inOldRegion.m_address = inNewRegion.m_address;
+ }
+
+ // replace old region's data
+ delete [] inOldRegion.m_data;
+ inOldRegion.m_data = newData;
+ inOldRegion.m_length = newLength;
+
+ // delete new region's data
+ delete [] inNewRegion.m_data;
+ inNewRegion.m_data = NULL;
+ break;
+ }
+
+ case FILL_REGION:
+ {
+ if (isOldBefore)
+ {
+ inOldRegion.m_length = newEnd - inOldRegion.m_address;
+ }
+ else
+ {
+ inOldRegion.m_length = oldEnd - inNewRegion.m_address;
+ inOldRegion.m_address = inNewRegion.m_address;
+ }
+ break;
+ }
+ }
+}
+
+//! Used when we remove a region from the region list by value. Because this
+//! operator compares the #m_data member, it will only return true for either an
+//! exact copy or a reference to the original.
+bool StExecutableImage::MemoryRegion::operator == (const MemoryRegion & other)
+{
+ return (m_type == other.m_type) && (m_address == other.m_address) && (m_length == other.m_length) && (m_flags == other.m_flags) && (m_data == other.m_data);
+}
+
+//! Returns true if the address filter overlaps \a region.
+bool StExecutableImage::AddressFilter::matchesMemoryRegion(const MemoryRegion & region) const
+{
+ uint32_t firstByte = region.m_address; // first byte occupied by this region
+ uint32_t lastByte = region.endAddress(); // last used byte in this region
+ return (firstByte >= m_fromAddress && firstByte <= m_toAddress) || (lastByte >= m_fromAddress && lastByte <= m_toAddress);
+}
+
+//! The comparison does \em not take the action into account. It only looks at the
+//! priority and address ranges of each filter. Priority is considered only if the two
+//! filters overlap. Lower priority filters will come after higher priority ones.
+//!
+//! \retval -1 This filter is less than filter \a b.
+//! \retval 0 This filter is equal to filter \a b.
+//! \retval 1 This filter is greater than filter \a b.
+int StExecutableImage::AddressFilter::compare(const AddressFilter & other) const
+{
+ if (m_priority != other.m_priority && ((m_fromAddress >= other.m_fromAddress && m_fromAddress <= other.m_toAddress) || (m_toAddress >= other.m_fromAddress && m_toAddress <= other.m_toAddress)))
+ {
+ // we know the priorities are not equal
+ if (m_priority > other.m_priority)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ if (m_fromAddress == other.m_fromAddress)
+ {
+ if (m_toAddress == other.m_toAddress)
+ {
+ return 0;
+ }
+ else if (m_toAddress < other.m_toAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else if (m_fromAddress < other.m_fromAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+
diff --git a/common/StExecutableImage.h b/common/StExecutableImage.h
new file mode 100644
index 0000000..edfd5f4
--- /dev/null
+++ b/common/StExecutableImage.h
@@ -0,0 +1,251 @@
+/*
+ * File: StExecutableImage.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_StExecutableImage_h_)
+#define _StExecutableImage_h_
+
+#include "stdafx.h"
+#include <list>
+
+/*!
+ * \brief Used to build a representation of memory regions.
+ *
+ * An intermediate representation of the memory regions and segments loaded
+ * from an executable file. Also used to find contiguous segments that are
+ * specified separately in the source file.
+ *
+ * When regions are added, an attempt is made to coalesce contiguous regions.
+ * In order for this to succeed, the touching regions must be of the same
+ * type and have the same permissions. Regions are also kept sorted by their
+ * address range as they are added.
+ *
+ * \todo Implement alignment support.
+ */
+class StExecutableImage
+{
+public:
+ //! Possible types of memory regions.
+ typedef enum {
+ TEXT_REGION, //!< A region containing data or instructions.
+ FILL_REGION //!< Region to be initialized with zero bytes.
+ } MemoryRegionType;
+
+ //! Memory region flag constants.
+ enum {
+ REGION_READ_FLAG = 1, //!< Region is readable.
+ REGION_WRITE_FLAG = 2, //!< Region is writable.
+ REGION_EXEC_FLAG = 4, //!< Region may contain executable code.
+
+ REGION_RW_FLAG = REGION_READ_FLAG | REGION_WRITE_FLAG, //!< Region is read-write.
+
+ //! Mask to access only permissions flags for a region.
+ REGION_PERM_FLAG_MASK = 0x7
+ };
+
+ /*!
+ * Representation of a contiguous region of memory.
+ *
+ * \todo Add comparison operators so we can use the STL sort algorithm.
+ */
+ struct MemoryRegion
+ {
+ MemoryRegionType m_type; //!< Memory region type.
+ uint32_t m_address; //!< The 32-bit start address of this region.
+ uint32_t m_length; //!< Number of bytes in this region.
+ uint8_t * m_data; //!< Pointer to data. Will be NULL for FILL_REGION type.
+ unsigned m_flags; //!< Flags for the region.
+
+ //! \brief Calculates the address of the last byte occupied by this region.
+ inline uint32_t endAddress() const { return m_address + m_length - 1; }
+
+ //! \brief Equality operator.
+ bool operator == (const MemoryRegion & other);
+ };
+
+ //! A list of #StExecutableImage::MemoryRegion objects.
+ typedef std::list<MemoryRegion> MemoryRegionList;
+
+ //! The iterator type used to access #StExecutableImage::MemoryRegion objects. This type
+ //! is used by the methods #getRegionBegin() and #getRegionEnd().
+ typedef MemoryRegionList::const_iterator const_iterator;
+
+ //! The possible actions for regions matching an address filter range.
+ typedef enum {
+ ADDR_FILTER_NONE, //!< Do nothing.
+ ADDR_FILTER_ERROR, //!< Raise an error exception.
+ ADDR_FILTER_WARNING, //!< Raise a warning exception.
+ ADDR_FILTER_CROP //!< Don't include the matching address range in the executable image.
+ } AddressFilterAction;
+
+ /*!
+ * An address filter consists of a single address range and an action. If a
+ * memory region overlaps the filter's range then the action will be performed.
+ * The possible filter actions are defined by the #AddressFilterAction enumeration.
+ */
+ struct AddressFilter
+ {
+ AddressFilterAction m_action; //!< Action to be performed when the filter is matched.
+ uint32_t m_fromAddress; //!< Start address of the filter. Should be lower than or equal to #m_toAddress.
+ uint32_t m_toAddress; //!< End address of the filter. Should be higher than or equal to #m_fromAddress.
+ unsigned m_priority; //!< Priority for this filter. Zero is the lowest priority.
+
+ //! \brief Constructor.
+ AddressFilter(AddressFilterAction action, uint32_t from, uint32_t to, unsigned priority=0)
+ : m_action(action), m_fromAddress(from), m_toAddress(to), m_priority(priority)
+ {
+ }
+
+ //! \brief Test routine.
+ bool matchesMemoryRegion(const MemoryRegion & region) const;
+
+ //! \brief Compares two address filter objects.
+ int compare(const AddressFilter & other) const;
+
+ //! \name Comparison operators
+ //@{
+ inline bool operator < (const AddressFilter & other) const { return compare(other) == -1; }
+ inline bool operator > (const AddressFilter & other) const { return compare(other) == 1; }
+ inline bool operator == (const AddressFilter & other) const { return compare(other) == 0; }
+ inline bool operator <= (const AddressFilter & other) const { return compare(other) != 1; }
+ inline bool operator >= (const AddressFilter & other) const { return compare(other) != -1; }
+ //@}
+ };
+
+ //! List of #StExecutableImage::AddressFilter objects.
+ typedef std::list<AddressFilter> AddressFilterList;
+
+ //! The exception class raised for the #ADDR_FILTER_ERROR and #ADDR_FILTER_WARNING
+ //! filter actions.
+ class address_filter_exception
+ {
+ public:
+ //! \brief Constructor.
+ //!
+ //! A local copy of \a matchingFilter is made, in case the image and/or filter
+ //! are on the stack and would be disposed of when the exception is raised.
+ address_filter_exception(bool isError, std::string & imageName, const AddressFilter & matchingFilter)
+ : m_isError(isError), m_imageName(imageName), m_filter(matchingFilter)
+ {
+ }
+
+ //! \brief Returns true if the exception is an error. Otherwise the exception
+ //! is for a warning.
+ inline bool isError() const { return m_isError; }
+
+ //! \brief
+ inline std::string getImageName() const { return m_imageName; }
+
+ //! \brief
+ inline const AddressFilter & getMatchingFilter() const { return m_filter; }
+
+ protected:
+ bool m_isError;
+ std::string m_imageName;
+ AddressFilter m_filter;
+ };
+
+public:
+ //! \brief Constructor.
+ StExecutableImage(int inAlignment=256);
+
+ //! \brief Copy constructor.
+ StExecutableImage(const StExecutableImage & inOther);
+
+ //! \brief Destructor.
+ virtual ~StExecutableImage();
+
+ //! \name Image name
+ //! Methods for getting and setting the image name.
+ //@{
+ //! \brief Sets the image's name to \a inName.
+ virtual void setName(const std::string & inName);
+
+ //! \brief Returns a copy of the image's name.
+ virtual std::string getName() const;
+ //@}
+
+ //! \name Regions
+ //! Methods to add and access memory regions.
+ //@{
+ //! \brief Add a region to be filled with zeroes.
+ virtual void addFillRegion(uint32_t inAddress, unsigned inLength);
+
+ //! \brief Add a region containing data to be loaded.
+ virtual void addTextRegion(uint32_t inAddress, const uint8_t * inData, unsigned inLength);
+
+ //! \brief Returns the total number of regions.
+ //!
+ //! Note that this count may not be the same as the number of calls to
+ //! addFillRegion() and addTextRegion() due to region coalescing.
+ inline unsigned getRegionCount() const { return static_cast<unsigned>(m_image.size()); }
+
+ //! \brief Returns a reference to the region specified by \a inIndex.
+ const MemoryRegion & getRegionAtIndex(unsigned inIndex) const;
+
+ //! \brief Return an iterator to the first region.
+ inline const_iterator getRegionBegin() const { return m_image.begin(); }
+
+ //! \brief Return an iterator to the next-after-last region.
+ inline const_iterator getRegionEnd() const { return m_image.end(); }
+ //@}
+
+ //! \name Entry point
+ //@{
+ //! \brief Sets the entry point address.
+ inline void setEntryPoint(uint32_t inEntryAddress) { m_entry = inEntryAddress; m_hasEntry = true; }
+
+ //! \brief Returns true if an entry point has been set.
+ inline bool hasEntryPoint() const { return m_hasEntry; }
+
+ //! \brief Returns the entry point address.
+ inline uint32_t getEntryPoint() const { return hasEntryPoint() ? m_entry : 0; }
+ //@}
+
+ //! \name Address filter
+ //@{
+ //! \brief Add a new address filter.
+ virtual void addAddressFilter(const AddressFilter & filter);
+
+ //! \brief Add multiple address filters at once.
+ //!
+ //! The template argument \a _T must be an iterator or const iterator that
+ //! dereferences to an StExecutableImage::AddressFilter reference. All filters
+ //! from \a from to \a to will be added to the address filter list.
+ template<typename _T> void addAddressFilters(_T from, _T to)
+ {
+ _T it = from;
+ for (; it != to; ++it)
+ {
+ addAddressFilter(*it);
+ }
+ }
+
+ //! \brief Remove all active filters.
+ virtual void clearAddressFilters();
+
+ //! \brief Process all active filters and perform associated actions.
+ virtual void applyAddressFilters();
+ //@}
+
+protected:
+ std::string m_name; //!< The name of the image (can be a file name, for instance).
+ int m_alignment; //!< The required address alignment for each memory region.
+ bool m_hasEntry; //!< True if an entry point has been set.
+ uint32_t m_entry; //!< Entry point address.
+ MemoryRegionList m_image; //!< The memory regions.
+ AddressFilterList m_filters; //!< List of active address filters.
+
+ //! \brief Deletes the portion \a region that overlaps \a filter.
+ void cropRegionToFilter(MemoryRegion & region, const AddressFilter & filter);
+
+ //! \brief Inserts the region in sorted order or merges with one already in the image.
+ void insertOrMergeRegion(MemoryRegion & inRegion);
+
+ //! \brief Merges two memory regions into one.
+ void mergeRegions(MemoryRegion & inOldRegion, MemoryRegion & inNewRegion);
+};
+
+#endif // _StExecutableImage_h_
diff --git a/common/StSRecordFile.cpp b/common/StSRecordFile.cpp
new file mode 100644
index 0000000..1ad0872
--- /dev/null
+++ b/common/StSRecordFile.cpp
@@ -0,0 +1,235 @@
+/*
+ * File: StSRecordFile.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "stdafx.h"
+#include "StSRecordFile.h"
+#include "string.h"
+
+StSRecordFile::StSRecordFile(std::istream & inStream)
+: m_stream(inStream)
+{
+}
+
+//! Frees any data allocated as part of an S-record.
+StSRecordFile::~StSRecordFile()
+{
+ const_iterator it;
+ for (it = m_records.begin(); it != m_records.end(); it++)
+ {
+ SRecord & theRecord = (SRecord &)*it;
+ if (theRecord.m_data)
+ {
+ delete [] theRecord.m_data;
+ theRecord.m_data = NULL;
+ }
+ }
+}
+
+//! Just looks for "S[0-9]" as the first two characters of the file.
+bool StSRecordFile::isSRecordFile()
+{
+ int savePosition = m_stream.tellg();
+ m_stream.seekg(0, std::ios_base::beg);
+
+ char buffer[2];
+ m_stream.read(buffer, 2);
+ bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
+
+ m_stream.seekg(savePosition, std::ios_base::beg);
+
+ return isSRecord;
+}
+
+//! Extract records one line at a time and hand them to the parseLine()
+//! method. Either CR, LF, or CRLF line endings are supported. The input
+//! stream is read until EOF.
+//! The parse() method must be called after the object has been constructed
+//! before any of the records will become accessible.
+//! \exception StSRecordParseException will be thrown if any error occurs while
+//! parsing the input.
+void StSRecordFile::parse()
+{
+ // back to start of stream
+ m_stream.seekg(0, std::ios_base::beg);
+
+ std::string thisLine;
+
+ do {
+ char thisChar;
+ m_stream.get(thisChar);
+
+ if (thisChar == '\r' || thisChar == '\n')
+ {
+ // skip the LF in a CRLF
+ if (thisChar == '\r' && m_stream.peek() == '\n')
+ m_stream.ignore();
+
+ // parse line if it's not empty
+ if (!thisLine.empty())
+ {
+ parseLine(thisLine);
+
+ // reset line
+ thisLine.clear();
+ }
+ }
+ else
+ {
+ thisLine += thisChar;
+ }
+ } while (!m_stream.eof());
+}
+
+bool StSRecordFile::isHexDigit(char c)
+{
+ return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+int StSRecordFile::hexDigitToInt(char digit)
+{
+ if (isdigit(digit))
+ return digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ return 10 + digit - 'a';
+ else if (digit >= 'A' && digit <= 'F')
+ return 10 + digit - 'A';
+
+ // unknow char
+ return 0;
+}
+
+//! \exception StSRecordParseException is thrown if either of the nibble characters
+//! is not a valid hex digit.
+int StSRecordFile::readHexByte(std::string & inString, int inIndex)
+{
+ char nibbleCharHi= inString[inIndex];
+ char nibbleCharLo = inString[inIndex + 1];
+
+ // must be hex digits
+ if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
+ {
+ throw StSRecordParseException("invalid hex digit");
+ }
+
+ return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
+}
+
+//! \brief Parses individual S-records.
+//!
+//! Takes a single S-record line as input and appends a new SRecord struct
+//! to the m_records vector.
+//! \exception StSRecordParseException will be thrown if any error occurs while
+//! parsing \a inLine.
+void StSRecordFile::parseLine(std::string & inLine)
+{
+ int checksum = 0;
+ SRecord newRecord;
+ memset(&newRecord, 0, sizeof(newRecord));
+
+ // must start with "S" and be at least a certain length
+ if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
+ {
+ throw StSRecordParseException("invalid record length");
+ }
+
+ // parse type field
+ char typeChar = inLine[1];
+ if (!isdigit(typeChar))
+ {
+ throw StSRecordParseException("invalid S-record type");
+ }
+ newRecord.m_type = typeChar - '0';
+
+ // parse count field
+ newRecord.m_count = readHexByte(inLine, 2);
+ checksum += newRecord.m_count;
+
+ // verify the record length now that we know the count
+ if (inLine.length() != 4 + newRecord.m_count * 2)
+ {
+ throw StSRecordParseException("invalid record length");
+ }
+
+ // get address length
+ int addressLength; // len in bytes
+ bool hasData = false;
+ switch (newRecord.m_type)
+ {
+ case 0: // contains header information
+ addressLength = 2;
+ hasData = true;
+ break;
+ case 1: // data record with 2-byte address
+ addressLength = 2;
+ hasData = true;
+ break;
+ case 2: // data record with 3-byte address
+ addressLength = 3;
+ hasData = true;
+ break;
+ case 3: // data record with 4-byte address
+ addressLength = 4;
+ hasData = true;
+ break;
+ case 5: // the 2-byte address field contains a count of all prior S1, S2, and S3 records
+ addressLength = 2;
+ break;
+ case 7: // entry point record with 4-byte address
+ addressLength = 4;
+ break;
+ case 8: // entry point record with 3-byte address
+ addressLength = 3;
+ break;
+ case 9: // entry point record with 2-byte address
+ addressLength = 2;
+ break;
+ default:
+ // unrecognized type
+ //throw StSRecordParseException("unknown S-record type");
+ break;
+ }
+
+ // read address
+ int address = 0;
+ int i;
+ for (i=0; i < addressLength; ++i)
+ {
+ int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
+ address = (address << 8) | addressByte;
+ checksum += addressByte;
+ }
+ newRecord.m_address = address;
+
+ // read data
+ if (hasData)
+ {
+ int dataStartCharIndex = 4 + addressLength * 2;
+ int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
+ uint8_t * data = new uint8_t[dataLength];
+
+ for (i=0; i < dataLength; ++i)
+ {
+ int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
+ data[i] = dataByte;
+ checksum += dataByte;
+ }
+
+ newRecord.m_data = data;
+ newRecord.m_dataCount = dataLength;
+ }
+
+ // read and compare checksum byte
+ checksum = (~checksum) & 0xff; // low byte of one's complement of sum of other bytes
+ newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
+ if (checksum != newRecord.m_checksum)
+ {
+ throw StSRecordParseException("invalid checksum");
+ }
+
+ // now save the new S-record
+ m_records.push_back(newRecord);
+}
diff --git a/common/StSRecordFile.h b/common/StSRecordFile.h
new file mode 100644
index 0000000..4340c6a
--- /dev/null
+++ b/common/StSRecordFile.h
@@ -0,0 +1,119 @@
+/*
+ * File: StSRecordFile.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_StSRecordFile_h_)
+#define _StSRecordFile_h_
+
+//#include <stdint.h>
+#include "stdafx.h"
+#include <istream>
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+enum {
+ //! The required first character of an S-record.
+ SRECORD_START_CHAR = 'S',
+
+ //! The minimum length of a S-record. This is the type (2) + count (2) + addr (4) + cksum (2).
+ SRECORD_MIN_LENGTH = 10,
+
+ //! Index of the first character of the address field.
+ SRECORD_ADDRESS_START_CHAR_INDEX = 4
+};
+
+/*!
+ * \brief S-record parser.
+ *
+ * This class takes an input stream and parses it as an S-record file. While
+ * the individual records that comprise the file are available for access, the
+ * class also provides a higher-level view of the contents. It processes the
+ * individual records and builds an image of what the memory touched by the
+ * file looks like. Then you can access the contiguous sections of memory.
+ */
+class StSRecordFile
+{
+public:
+ /*!
+ * Structure representing each individual line of the S-record input data.
+ */
+ struct SRecord
+ {
+ unsigned m_type; //!< Record number type, such as 9 for "S9", 3 for "S3" and so on.
+ unsigned m_count; //!< Number of character pairs (bytes) from address through checksum.
+ uint32_t m_address; //!< The address specified as part of the S-record.
+ unsigned m_dataCount; //!< Number of bytes of data.
+ uint8_t * m_data; //!< Pointer to data, or NULL if no data for this record type.
+ uint8_t m_checksum; //!< The checksum byte present in the S-record.
+ };
+
+ //! Iterator type.
+ typedef std::vector<SRecord>::const_iterator const_iterator;
+
+public:
+ //! \brief Constructor.
+ StSRecordFile(std::istream & inStream);
+
+ //! \brief Destructor.
+ virtual ~StSRecordFile();
+
+ //! \name File name
+ //@{
+ virtual void setName(const std::string & inName) { m_name = inName; }
+ virtual std::string getName() const { return m_name; }
+ //@}
+
+ //! \name Parsing
+ //@{
+ //! \brief Determine if the file is an S-record file.
+ virtual bool isSRecordFile();
+
+ //! \brief Parses the entire S-record input stream.
+ virtual void parse();
+ //@}
+
+ //! \name Record access
+ //@{
+ //! \return the number of S-records that have been parsed from the input stream.
+ inline unsigned getRecordCount() const { return static_cast<unsigned>(m_records.size()); }
+
+ //! \return iterator for
+ inline const_iterator getBegin() const { return m_records.begin(); }
+ inline const_iterator getEnd() const { return m_records.end(); }
+ //@}
+
+ //! \name Operators
+ //@{
+ inline const SRecord & operator [] (unsigned inIndex) { return m_records[inIndex]; }
+ //@}
+
+protected:
+ std::istream& m_stream; //!< The input stream for the S-record data.
+ std::vector<SRecord> m_records; //!< Vector of S-records in the input data.
+
+ std::string m_name; //!< File name. (optional)
+
+ //! \name Parsing utilities
+ //@{
+ virtual void parseLine(std::string & inLine);
+
+ bool isHexDigit(char c);
+ int hexDigitToInt(char digit);
+ int readHexByte(std::string & inString, int inIndex);
+ //@}
+};
+
+/*!
+ * \brief Simple exception thrown to indicate an error in the input SRecord data format.
+ */
+class StSRecordParseException : public std::runtime_error
+{
+public:
+ //! \brief Default constructor.
+ StSRecordParseException(const std::string & inMessage) : std::runtime_error(inMessage) {}
+};
+
+#endif // _StSRecordFile_h_
diff --git a/common/StringMatcher.h b/common/StringMatcher.h
new file mode 100644
index 0000000..e8074ff
--- /dev/null
+++ b/common/StringMatcher.h
@@ -0,0 +1,62 @@
+/*
+ * File: GlobSectionSelector.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_StringMatcher_h_)
+#define _StringMatcher_h_
+
+#include <string>
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract interface class used to select strings by name.
+ */
+class StringMatcher
+{
+public:
+ //! \brief Performs a single string match test against testValue.
+ //!
+ //! \retval true The \a testValue argument matches.
+ //! \retval false No match was made against the argument.
+ virtual bool match(const std::string & testValue)=0;
+};
+
+/*!
+ * \brief String matcher subclass that matches all test strings.
+ */
+class WildcardMatcher : public StringMatcher
+{
+public:
+ //! \brief Always returns true, indicating a positive match.
+ virtual bool match(const std::string & testValue) { return true; }
+};
+
+/*!
+ * \brief Simple string matcher that compares against a fixed value.
+ */
+class FixedMatcher : public StringMatcher
+{
+public:
+ //! \brief Constructor. Sets the string to compare against to be \a fixedValue.
+ FixedMatcher(const std::string & fixedValue) : m_value(fixedValue) {}
+
+ //! \brief Returns whether \a testValue is the same as the value passed to the constructor.
+ //!
+ //! \retval true The \a testValue argument matches the fixed compare value.
+ //! \retval false The argument is not the same as the compare value.
+ virtual bool match(const std::string & testValue)
+ {
+ return testValue == m_value;
+ }
+
+protected:
+ const std::string & m_value; //!< The section name to look for.
+};
+
+}; // namespace elftosb
+
+#endif // _StringMatcher_h_
diff --git a/common/Value.cpp b/common/Value.cpp
new file mode 100644
index 0000000..5a6a034
--- /dev/null
+++ b/common/Value.cpp
@@ -0,0 +1,43 @@
+/*
+ * File: Value.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Value.h"
+
+using namespace elftosb;
+
+//! Returns a varying size depending on the word size attribute.
+//!
+size_t SizedIntegerValue::getSize() const
+{
+ switch (m_size)
+ {
+ case kWordSize:
+ return sizeof(uint32_t);
+ case kHalfWordSize:
+ return sizeof(uint16_t);
+ case kByteSize:
+ return sizeof(uint8_t);
+ }
+ return kWordSize;
+}
+
+//! The resulting mask can be used to truncate the integer value to be
+//! certain it doesn't extend beyond the associated word size.
+uint32_t SizedIntegerValue::getWordSizeMask() const
+{
+ switch (m_size)
+ {
+ case kWordSize:
+ return 0xffffffff;
+ case kHalfWordSize:
+ return 0x0000ffff;
+ case kByteSize:
+ return 0x000000ff;
+ }
+ return 0;
+}
+
diff --git a/common/Value.h b/common/Value.h
new file mode 100644
index 0000000..8a676d5
--- /dev/null
+++ b/common/Value.h
@@ -0,0 +1,138 @@
+/*
+ * File: Value.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Value_h_)
+#define _Value_h_
+
+#include "stdafx.h"
+#include <string>
+#include "int_size.h"
+#include "Blob.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract base class for values of arbitrary types.
+ */
+class Value
+{
+public:
+ Value() {}
+ virtual ~Value() {}
+
+ virtual std::string getTypeName() const = 0;
+ virtual size_t getSize() const = 0;
+};
+
+/*!
+ * \brief 32-bit signed integer value.
+ */
+class IntegerValue : public Value
+{
+public:
+ IntegerValue() : m_value(0) {}
+ IntegerValue(uint32_t value) : m_value(value) {}
+ IntegerValue(const IntegerValue & other) : m_value(other.m_value) {}
+
+ virtual std::string getTypeName() const { return "integer"; }
+ virtual size_t getSize() const { return sizeof(m_value); }
+
+ inline uint32_t getValue() const { return m_value; }
+
+ inline operator uint32_t () const { return m_value; }
+
+ inline IntegerValue & operator = (uint32_t value) { m_value = value; return *this; }
+
+protected:
+ uint32_t m_value; //!< The integer value.
+};
+
+/*!
+ * \brief Adds a word size attribute to IntegerValue.
+ *
+ * The word size really only acts as an attribute that is carried along
+ * with the integer value. It doesn't affect the actual value at all.
+ * However, you can use the getWordSizeMask() method to mask off bits
+ * that should not be there.
+ *
+ * The word size defaults to a 32-bit word.
+ */
+class SizedIntegerValue : public IntegerValue
+{
+public:
+ SizedIntegerValue() : IntegerValue(), m_size(kWordSize) {}
+ SizedIntegerValue(uint32_t value, int_size_t size=kWordSize) : IntegerValue(value), m_size(size) {}
+ SizedIntegerValue(uint16_t value) : IntegerValue(value), m_size(kHalfWordSize) {}
+ SizedIntegerValue(uint8_t value) : IntegerValue(value), m_size(kByteSize) {}
+ SizedIntegerValue(const SizedIntegerValue & other) : IntegerValue(other), m_size(other.m_size) {}
+
+ virtual std::string getTypeName() const { return "sized integer"; }
+ virtual size_t getSize() const;
+
+ inline int_size_t getWordSize() const { return m_size; }
+ inline void setWordSize(int_size_t size) { m_size = size; }
+
+ //! \brief Returns a 32-bit mask value dependant on the word size attribute.
+ uint32_t getWordSizeMask() const;
+
+ //! \name Assignment operators
+ //! These operators set the word size as well as the integer value.
+ //@{
+ SizedIntegerValue & operator = (uint8_t value) { m_value = value; m_size = kByteSize; return *this; }
+ SizedIntegerValue & operator = (uint16_t value) { m_value = value; m_size = kHalfWordSize; return *this; }
+ SizedIntegerValue & operator = (uint32_t value) { m_value = value; m_size = kWordSize; return *this; }
+ //@}
+
+protected:
+ int_size_t m_size; //!< Size of the integer.
+};
+
+/*!
+ * \brief String value.
+ *
+ * Simply wraps the STL std::string class.
+ */
+class StringValue : public Value
+{
+public:
+ StringValue() : m_value() {}
+ StringValue(const std::string & value) : m_value(value) {}
+ StringValue(const std::string * value) : m_value(*value) {}
+ StringValue(const StringValue & other) : m_value(other.m_value) {}
+
+ virtual std::string getTypeName() const { return "string"; }
+ virtual size_t getSize() const { return m_value.size(); }
+
+ operator const char * () const { return m_value.c_str(); }
+ operator const std::string & () const { return m_value; }
+ operator std::string & () { return m_value; }
+ operator const std::string * () { return &m_value; }
+ operator std::string * () { return &m_value; }
+
+ StringValue & operator = (const StringValue & other) { m_value = other.m_value; return *this; }
+ StringValue & operator = (const std::string & value) { m_value = value; return *this; }
+ StringValue & operator = (const char * value) { m_value = value; return *this; }
+
+protected:
+ std::string m_value;
+};
+
+/*!
+ * \brief Binary object value of arbitrary size.
+ */
+class BinaryValue : public Value, public Blob
+{
+public:
+ BinaryValue() : Value(), Blob() {}
+
+ virtual std::string getTypeName() const { return "binary"; }
+ virtual size_t getSize() const { return getLength(); }
+};
+
+}; // namespace elftosb
+
+#endif // _Value_h_
diff --git a/common/Version.cpp b/common/Version.cpp
new file mode 100644
index 0000000..5d40d67
--- /dev/null
+++ b/common/Version.cpp
@@ -0,0 +1,143 @@
+/*
+ * File: Version.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "Version.h"
+#include "EndianUtilities.h"
+
+using namespace elftosb;
+
+/*!
+ * Parses a string in the form "xxx.xxx.xxx" (where x is a digit) into
+ * three version fields for major, minor, and revision. The output is
+ * right aligned BCD in host-natural byte order.
+ *
+ * \param versionString String containing the version.
+ */
+void version_t::set(const std::string & versionString)
+{
+ size_t length = versionString.size();
+ unsigned version = 0;
+ unsigned index = 0;
+
+ typedef enum {
+ kVersionStateNone,
+ kVersionStateMajor,
+ kVersionStateMinor,
+ kVersionStateRevision
+ } VersionParseState;
+
+ // set initial versions to 0s
+ m_major = 0;
+ m_minor = 0;
+ m_revision = 0;
+
+ VersionParseState parseState = kVersionStateNone;
+ bool done = false;
+ for (; index < length && !done; ++index)
+ {
+ char c = versionString[index];
+
+ if (isdigit(c))
+ {
+ switch (parseState)
+ {
+ case kVersionStateNone:
+ parseState = kVersionStateMajor;
+ version = c - '0';
+ break;
+ case kVersionStateMajor:
+ case kVersionStateMinor:
+ case kVersionStateRevision:
+ version = (version << 4) | (c - '0');
+ break;
+ }
+ }
+ else if (c == '.')
+ {
+ switch (parseState)
+ {
+ case kVersionStateNone:
+ parseState = kVersionStateNone;
+ break;
+ case kVersionStateMajor:
+ m_major = version;
+ version = 0;
+ parseState = kVersionStateMinor;
+ break;
+ case kVersionStateMinor:
+ m_minor = version;
+ version = 0;
+ parseState = kVersionStateRevision;
+ break;
+ case kVersionStateRevision:
+ m_revision = version;
+ version = 0;
+ done = true;
+ break;
+ }
+ }
+ else
+ {
+ switch (parseState)
+ {
+ case kVersionStateNone:
+ parseState = kVersionStateNone;
+ break;
+ case kVersionStateMajor:
+ m_major = version;
+ done = true;
+ break;
+ case kVersionStateMinor:
+ m_minor = version;
+ done = true;
+ break;
+ case kVersionStateRevision:
+ m_revision = version;
+ done = true;
+ break;
+ }
+ }
+ }
+
+ switch (parseState)
+ {
+ case kVersionStateMajor:
+ m_major = version;
+ break;
+ case kVersionStateMinor:
+ m_minor = version;
+ break;
+ case kVersionStateRevision:
+ m_revision = version;
+ break;
+ default:
+ // do nothing
+ break;
+ }
+}
+
+//! \brief Converts host endian BCD version values to the equivalent big-endian BCD values.
+//!
+//! The output is a half-word. And BCD is inherently big-endian, or byte ordered, if
+//! you prefer to think of it that way. So for little endian systems, we need to convert
+//! the output half-word in reverse byte order. When it is written to disk or a
+//! buffer it will come out big endian.
+//!
+//! For example:
+//! - The input is BCD in host endian format, so 0x1234. Written to a file, this would
+//! come out as 0x34 0x12, reverse of what we want.
+//! - The desired BCD output is the two bytes 0x12 0x34.
+//! - So the function's uint16_t result must be 0x3412 on a little-endian host.
+//!
+//! On big endian hosts, we don't have to worry about byte swapping.
+void version_t::fixByteOrder()
+{
+ m_major = ENDIAN_HOST_TO_BIG_U16(m_major);
+ m_minor = ENDIAN_HOST_TO_BIG_U16(m_minor);
+ m_revision = ENDIAN_HOST_TO_BIG_U16(m_revision);
+}
+
diff --git a/common/Version.h b/common/Version.h
new file mode 100644
index 0000000..9533586
--- /dev/null
+++ b/common/Version.h
@@ -0,0 +1,51 @@
+/*
+ * File: Version.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_Version_h_)
+#define _Version_h_
+
+#include <string>
+#include "stdafx.h"
+
+namespace elftosb
+{
+
+//! Same version struct used for 3600 boot image.
+struct version_t
+{
+ uint16_t m_major;
+ uint16_t m_pad0;
+ uint16_t m_minor;
+ uint16_t m_pad1;
+ uint16_t m_revision;
+ uint16_t m_pad2;
+
+ version_t()
+ : m_major(0x999), m_pad0(0), m_minor(0x999), m_pad1(0), m_revision(0x999), m_pad2(0)
+ {
+ }
+
+ version_t(uint16_t maj, uint16_t min, uint16_t rev)
+ : m_major(maj), m_pad0(0), m_minor(min), m_pad1(0), m_revision(rev), m_pad2(0)
+ {
+ }
+
+ version_t(const std::string & versionString)
+ : m_major(0x999), m_pad0(0), m_minor(0x999), m_pad1(0), m_revision(0x999), m_pad2(0)
+ {
+ set(versionString);
+ }
+
+ //! \brief Sets the version by parsing a string.
+ void set(const std::string & versionString);
+
+ //! \brief
+ void fixByteOrder();
+};
+
+}; // namespace elftosb
+
+#endif // _Version_h_
diff --git a/common/crc.cpp b/common/crc.cpp
new file mode 100644
index 0000000..8c32819
--- /dev/null
+++ b/common/crc.cpp
@@ -0,0 +1,292 @@
+/*
+ * File: crc.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "crc.h"
+
+//! Table of CRC-32's of all single byte values. The values in
+//! this table are those used in the Ethernet CRC algorithm.
+const uint32_t CRC32::m_tab[] = {
+//#ifdef __LITTLE_ENDIAN__
+ 0x00000000,
+ 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+ 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+ 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+ 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+ 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+ 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+ 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+ 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+ 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+ 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+ 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+ 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+ 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+ 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+ 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+ 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+ 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+ 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+ 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+ 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+ 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+ 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+ 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+ 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+ 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+ 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+ 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+ 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+ 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+ 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+ 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+ 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+ 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+ 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+//#else
+// 0x00000000,
+// 0xb71dc104, 0x6e3b8209, 0xd926430d, 0xdc760413, 0x6b6bc517,
+// 0xb24d861a, 0x0550471e, 0xb8ed0826, 0x0ff0c922, 0xd6d68a2f,
+// 0x61cb4b2b, 0x649b0c35, 0xd386cd31, 0x0aa08e3c, 0xbdbd4f38,
+// 0x70db114c, 0xc7c6d048, 0x1ee09345, 0xa9fd5241, 0xacad155f,
+// 0x1bb0d45b, 0xc2969756, 0x758b5652, 0xc836196a, 0x7f2bd86e,
+// 0xa60d9b63, 0x11105a67, 0x14401d79, 0xa35ddc7d, 0x7a7b9f70,
+// 0xcd665e74, 0xe0b62398, 0x57abe29c, 0x8e8da191, 0x39906095,
+// 0x3cc0278b, 0x8bdde68f, 0x52fba582, 0xe5e66486, 0x585b2bbe,
+// 0xef46eaba, 0x3660a9b7, 0x817d68b3, 0x842d2fad, 0x3330eea9,
+// 0xea16ada4, 0x5d0b6ca0, 0x906d32d4, 0x2770f3d0, 0xfe56b0dd,
+// 0x494b71d9, 0x4c1b36c7, 0xfb06f7c3, 0x2220b4ce, 0x953d75ca,
+// 0x28803af2, 0x9f9dfbf6, 0x46bbb8fb, 0xf1a679ff, 0xf4f63ee1,
+// 0x43ebffe5, 0x9acdbce8, 0x2dd07dec, 0x77708634, 0xc06d4730,
+// 0x194b043d, 0xae56c539, 0xab068227, 0x1c1b4323, 0xc53d002e,
+// 0x7220c12a, 0xcf9d8e12, 0x78804f16, 0xa1a60c1b, 0x16bbcd1f,
+// 0x13eb8a01, 0xa4f64b05, 0x7dd00808, 0xcacdc90c, 0x07ab9778,
+// 0xb0b6567c, 0x69901571, 0xde8dd475, 0xdbdd936b, 0x6cc0526f,
+// 0xb5e61162, 0x02fbd066, 0xbf469f5e, 0x085b5e5a, 0xd17d1d57,
+// 0x6660dc53, 0x63309b4d, 0xd42d5a49, 0x0d0b1944, 0xba16d840,
+// 0x97c6a5ac, 0x20db64a8, 0xf9fd27a5, 0x4ee0e6a1, 0x4bb0a1bf,
+// 0xfcad60bb, 0x258b23b6, 0x9296e2b2, 0x2f2bad8a, 0x98366c8e,
+// 0x41102f83, 0xf60dee87, 0xf35da999, 0x4440689d, 0x9d662b90,
+// 0x2a7bea94, 0xe71db4e0, 0x500075e4, 0x892636e9, 0x3e3bf7ed,
+// 0x3b6bb0f3, 0x8c7671f7, 0x555032fa, 0xe24df3fe, 0x5ff0bcc6,
+// 0xe8ed7dc2, 0x31cb3ecf, 0x86d6ffcb, 0x8386b8d5, 0x349b79d1,
+// 0xedbd3adc, 0x5aa0fbd8, 0xeee00c69, 0x59fdcd6d, 0x80db8e60,
+// 0x37c64f64, 0x3296087a, 0x858bc97e, 0x5cad8a73, 0xebb04b77,
+// 0x560d044f, 0xe110c54b, 0x38368646, 0x8f2b4742, 0x8a7b005c,
+// 0x3d66c158, 0xe4408255, 0x535d4351, 0x9e3b1d25, 0x2926dc21,
+// 0xf0009f2c, 0x471d5e28, 0x424d1936, 0xf550d832, 0x2c769b3f,
+// 0x9b6b5a3b, 0x26d61503, 0x91cbd407, 0x48ed970a, 0xfff0560e,
+// 0xfaa01110, 0x4dbdd014, 0x949b9319, 0x2386521d, 0x0e562ff1,
+// 0xb94beef5, 0x606dadf8, 0xd7706cfc, 0xd2202be2, 0x653deae6,
+// 0xbc1ba9eb, 0x0b0668ef, 0xb6bb27d7, 0x01a6e6d3, 0xd880a5de,
+// 0x6f9d64da, 0x6acd23c4, 0xddd0e2c0, 0x04f6a1cd, 0xb3eb60c9,
+// 0x7e8d3ebd, 0xc990ffb9, 0x10b6bcb4, 0xa7ab7db0, 0xa2fb3aae,
+// 0x15e6fbaa, 0xccc0b8a7, 0x7bdd79a3, 0xc660369b, 0x717df79f,
+// 0xa85bb492, 0x1f467596, 0x1a163288, 0xad0bf38c, 0x742db081,
+// 0xc3307185, 0x99908a5d, 0x2e8d4b59, 0xf7ab0854, 0x40b6c950,
+// 0x45e68e4e, 0xf2fb4f4a, 0x2bdd0c47, 0x9cc0cd43, 0x217d827b,
+// 0x9660437f, 0x4f460072, 0xf85bc176, 0xfd0b8668, 0x4a16476c,
+// 0x93300461, 0x242dc565, 0xe94b9b11, 0x5e565a15, 0x87701918,
+// 0x306dd81c, 0x353d9f02, 0x82205e06, 0x5b061d0b, 0xec1bdc0f,
+// 0x51a69337, 0xe6bb5233, 0x3f9d113e, 0x8880d03a, 0x8dd09724,
+// 0x3acd5620, 0xe3eb152d, 0x54f6d429, 0x7926a9c5, 0xce3b68c1,
+// 0x171d2bcc, 0xa000eac8, 0xa550add6, 0x124d6cd2, 0xcb6b2fdf,
+// 0x7c76eedb, 0xc1cba1e3, 0x76d660e7, 0xaff023ea, 0x18ede2ee,
+// 0x1dbda5f0, 0xaaa064f4, 0x738627f9, 0xc49be6fd, 0x09fdb889,
+// 0xbee0798d, 0x67c63a80, 0xd0dbfb84, 0xd58bbc9a, 0x62967d9e,
+// 0xbbb03e93, 0x0cadff97, 0xb110b0af, 0x060d71ab, 0xdf2b32a6,
+// 0x6836f3a2, 0x6d66b4bc, 0xda7b75b8, 0x035d36b5, 0xb440f7b1
+//#endif // __LITTLE_ENDIAN__
+
+// This is the original table that came with this source.
+//#ifdef __LITTLE_ENDIAN__
+// 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+// 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+// 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+// 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+// 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+// 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+// 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+// 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+// 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+// 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+// 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+// 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+// 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+// 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+// 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+// 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+// 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+// 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+// 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+// 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+// 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+// 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+// 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+// 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+// 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+// 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+// 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+// 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+// 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+// 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+// 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+// 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+// 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+// 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+// 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+// 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+// 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+// 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+// 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+// 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+// 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+// 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+// 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+// 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+// 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+// 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+// 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+// 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+// 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+// 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+// 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+// 0x2d02ef8dL
+//#else
+// 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
+// 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
+// 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
+// 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
+// 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
+// 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
+// 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
+// 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
+// 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
+// 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
+// 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
+// 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
+// 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
+// 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
+// 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
+// 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
+// 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
+// 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
+// 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
+// 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
+// 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
+// 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
+// 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
+// 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
+// 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
+// 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
+// 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
+// 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
+// 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
+// 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
+// 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
+// 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
+// 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
+// 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
+// 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
+// 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
+// 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
+// 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
+// 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
+// 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
+// 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
+// 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
+// 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
+// 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
+// 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
+// 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
+// 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
+// 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
+// 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
+// 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
+// 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
+// 0x8def022dL
+//#endif
+};
+
+CRC32::CRC32()
+{
+ reset();
+}
+
+void CRC32::update(const uint8_t * s, unsigned n)
+{
+ uint32_t crc = m_crc;
+ m_count += n;
+
+ while (n--)
+ {
+ uint8_t c = *s++ & 0xff;
+ crc = (crc << 8) ^ m_tab[(crc >> 24) ^ c];
+ }
+
+// for(; !((reinterpret_cast<uint32_t>(s) & 0x3) == 0) && n > 0; n--)
+// {
+// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
+// }
+//
+// while (n >= 4)
+// {
+// crc ^= *(const uint32_t *)s;
+// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+// n -= 4;
+// s += 4;
+// }
+//
+// while (n--)
+// {
+// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
+// }
+
+ m_crc = crc;
+}
+
+void CRC32::truncatedFinal(uint8_t * hash, unsigned size)
+{
+ // pad with zeroes
+ if (m_count % 4)
+ {
+ unsigned i;
+ for (i = m_count % 4; i < 4; i++) {
+ m_crc = (m_crc << 8) ^ m_tab[(m_crc >> 24) ^ 0];
+ }
+ }
+
+// m_crc ^= CRC32_NEGL;
+
+ unsigned i;
+ for (i=0; i<size; i++)
+ {
+ hash[i] = getCrcByte(i);
+ }
+
+ reset();
+}
+
diff --git a/common/crc.h b/common/crc.h
new file mode 100644
index 0000000..d6d0b7a
--- /dev/null
+++ b/common/crc.h
@@ -0,0 +1,48 @@
+/*
+ * File: crc.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_crc_h_)
+#define CRYPTOPP_CRC32_H
+
+#include "stdafx.h"
+
+const uint32_t CRC32_NEGL = 0xffffffffL;
+
+#ifdef __LITTLE_ENDIAN__
+ #define CRC32_INDEX(c) (c & 0xff)
+ #define CRC32_SHIFTED(c) (c >> 8)
+#else
+ #define CRC32_INDEX(c) (c >> 24)
+ #define CRC32_SHIFTED(c) (c << 8)
+#endif
+
+//! CRC Checksum Calculation
+class CRC32
+{
+public:
+ enum
+ {
+ DIGESTSIZE = 4
+ };
+
+ CRC32();
+
+ void update(const uint8_t * input, unsigned length);
+
+ void truncatedFinal(uint8_t * hash, unsigned size);
+
+ void updateByte(uint8_t b) { m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc); }
+ uint8_t getCrcByte(unsigned i) const { return ((uint8_t *)&(m_crc))[i]; }
+
+private:
+ void reset() { m_crc = CRC32_NEGL; m_count = 0; }
+
+ static const uint32_t m_tab[256];
+ uint32_t m_crc;
+ unsigned m_count;
+};
+
+#endif // _crc_h_
diff --git a/common/format_string.cpp b/common/format_string.cpp
new file mode 100644
index 0000000..3a26d0c
--- /dev/null
+++ b/common/format_string.cpp
@@ -0,0 +1,79 @@
+/*
+ * File: format_string.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "format_string.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdexcept>
+#include <string.h>
+#include <stdlib.h>
+//! Size of the temporary buffer to hold the formatted output string.
+#define WIN32_FMT_BUF_LEN (512)
+
+/*!
+ * \brief Simple template class to free a pointer.
+ */
+template <typename T>
+class free_ptr
+{
+public:
+ //! \brief Constructor.
+ free_ptr(T ptr)
+ : m_p(ptr)
+ {
+ }
+
+ //! \brief Destructor.
+ ~free_ptr()
+ {
+ if (m_p)
+ {
+ free(m_p);
+ }
+ }
+
+protected:
+ T m_p; //!< The value to free.
+};
+
+//! The purpose of this function to provide a convenient way of generating formatted
+//! STL strings inline. This is especially useful when throwing exceptions that take
+//! a std::string for a message. The length of the formatted output string is limited
+//! only by memory. Memory temporarily allocated for the output string is disposed of
+//! before returning.
+//!
+//! Example usage:
+//! \code
+//! throw std::runtime_error(format_string("error on line %d", line));
+//! \endcode
+//!
+//! \param fmt Format string using printf-style format markers.
+//! \return An STL string object of the formatted output.
+std::string format_string(const char * fmt, ...)
+{
+ char * buf = 0;
+ va_list vargs;
+ va_start(vargs, fmt);
+ int result = -1;
+#if WIN32
+ buf = (char *)malloc(WIN32_FMT_BUF_LEN);
+ if (buf)
+ {
+ result = _vsnprintf(buf, WIN32_FMT_BUF_LEN, fmt, vargs);
+ }
+#else // WIN32
+ result = vasprintf(&buf, fmt, vargs);
+#endif // WIN32
+ va_end(vargs);
+ if (result != -1 && buf)
+ {
+ free_ptr<char *> freebuf(buf);
+ return std::string(buf);
+ }
+ return "";
+}
+
diff --git a/common/format_string.h b/common/format_string.h
new file mode 100644
index 0000000..a879d4e
--- /dev/null
+++ b/common/format_string.h
@@ -0,0 +1,20 @@
+/*
+ * File: format_string.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_format_string_h_)
+#define _format_string_h_
+
+#include <string>
+#include <stdexcept>
+
+/*!
+ * \brief Returns a formatted STL string using printf format strings.
+ */
+std::string format_string(const char * fmt, ...);
+
+
+#endif // _format_string_h_
+
diff --git a/common/int_size.h b/common/int_size.h
new file mode 100644
index 0000000..cf66d68
--- /dev/null
+++ b/common/int_size.h
@@ -0,0 +1,22 @@
+/*
+ * File: int_size.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_int_size_h_)
+#define _int_size_h_
+
+namespace elftosb
+{
+
+//! Supported sizes of integers.
+typedef enum {
+ kWordSize, //!< 32-bit word.
+ kHalfWordSize, //!< 16-bit half word.
+ kByteSize //!< 8-bit byte.
+} int_size_t;
+
+}; // namespace elftosb
+
+#endif // _int_size_h_
diff --git a/common/options.cpp b/common/options.cpp
new file mode 100644
index 0000000..9f12aa6
--- /dev/null
+++ b/common/options.cpp
@@ -0,0 +1,1140 @@
+// ****************************************************************************
+// ^FILE: options.c - implement the functions defined in <options.h>
+//
+// ^HISTORY:
+// 01/16/92 Brad Appleton <bradapp@enteract.com> Created
+//
+// 03/23/93 Brad Appleton <bradapp@enteract.com>
+// - Added OptIstreamIter class
+//
+// 10/08/93 Brad Appleton <bradapp@enteract.com>
+// - Added "hidden" options
+//
+// 02/08/94 Brad Appleton <bradapp@enteract.com>
+// - Added "OptionSpec" class
+// - Permitted use of stdio instead of iostreams via #ifdef USE_STDIO
+//
+// 03/08/94 Brad Appleton <bradapp@enteract.com>
+// - completed support for USE_STDIO
+// - added #ifdef NO_USAGE for people who always want to print their own
+// - Fixed stupid NULL pointer error in OptionsSpec class
+//
+// 07/31/97 Brad Appleton <bradapp@enteract.com>
+// - Added PARSE_POS control flag and POSITIONAL return value.
+// ^^**************************************************************************
+
+// #include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "options.h"
+
+using namespace std;
+
+extern "C" {
+ void exit(int);
+}
+
+static const char ident[] = "@(#)Options 1.05" ;
+
+ // I need a portable version of "tolower" that does NOT modify
+ // non-uppercase characters.
+ //
+#define TOLOWER(c) (isupper(c) ? tolower(c) : c)
+
+ // Use this to shut the compiler up about NULL strings
+#define NULLSTR (char *)NULL
+
+// ******************************************************** insertion operators
+
+ // If you are using <stdio.h> then you need this stuff!
+ // If you are using <iostream.h> then #ifdef this stuff out
+ //
+
+
+#ifdef USE_STDIO
+
+ // Implement just enough of ostream to get this file to compile
+ //
+
+static const char endl = '\n' ;
+
+class ostream {
+public:
+ ostream(FILE * fileptr) : fp(fileptr) {}
+
+ ostream &
+ operator<<(char ch);
+
+ ostream &
+ operator<<(const char * str);
+
+ ostream &
+ write(const char * buf, unsigned bufsize);
+
+private:
+ FILE * fp;
+} ;
+
+ostream &
+ostream::operator<<(char ch) {
+ fputc(ch, fp);
+ return *this;
+}
+
+ostream &
+ostream::operator<<(const char * str) {
+ fputs(str, fp);
+ return *this;
+}
+
+ostream &
+ostream::write(const char * buf, unsigned ) {
+ fputs(buf, fp);
+ return *this;
+}
+
+static ostream cerr(stderr);
+static ostream cout(stdout);
+
+#endif /* USE_STDIO */
+
+// ************************************************************** OptIter
+
+OptIter::~OptIter(void) {}
+
+const char *
+OptIter::operator()(void) {
+ const char * elt = curr();
+ (void) next();
+ return elt;
+}
+
+// ************************************************************** OptIterRwd
+
+OptIterRwd::OptIterRwd(void) {}
+
+OptIterRwd::~OptIterRwd(void) {}
+
+// ************************************************************** OptArgvIter
+
+OptArgvIter::~OptArgvIter(void) {}
+
+const char *
+OptArgvIter::curr(void) {
+ return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx];
+}
+
+void
+OptArgvIter::next(void) {
+ if ((ndx != ac) && av[ndx]) ++ndx;
+}
+
+const char *
+OptArgvIter::operator()(void) {
+ return ((ndx == ac) || (av[ndx] == NULL)) ? NULLSTR : av[ndx++];
+}
+
+void
+OptArgvIter::rewind(void) { ndx = 0; }
+
+// ************************************************************** OptStrTokIter
+
+static const char WHITESPACE[] = " \t\n\r\v\f" ;
+const char * OptStrTokIter::default_delims = WHITESPACE ;
+
+OptStrTokIter::OptStrTokIter(const char * tokens, const char * delimiters)
+ : len(unsigned(strlen(tokens))), str(tokens), seps(delimiters),
+ cur(NULLSTR), tokstr(NULLSTR)
+{
+ if (seps == NULL) seps = default_delims;
+ tokstr = new char[len + 1];
+ (void) ::strcpy(tokstr, str);
+ cur = ::strtok(tokstr, seps);
+}
+
+
+OptStrTokIter::~OptStrTokIter(void) { delete [] tokstr; }
+
+const char *
+OptStrTokIter::curr(void) { return cur; }
+
+void
+OptStrTokIter::next(void) { if (cur) cur = ::strtok(NULL, seps); }
+
+const char *
+OptStrTokIter::operator()(void) {
+ const char * elt = cur;
+ if (cur) cur = ::strtok(NULL, seps);
+ return elt;
+}
+
+void
+OptStrTokIter::rewind(void) {
+ (void) ::strcpy(tokstr, str);
+ cur = ::strtok(tokstr, seps);
+}
+
+// ************************************************************* OptIstreamIter
+
+#ifdef vms
+ enum { c_COMMENT = '!' } ;
+#else
+ enum { c_COMMENT = '#' } ;
+#endif
+
+const unsigned OptIstreamIter::MAX_LINE_LEN = 1024 ;
+
+ // Constructor
+OptIstreamIter::OptIstreamIter(istream & input) : is(input), tok_iter(NULL)
+{
+#ifdef USE_STDIO
+ fprintf(stderr, "%s: Can't use OptIstreamIter class:\n",
+ "OptIstreamIter::OptIstreamIter");
+ fprintf(stderr, "\tOptions(3C++) was compiled with USE_STDIO #defined.\n");
+ exit(-1);
+#endif /* USE_STDIO */
+}
+
+ // Destructor
+OptIstreamIter::~OptIstreamIter(void) {
+ delete tok_iter;
+}
+
+const char *
+OptIstreamIter::curr(void) {
+#ifdef USE_STDIO
+ return NULLSTR;
+#else
+ const char * result = NULLSTR;
+ if (tok_iter) result = tok_iter->curr();
+ if (result) return result;
+ fill();
+ return (! is) ? NULLSTR : tok_iter->curr();
+#endif /* USE_STDIO */
+}
+
+void
+OptIstreamIter::next(void) {
+#ifdef USE_STDIO
+ return;
+#else
+ const char * result = NULLSTR;
+ if (tok_iter) result = tok_iter->operator()();
+ if (result) return;
+ fill();
+ if (! is) tok_iter->next();
+#endif /* USE_STDIO */
+}
+
+const char *
+OptIstreamIter::operator()(void) {
+#ifdef USE_STDIO
+ return NULLSTR;
+#else
+ const char * result = NULLSTR;
+ if (tok_iter) result = tok_iter->operator()();
+ if (result) return result;
+ fill();
+ return (! is) ? NULLSTR : tok_iter->operator()();
+#endif /* USE_STDIO */
+}
+
+ // What we do is this: for each line of text in the istream, we use
+ // a OptStrTokIter to iterate over each token on the line.
+ //
+ // If the first non-white character on a line is c_COMMENT, then we
+ // consider the line to be a comment and we ignore it.
+ //
+void
+OptIstreamIter::fill(void) {
+#ifdef USE_STDIO
+ return;
+#else
+ char buf[OptIstreamIter::MAX_LINE_LEN];
+ do {
+ *buf = '\0';
+ is.getline(buf, sizeof(buf));
+ char * ptr = buf;
+ while (isspace(*ptr)) ++ptr;
+ if (*ptr && (*ptr != c_COMMENT)) {
+ delete tok_iter;
+ tok_iter = new OptStrTokIter(ptr);
+ return;
+ }
+ } while (is);
+#endif /* USE_STDIO */
+}
+
+// **************************************************** Options class utilities
+
+ // Is this option-char null?
+inline static int
+isNullOpt(char optchar) {
+ return ((! optchar) || isspace(optchar) || (! isprint(optchar)));
+}
+
+ // Check for explicit "end-of-options"
+inline static int
+isEndOpts(const char * token) {
+ return ((token == NULL) || (! ::strcmp(token, "--"))) ;
+}
+
+ // See if an argument is an option
+inline static int
+isOption(unsigned flags, const char * arg) {
+ return (((*arg != '\0') || (arg[1] != '\0')) &&
+ ((*arg == '-') || ((flags & Options::PLUS) && (*arg == '+')))) ;
+}
+
+ // See if we should be parsing only options or if we also need to
+ // parse positional arguments
+inline static int
+isOptsOnly(unsigned flags) {
+ return (flags & Options::PARSE_POS) ? 0 : 1;
+}
+
+ // return values for a keyword matching function
+enum kwdmatch_t { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } ;
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: kwdmatch - match a keyword
+//
+// ^SYNOPSIS:
+// static kwdmatch_t kwdmatch(src, attempt, len)
+//
+// ^PARAMETERS:
+// char * src -- the actual keyword to match
+// char * attempt -- the possible keyword to compare against "src"
+// int len -- number of character of "attempt" to consider
+// (if 0 then we should use all of "attempt")
+//
+// ^DESCRIPTION:
+// See if "attempt" matches some prefix of "src" (case insensitive).
+//
+// ^REQUIREMENTS:
+// - attempt should be non-NULL and non-empty
+//
+// ^SIDE-EFFECTS:
+// None.
+//
+// ^RETURN-VALUE:
+// An enumeration value of type kwdmatch_t corresponding to whether
+// We had an exact match, a partial match, or no match.
+//
+// ^ALGORITHM:
+// Trivial
+// ^^-------------------------------------------------------------------------
+static kwdmatch_t
+kwdmatch(const char * src, const char * attempt, int len =0) {
+ int i;
+
+ if (src == attempt) return EXACT_MATCH ;
+ if ((src == NULL) || (attempt == NULL)) return NO_MATCH ;
+ if ((! *src) && (! *attempt)) return EXACT_MATCH ;
+ if ((! *src) || (! *attempt)) return NO_MATCH ;
+
+ for (i = 0 ; ((i < len) || (len == 0)) &&
+ (attempt[i]) && (attempt[i] != ' ') ; i++) {
+ if (TOLOWER(src[i]) != TOLOWER(attempt[i])) return NO_MATCH ;
+ }
+
+ return (src[i]) ? PARTIAL_MATCH : EXACT_MATCH ;
+}
+
+// **************************************************************** OptionSpec
+
+ // Class that represents an option-specification
+ // *NOTE*:: Assumes that the char-ptr given to the constructor points
+ // to storage that will NOT be modified and whose lifetime will
+ // be as least as long as the OptionSpec object we construct.
+ //
+class OptionSpec {
+public:
+ OptionSpec(const char * decl =NULLSTR)
+ : hidden(0), spec(decl)
+ {
+ if (spec == NULL) spec = NULL_spec;
+ CheckHidden();
+ }
+
+ OptionSpec(const OptionSpec & cp) : hidden(cp.hidden), spec(cp.spec) {}
+
+ // NOTE: use default destructor!
+
+ // Assign to another OptionSpec
+ OptionSpec &
+ operator=(const OptionSpec & cp) {
+ if (this != &cp) {
+ spec = cp.spec;
+ hidden = cp.hidden;
+ }
+ return *this;
+ }
+
+ // Assign to a string
+ OptionSpec &
+ operator=(const char * decl) {
+ if (spec != decl) {
+ spec = decl;
+ hidden = 0;
+ CheckHidden();
+ }
+ return *this;
+ }
+
+ // Convert to char-ptr by returning the original declaration-string
+ operator const char*() { return isHiddenOpt() ? (spec - 1) : spec; }
+
+ // Is this option NULL?
+ int
+ isNULL(void) const { return ((spec == NULL) || (spec == NULL_spec)); }
+
+ // Is this options incorrectly specified?
+ int
+ isSyntaxError(const char * name) const;
+
+ // See if this is a Hidden option
+ int
+ isHiddenOpt(void) const { return hidden; }
+
+ // Get the corresponding option-character
+ char
+ OptChar(void) const { return *spec; }
+
+ // Get the corresponding long-option string
+ const char *
+ LongOpt(void) const {
+ return (spec[1] && spec[2] && (! isspace(spec[2]))) ? (spec + 2) : NULLSTR;
+ }
+
+ // Does this option require an argument?
+ int
+ isValRequired(void) const {
+ return ((spec[1] == ':') || (spec[1] == '+'));
+ }
+
+ // Does this option take an optional argument?
+ int
+ isValOptional(void) const {
+ return ((spec[1] == '?') || (spec[1] == '*'));
+ }
+
+ // Does this option take no arguments?
+ int
+ isNoArg(void) const {
+ return ((spec[1] == '|') || (! spec[1]));
+ }
+
+ // Can this option take more than one argument?
+ int
+ isList(void) const {
+ return ((spec[1] == '+') || (spec[1] == '*'));
+ }
+
+ // Does this option take any arguments?
+ int
+ isValTaken(void) const {
+ return (isValRequired() || isValOptional()) ;
+ }
+
+ // Format this option in the given buffer
+ unsigned
+ Format(char * buf, unsigned optctrls) const;
+
+private:
+ void
+ CheckHidden(void) {
+ if ((! hidden) && (*spec == '-')) {
+ ++hidden;
+ ++spec;
+ }
+ }
+
+ unsigned hidden : 1; // hidden-flag
+ const char * spec; // string specification
+
+ static const char NULL_spec[];
+} ;
+
+const char OptionSpec::NULL_spec[] = "\0\0\0" ;
+
+int
+OptionSpec::isSyntaxError(const char * name) const {
+ int error = 0;
+ if ((! spec) || (! *spec)) {
+ cerr << name << ": empty option specifier." << endl;
+ cerr << "\tmust be at least 1 character long." << endl;
+ ++error;
+ } else if (spec[1] && (strchr("|?:*+", spec[1]) == NULL)) {
+ cerr << name << ": bad option specifier \"" << spec << "\"." << endl;
+ cerr << "\t2nd character must be in the set \"|?:*+\"." << endl;
+ ++error;
+ }
+ return error;
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: OptionSpec::Format - format an option-spec for a usage message
+//
+// ^SYNOPSIS:
+// unsigned OptionSpec::Format(buf, optctrls) const
+//
+// ^PARAMETERS:
+// char * buf -- where to print the formatted option
+// unsigned optctrls -- option-parsing configuration flags
+//
+// ^DESCRIPTION:
+// Self-explanatory.
+//
+// ^REQUIREMENTS:
+// - buf must be large enough to hold the result
+//
+// ^SIDE-EFFECTS:
+// - writes to buf.
+//
+// ^RETURN-VALUE:
+// Number of characters written to buf.
+//
+// ^ALGORITHM:
+// Follow along in the source - it's not hard but it is tedious!
+// ^^-------------------------------------------------------------------------
+unsigned
+OptionSpec::Format(char * buf, unsigned optctrls) const {
+#ifdef NO_USAGE
+ return (*buf = '\0');
+#else
+ static char default_value[] = "<value>";
+ if (isHiddenOpt()) return (unsigned)(*buf = '\0');
+ char optchar = OptChar();
+ const char * longopt = LongOpt();
+ char * p = buf ;
+
+ const char * value = NULLSTR;
+ int longopt_len = 0;
+ int value_len = 0;
+
+ if (longopt) {
+ value = ::strchr(longopt, ' ');
+ longopt_len = (value) ? (value - longopt) : ::strlen(longopt);
+ } else {
+ value = ::strchr(spec + 1, ' ');
+ }
+ while (value && (*value == ' ')) ++value;
+ if (value && *value) {
+ value_len = ::strlen(value);
+ } else {
+ value = default_value;
+ value_len = sizeof(default_value) - 1;
+ }
+
+ if ((optctrls & Options::SHORT_ONLY) &&
+ ((! isNullOpt(optchar)) || (optctrls & Options::NOGUESSING))) {
+ longopt = NULLSTR;
+ }
+ if ((optctrls & Options::LONG_ONLY) &&
+ (longopt || (optctrls & Options::NOGUESSING))) {
+ optchar = '\0';
+ }
+ if (isNullOpt(optchar) && (longopt == NULL)) {
+ *buf = '\0';
+ return 0;
+ }
+
+ *(p++) = '[';
+
+ // print the single character option
+ if (! isNullOpt(optchar)) {
+ *(p++) = '-';
+ *(p++) = optchar;
+ }
+
+ if ((! isNullOpt(optchar)) && (longopt)) *(p++) = '|';
+
+ // print the long option
+ if (longopt) {
+ *(p++) = '-';
+ if (! (optctrls & (Options::LONG_ONLY | Options::SHORT_ONLY))) {
+ *(p++) = '-';
+ }
+ strncpy(p, longopt, longopt_len);
+ p += longopt_len;
+ }
+
+ // print any argument the option takes
+ if (isValTaken()) {
+ *(p++) = ' ' ;
+ if (isValOptional()) *(p++) = '[' ;
+ strcpy(p, value);
+ p += value_len;
+ if (isList()) {
+ strcpy(p, " ...");
+ p += 4;
+ }
+ if (isValOptional()) *(p++) = ']' ;
+ }
+
+ *(p++) = ']';
+ *p = '\0';
+
+ return (unsigned) strlen(buf);
+#endif /* USE_STDIO */
+}
+
+// ******************************************************************* Options
+
+#if (defined(MSWIN) || defined(OS2) || defined(MSDOS))
+# define DIR_SEP_CHAR '\\'
+#else
+# define DIR_SEP_CHAR '/'
+#endif
+
+Options::Options(const char * name, const char * const optv[])
+ : cmdname(name), optvec(optv), explicit_end(0), optctrls(DEFAULT),
+ nextchar(NULLSTR), listopt(NULLSTR)
+{
+ const char * basename = ::strrchr(cmdname, DIR_SEP_CHAR);
+ if (basename) cmdname = basename + 1;
+ check_syntax();
+}
+
+Options::~Options(void) {}
+
+ // Make sure each option-specifier has correct syntax.
+ //
+ // If there is even one invalid specifier, then exit ungracefully!
+ //
+void
+Options::check_syntax(void) const {
+ int errors = 0;
+ if ((optvec == NULL) || (! *optvec)) return;
+
+ for (const char * const * optv = optvec ; *optv ; optv++) {
+ OptionSpec optspec = *optv;
+ errors += optspec.isSyntaxError(cmdname);
+ }
+ if (errors) exit(127);
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::match_opt - match an option
+//
+// ^SYNOPSIS:
+// const char * match_opt(opt, int ignore_case) const
+//
+// ^PARAMETERS:
+// char opt -- the option-character to match
+// int ignore_case -- should we ignore character-case?
+//
+// ^DESCRIPTION:
+// See if "opt" is found in "optvec"
+//
+// ^REQUIREMENTS:
+// - optvec should be non-NULL and terminated by a NULL pointer.
+//
+// ^SIDE-EFFECTS:
+// None.
+//
+// ^RETURN-VALUE:
+// NULL if no match is found,
+// otherwise a pointer to the matching option-spec.
+//
+// ^ALGORITHM:
+// foreach option-spec
+// - see if "opt" is a match, if so return option-spec
+// end-for
+// ^^-------------------------------------------------------------------------
+const char *
+Options::match_opt(char opt, int ignore_case) const {
+ if ((optvec == NULL) || (! *optvec)) return NULLSTR;
+
+ for (const char * const * optv = optvec ; *optv ; optv++) {
+ OptionSpec optspec = *optv;
+ char optchar = optspec.OptChar();
+ if (isNullOpt(optchar)) continue;
+ if (opt == optchar) {
+ return optspec;
+ } else if (ignore_case && (TOLOWER(opt) == TOLOWER(optchar))) {
+ return optspec;
+ }
+ }
+
+ return NULLSTR; // not found
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::match_longopt - match a long-option
+//
+// ^SYNOPSIS:
+// const char * Options::match_longopt(opt, len, ambiguous)
+//
+// ^PARAMETERS:
+// char * opt -- the long-option to match
+// int len -- the number of character of "opt" to match
+// int & ambiguous -- set by this routine before returning.
+//
+// ^DESCRIPTION:
+// Try to match "opt" against some unique prefix of a long-option
+// (case insensitive).
+//
+// ^REQUIREMENTS:
+// - optvec should be non-NULL and terminated by a NULL pointer.
+//
+// ^SIDE-EFFECTS:
+// - *ambiguous is set to '1' if "opt" matches >1 long-option
+// (otherwise it is set to 0).
+//
+// ^RETURN-VALUE:
+// NULL if no match is found,
+// otherwise a pointer to the matching option-spec.
+//
+// ^ALGORITHM:
+// ambiguous is FALSE
+// foreach option-spec
+// if we have an EXACT-MATCH, return the option-spec
+// if we have a partial-match then
+// if we already had a previous partial match then
+// set ambiguous = TRUE and return NULL
+// else
+// remember this options spec and continue matching
+// end-if
+// end-if
+// end-for
+// if we had exactly 1 partial match return it, else return NULL
+// ^^-------------------------------------------------------------------------
+const char *
+Options::match_longopt(const char * opt, int len, int & ambiguous) const {
+ kwdmatch_t result;
+ const char * matched = NULLSTR ;
+
+ ambiguous = 0;
+ if ((optvec == NULL) || (! *optvec)) return NULLSTR;
+
+ for (const char * const * optv = optvec ; *optv ; optv++) {
+ OptionSpec optspec = *optv;
+ const char * longopt = optspec.LongOpt();
+ if (longopt == NULL) continue;
+ result = kwdmatch(longopt, opt, len);
+ if (result == EXACT_MATCH) {
+ return optspec;
+ } else if (result == PARTIAL_MATCH) {
+ if (matched) {
+ ++ambiguous;
+ return NULLSTR;
+ } else {
+ matched = optspec;
+ }
+ }
+ }//for
+
+ return matched;
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::parse_opt - parse an option
+//
+// ^SYNOPSIS:
+// int Options::parse_opt(iter, optarg)
+//
+// ^PARAMETERS:
+// OptIter & iter -- option iterator
+// const char * & optarg -- where to store any option-argument
+//
+// ^DESCRIPTION:
+// Parse the next option in iter (advancing as necessary).
+// Make sure we update the nextchar pointer along the way. Any option
+// we find should be returned and optarg should point to its argument.
+//
+// ^REQUIREMENTS:
+// - nextchar must point to the prospective option character
+//
+// ^SIDE-EFFECTS:
+// - iter is advanced when an argument completely parsed
+// - optarg is modified to point to any option argument
+// - if Options::QUIET is not set, error messages are printed on cerr
+//
+// ^RETURN-VALUE:
+// 'c' if the -c option was matched (optarg points to its argument)
+// BADCHAR if the option is invalid (optarg points to the bad
+// option-character).
+//
+// ^ALGORITHM:
+// It gets complicated -- follow the comments in the source.
+// ^^-------------------------------------------------------------------------
+int
+Options::parse_opt(OptIter & iter, const char * & optarg) {
+ listopt = NULLSTR; // reset the list pointer
+
+ if ((optvec == NULL) || (! *optvec)) return Options::ENDOPTS;
+
+ // Try to match a known option
+ OptionSpec optspec = match_opt(*(nextchar++), (optctrls & Options::ANYCASE));
+
+ // Check for an unknown option
+ if (optspec.isNULL()) {
+ // See if this was a long-option in disguise
+ if (! (optctrls & Options::NOGUESSING)) {
+ unsigned save_ctrls = optctrls;
+ const char * save_nextchar = nextchar;
+ nextchar -= 1;
+ optctrls |= (Options::QUIET | Options::NOGUESSING);
+ int optchar = parse_longopt(iter, optarg);
+ optctrls = save_ctrls;
+ if (optchar > 0) {
+ return optchar;
+ } else {
+ nextchar = save_nextchar;
+ }
+ }
+ if (! (optctrls & Options::QUIET)) {
+ cerr << cmdname << ": unknown option -"
+ << *(nextchar - 1) << "." << endl ;
+ }
+ optarg = (nextchar - 1); // record the bad option in optarg
+ return Options::BADCHAR;
+ }
+
+ // If no argument is taken, then leave now
+ if (optspec.isNoArg()) {
+ optarg = NULLSTR;
+ return optspec.OptChar();
+ }
+
+ // Check for argument in this arg
+ if (*nextchar) {
+ optarg = nextchar; // the argument is right here
+ nextchar = NULLSTR; // we've exhausted this arg
+ if (optspec.isList()) listopt = optspec ; // save the list-spec
+ return optspec.OptChar();
+ }
+
+ // Check for argument in next arg
+ const char * nextarg = iter.curr();
+ if ((nextarg != NULL) &&
+ (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
+ optarg = nextarg; // the argument is here
+ iter.next(); // end of arg - advance
+ if (optspec.isList()) listopt = optspec ; // save the list-spec
+ return optspec.OptChar();
+ }
+
+ // No argument given - if its required, thats an error
+ optarg = NULLSTR;
+ if (optspec.isValRequired() && !(optctrls & Options::QUIET)) {
+ cerr << cmdname << ": argument required for -" << optspec.OptChar()
+ << " option." << endl ;
+ }
+ return optspec.OptChar();
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::parse_longopt - parse a long-option
+//
+// ^SYNOPSIS:
+// int Options::parse_longopt(iter, optarg)
+//
+// ^PARAMETERS:
+// OptIter & iter -- option iterator
+// const char * & optarg -- where to store any option-argument
+//
+// ^DESCRIPTION:
+// Parse the next long-option in iter (advancing as necessary).
+// Make sure we update the nextchar pointer along the way. Any option
+// we find should be returned and optarg should point to its argument.
+//
+// ^REQUIREMENTS:
+// - nextchar must point to the prospective option character
+//
+// ^SIDE-EFFECTS:
+// - iter is advanced when an argument completely parsed
+// - optarg is modified to point to any option argument
+// - if Options::QUIET is not set, error messages are printed on cerr
+//
+// ^RETURN-VALUE:
+// 'c' if the the long-option corresponding to the -c option was matched
+// (optarg points to its argument)
+// BADKWD if the option is invalid (optarg points to the bad long-option
+// name).
+//
+// ^ALGORITHM:
+// It gets complicated -- follow the comments in the source.
+// ^^-------------------------------------------------------------------------
+int
+Options::parse_longopt(OptIter & iter, const char * & optarg) {
+ int len = 0, ambiguous = 0;
+
+ listopt = NULLSTR ; // reset the list-spec
+
+ if ((optvec == NULL) || (! *optvec)) return Options::ENDOPTS;
+
+ // if a value is supplied in this argv element, get it now
+ const char * val = strpbrk(nextchar, ":=") ;
+ if (val) {
+ len = val - nextchar ;
+ ++val ;
+ }
+
+ // Try to match a known long-option
+ OptionSpec optspec = match_longopt(nextchar, len, ambiguous);
+
+ // Check for an unknown long-option
+ if (optspec.isNULL()) {
+ // See if this was a short-option in disguise
+ if ((! ambiguous) && (! (optctrls & Options::NOGUESSING))) {
+ unsigned save_ctrls = optctrls;
+ const char * save_nextchar = nextchar;
+ optctrls |= (Options::QUIET | Options::NOGUESSING);
+ int optchar = parse_opt(iter, optarg);
+ optctrls = save_ctrls;
+ if (optchar > 0) {
+ return optchar;
+ } else {
+ nextchar = save_nextchar;
+ }
+ }
+ if (! (optctrls & Options::QUIET)) {
+ cerr << cmdname << ": " << ((ambiguous) ? "ambiguous" : "unknown")
+ << " option "
+ << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
+ << nextchar << "." << endl ;
+ }
+ optarg = nextchar; // record the bad option in optarg
+ nextchar = NULLSTR; // we've exhausted this argument
+ return (ambiguous) ? Options::AMBIGUOUS : Options::BADKWD;
+ }
+
+ // If no argument is taken, then leave now
+ if (optspec.isNoArg()) {
+ if ((val) && ! (optctrls & Options::QUIET)) {
+ cerr << cmdname << ": option "
+ << ((optctrls & Options::LONG_ONLY) ? "-" : "--")
+ << optspec.LongOpt() << " does NOT take an argument." << endl ;
+ }
+ optarg = val; // record the unexpected argument
+ nextchar = NULLSTR; // we've exhausted this argument
+ return optspec.OptChar();
+ }
+
+ // Check for argument in this arg
+ if (val) {
+ optarg = val; // the argument is right here
+ nextchar = NULLSTR; // we exhausted the rest of this arg
+ if (optspec.isList()) listopt = optspec ; // save the list-spec
+ return optspec.OptChar();
+ }
+
+ // Check for argument in next arg
+ const char * nextarg = iter.curr(); // find the next argument to parse
+ if ((nextarg != NULL) &&
+ (optspec.isValRequired() || (! isOption(optctrls, nextarg)))) {
+ optarg = nextarg; // the argument is right here
+ iter.next(); // end of arg - advance
+ nextchar = NULLSTR; // we exhausted the rest of this arg
+ if (optspec.isList()) listopt = optspec ; // save the list-spec
+ return optspec.OptChar();
+ }
+
+ // No argument given - if its required, thats an error
+ optarg = NULLSTR;
+ if (optspec.isValRequired() && !(optctrls & Options::QUIET)) {
+ const char * longopt = optspec.LongOpt();
+ const char * spc = ::strchr(longopt, ' ');
+ int longopt_len;
+ if (spc) {
+ longopt_len = spc - longopt;
+ } else {
+ longopt_len = ::strlen(longopt);
+ }
+ cerr << cmdname << ": argument required for "
+ << ((optctrls & Options::LONG_ONLY) ? "-" : "--");
+ cerr.write(longopt, longopt_len) << " option." << endl ;
+ }
+ nextchar = NULLSTR; // we exhausted the rest of this arg
+ return optspec.OptChar();
+}
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::usage - print usage
+//
+// ^SYNOPSIS:
+// void Options::usage(os, positionals)
+//
+// ^PARAMETERS:
+// ostream & os -- where to print the usage
+// char * positionals -- command-line syntax for any positional args
+//
+// ^DESCRIPTION:
+// Print command-usage (using either option or long-option syntax) on os.
+//
+// ^REQUIREMENTS:
+// os should correspond to an open output file.
+//
+// ^SIDE-EFFECTS:
+// Prints on os
+//
+// ^RETURN-VALUE:
+// None.
+//
+// ^ALGORITHM:
+// Print usage on os, wrapping long lines where necessary.
+// ^^-------------------------------------------------------------------------
+void
+Options::usage(ostream & os, const char * positionals) const {
+#ifdef NO_USAGE
+ return;
+#else
+ const char * const * optv = optvec;
+ unsigned cols = 79;
+ int first, nloop;
+ char buf[256] ;
+
+ if ((optv == NULL) || (! *optv)) return;
+
+ // print first portion "usage: progname"
+ os << "usage: " << cmdname ;
+ unsigned ll = strlen(cmdname) + 7;
+
+ // save the current length so we know how much space to skip for
+ // subsequent lines.
+ //
+ unsigned margin = ll + 1;
+
+ // print the options and the positional arguments
+ for (nloop = 0, first = 1 ; !nloop ; optv++, first = 0) {
+ unsigned len;
+ OptionSpec optspec = *optv;
+
+ // figure out how wide this parameter is (for printing)
+ if (! *optv) {
+ len = strlen(positionals);
+ ++nloop; // terminate this loop
+ } else {
+ if (optspec.isHiddenOpt()) continue;
+ len = optspec.Format(buf, optctrls);
+ }
+
+ // Will this fit?
+ if ((ll + len + 1) > (cols - first)) {
+ os << '\n' ; // No - start a new line;
+#ifdef USE_STDIO
+ for (int _i_ = 0; _i_ < margin; ++_i_) os << " ";
+#else
+ os.width(margin); os << "" ;
+#endif
+ ll = margin;
+ } else {
+ os << ' ' ; // Yes - just throw in a space
+ ++ll;
+ }
+ ll += len;
+ os << ((nloop) ? positionals : buf) ;
+ }// for each ad
+
+ os << endl ;
+#endif /* NO_USAGE */
+}
+
+
+// ---------------------------------------------------------------------------
+// ^FUNCTION: Options::operator() - get options from the command-line
+//
+// ^SYNOPSIS:
+// int Options::operator()(iter, optarg)
+//
+// ^PARAMETERS:
+// OptIter & iter -- option iterator
+// const char * & optarg -- where to store any option-argument
+//
+// ^DESCRIPTION:
+// Parse the next option in iter (advancing as necessary).
+// Make sure we update the nextchar pointer along the way. Any option
+// we find should be returned and optarg should point to its argument.
+//
+// ^REQUIREMENTS:
+// None.
+//
+// ^SIDE-EFFECTS:
+// - iter is advanced when an argument is completely parsed
+// - optarg is modified to point to any option argument
+// - if Options::QUIET is not set, error messages are printed on cerr
+//
+// ^RETURN-VALUE:
+// 0 if all options have been parsed.
+// 'c' if the the option or long-option corresponding to the -c option was
+// matched (optarg points to its argument).
+// BADCHAR if the option is invalid (optarg points to the bad option char).
+// BADKWD if the option is invalid (optarg points to the bad long-opt name).
+// AMBIGUOUS if an ambiguous keyword name was given (optarg points to the
+// ambiguous keyword name).
+// POSITIONAL if PARSE_POS was set and the current argument is a positional
+// parameter (in which case optarg points to the positional argument).
+//
+// ^ALGORITHM:
+// It gets complicated -- follow the comments in the source.
+// ^^-------------------------------------------------------------------------
+int
+Options::operator()(OptIter & iter, const char * & optarg) {
+ int parse_opts_only = isOptsOnly(optctrls);
+ if (parse_opts_only) explicit_end = 0;
+
+ // See if we have an option left over from before ...
+ if ((nextchar) && *nextchar) {
+ return parse_opt(iter, optarg);
+ }
+
+ // Check for end-of-options ...
+ const char * arg = NULLSTR;
+ int get_next_arg = 0;
+ do {
+ arg = iter.curr();
+ get_next_arg = 0;
+ if (arg == NULL) {
+ listopt = NULLSTR;
+ return Options::ENDOPTS;
+ } else if ((! explicit_end) && isEndOpts(arg)) {
+ iter.next(); // advance past end-of-options arg
+ listopt = NULLSTR;
+ explicit_end = 1;
+ if (parse_opts_only) return Options::ENDOPTS;
+ get_next_arg = 1; // make sure we look at the next argument.
+ }
+ } while (get_next_arg);
+
+ // Do we have a positional arg?
+ if ( explicit_end || (! isOption(optctrls, arg)) ) {
+ if (parse_opts_only) {
+ return Options::ENDOPTS;
+ } else {
+ optarg = arg; // set optarg to the positional argument
+ iter.next(); // advance iterator to the next argument
+ return Options::POSITIONAL;
+ }
+ }
+
+ iter.next(); // pass the argument that arg already points to
+
+ // See if we have a long option ...
+ if (! (optctrls & Options::SHORT_ONLY)) {
+ if ((*arg == '-') && (arg[1] == '-')) {
+ nextchar = arg + 2;
+ return parse_longopt(iter, optarg);
+ } else if ((optctrls & Options::PLUS) && (*arg == '+')) {
+ nextchar = arg + 1;
+ return parse_longopt(iter, optarg);
+ }
+ }
+ if (*arg == '-') {
+ nextchar = arg + 1;
+ if (optctrls & Options::LONG_ONLY) {
+ return parse_longopt(iter, optarg);
+ } else {
+ return parse_opt(iter, optarg);
+ }
+ }
+
+ // If we get here - it is because we have a list value
+ OptionSpec optspec = listopt;
+ optarg = arg ; // record the list value
+ return optspec.OptChar() ;
+}
+
diff --git a/common/options.h b/common/options.h
new file mode 100644
index 0000000..0c4e49c
--- /dev/null
+++ b/common/options.h
@@ -0,0 +1,488 @@
+// ****************************************************************************
+// ^FILE: options.h - option parsing classes
+//
+// ^DESCRIPTION:
+// This file defines classes used to parse command-line options.
+// Options may be parsed from an array of strings, or from any structure
+// for which a corresponding option-iterator exists.
+//
+// ^HISTORY:
+// 03/06/92 Brad Appleton <bradapp@enteract.com> Created
+//
+// 03/23/93 Brad Appleton <bradapp@enteract.com>
+// - Added OptIstreamIter class
+//
+// 03/08/94 Brad Appleton <bradapp@enteract.com>
+// - Added Options::reset() member function
+//
+// 07/31/97 Brad Appleton <bradapp@enteract.com>
+// - Added PARSE_POS control flag and POSITIONAL return value
+//
+// 04/30/06 Chris Reed
+// - Updated to modern C++ and STL
+// - Converted comments to doxygen style
+// ^^**************************************************************************
+
+#ifndef _options_h
+#define _options_h
+
+#ifdef USE_STDIO
+ #include <stdio.h>
+#else
+ #include <iostream>
+#endif
+
+
+//! Abstract class to iterate through options/arguments
+//!
+class OptIter {
+public:
+ OptIter(void) {}
+ virtual ~OptIter(void);
+
+ //! curr() returns the current item in the iterator without
+ //! advancing on to the next item. If we are at the end of items
+ //! then NULL is returned.
+ virtual const char *
+ curr(void) = 0;
+
+ //! next() advances to the next item.
+ virtual void
+ next(void) = 0;
+
+ //! operator() returns the current item in the iterator and then
+ //! advances on to the next item. If we are at the end of items
+ //! then NULL is returned.
+ virtual const char *
+ operator()(void);
+} ;
+
+//! Abstract class for a rewindable OptIter
+//!
+class OptIterRwd : public OptIter {
+public:
+ OptIterRwd(void);
+
+ virtual ~OptIterRwd(void);
+
+ virtual const char *
+ curr(void) = 0;
+
+ virtual void
+ next(void) = 0;
+
+ virtual const char *
+ operator()(void) = 0;
+
+ //! rewind() resets the "current-element" to the first one in the "list"
+ virtual void
+ rewind(void) = 0;
+} ;
+
+//! Class to iterate through an array of tokens. The array may be terminated
+//! by NULL or a count containing the number of tokens may be given.
+//!
+class OptArgvIter : public OptIterRwd {
+private:
+ int ndx; // index of current arg
+ int ac; // arg count
+ const char * const * av; // arg vector
+
+public:
+ OptArgvIter(const char * const argv[])
+ : av(argv), ac(-1), ndx(0) {}
+
+ OptArgvIter(int argc, const char * const argv[])
+ : av(argv), ac(argc), ndx(0) {}
+
+ virtual
+ ~OptArgvIter(void);
+
+ virtual const char *
+ curr(void);
+
+ virtual void
+ next(void);
+
+ virtual const char *
+ operator()(void);
+
+ virtual void
+ rewind(void);
+
+ //! index returns the current index to use for argv[]
+ int index(void) { return ndx; }
+} ;
+
+
+//! Class to iterate through a string containing delimiter-separated tokens
+//!
+class OptStrTokIter : public OptIterRwd {
+private:
+ unsigned len; // length of token-string
+ const char * str; // the token-string
+ const char * seps; // delimiter-set (separator-characters)
+ const char * cur; // current token
+ char * tokstr; // our copy of the token-string
+
+ static const char * default_delims; // default delimiters = whitespace
+
+public:
+ OptStrTokIter(const char * tokens, const char * delimiters =0);
+
+ virtual
+ ~OptStrTokIter(void);
+
+ virtual const char *
+ curr(void);
+
+ virtual void
+ next(void);
+
+ virtual const char *
+ operator()(void);
+
+ virtual void
+ rewind(void);
+
+ //! delimiters() with NO arguments returns the current set of delimiters,
+ //! If an argument is given then it is used as the new set of delimiters.
+ const char *
+ delimiters(void) { return seps; }
+
+ void
+ delimiters(const char * delims) {
+ seps = (delims) ? delims : default_delims ;
+ }
+} ;
+
+
+//! OptIstreamIter is a class for iterating over arguments that come
+//! from an input stream. Each line of the input stream is considered
+//! to be a set of white-space separated tokens. If the the first
+//! non-white character on a line is '#' ('!' for VMS systems) then
+//! the line is considered a comment and is ignored.
+//!
+//! \note If a line is more than 1022 characters in length then we
+//! treat it as if it were several lines of length 1022 or less.
+//!
+//! \note The string tokens returned by this iterator are pointers
+//! to temporary buffers which may not necessarily stick around
+//! for too long after the call to curr() or operator(), hence
+//! if you need the string value to persist - you will need to
+//! make a copy.
+//!
+class OptIstreamIter : public OptIter {
+private:
+ std::istream & is ;
+ OptStrTokIter * tok_iter ;
+
+ void
+ fill(void);
+
+public:
+ static const unsigned MAX_LINE_LEN ;
+
+ OptIstreamIter(std::istream & input);
+
+ virtual
+ ~OptIstreamIter(void);
+
+ virtual const char *
+ curr(void);
+
+ virtual void
+ next(void);
+
+ virtual const char *
+ operator()(void);
+} ;
+
+
+//! \brief parse command-line options
+//!
+//! \section Synopsis
+//! \code
+//! #include <options.h>
+//!
+//! Options opts(cmdname, optv);
+//! char cmdname[], *optv[];
+//! \endcode
+//! \section Description
+//! The Options constructor expects a command-name (usually argv[0]) and
+//! a pointer to an array of strings. The last element in this array MUST
+//! be NULL. Each non-NULL string in the array must have the following format:
+//!
+//! The 1st character must be the option-name ('c' for a -c option).
+//!
+//! The 2nd character must be one of '|', '?', ':', '*', or '+'.
+//! '|' -- indicates that the option takes NO argument;
+//! '?' -- indicates that the option takes an OPTIONAL argument;
+//! ':' -- indicates that the option takes a REQUIRED argument;
+//! '*' -- indicates that the option takes 0 or more arguments;
+//! '+' -- indicates that the option takes 1 or more arguments;
+//!
+//! The remainder of the string must be the long-option name.
+//!
+//! If desired, the long-option name may be followed by one or more
+//! spaces and then by the name of the option value. This name will
+//! be used when printing usage messages. If the option-value-name
+//! is not given then the string "<value>" will be used in usage
+//! messages.
+//!
+//! One may use a space to indicate that a particular option does not
+//! have a corresponding long-option. For example, "c: " (or "c:")
+//! means the -c option takes a value & has NO corresponding long-option.
+//!
+//! To specify a long-option that has no corresponding single-character
+//! option is a bit trickier: Options::operator() still needs an "option-
+//! character" to return when that option is matched. One may use a whitespace
+//! character or a non-printable character as the single-character option
+//! in such a case. (hence " |hello" would only match "--hello").
+//!
+//! \section Exceptions Exceptions to the above
+//! If the 1st character of the string is '-', then the rest of the
+//! string must correspond to the above format, and the option is
+//! considered to be a hidden-option. This means it will be parsed
+//! when actually matching options from the command-line, but will
+//! NOT show-up if a usage message is printed using the usage() member
+//! function. Such an example might be "-h|hidden". If you want to
+//! use any "dummy" options (options that are not parsed, but that
+//! to show up in the usage message), you can specify them along with
+//! any positional parameters to the usage() member function.
+//!
+//! If the 2nd character of the string is '\0' then it is assumed
+//! that there is no corresponding long-option and that the option
+//! takes no argument (hence "f", and "f| " are equivalent).
+//!
+//! \code
+//! const char * optv[] = {
+//! "c:count <number>",
+//! "s?str <string>",
+//! "x",
+//! " |hello",
+//! "g+groups <newsgroup>",
+//! NULL
+//! } ;
+//! \endcode
+//! optv[] now corresponds to the following:
+//!
+//! usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
+//! [-x] [--hello] [-g|--groups <newsgroup> ...]
+//!
+//! Long-option names are matched case-insensitive and only a unique prefix
+//! of the name needs to be specified.
+//!
+//! Option-name characters are case-sensitive!
+//!
+//! \section Caveat
+//! Because of the way in which multi-valued options and options with optional
+//! values are handled, it is NOT possible to supply a value to an option in
+//! a separate argument (different argv[] element) if the value is OPTIONAL
+//! and begins with a '-'. What this means is that if an option "-s" takes an
+//! optional value value and you wish to supply a value of "-foo" then you must
+//! specify this on the command-line as "-s-foo" instead of "-s -foo" because
+//! "-s -foo" will be considered to be two separate sets of options.
+//!
+//! A multi-valued option is terminated by another option or by the end-of
+//! options. The following are all equivalent (if "-l" is a multi-valued
+//! option and "-x" is an option that takes no value):
+//!
+//! cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
+//! cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
+//! cmdname -l item1 item2 item3 -x arg1 arg2 arg3
+//!
+//!
+//! \code
+//! #include <options.h>
+//!
+//! static const char * optv[] = {
+//! "H|help",
+//! "c:count <number>",
+//! "s?str <string>",
+//! "x",
+//! " |hello",
+//! "g+groups <newsgroup>",
+//! NULL
+//! } ;
+//!
+//! main(int argc, char * argv[]) {
+//! int optchar;
+//! const char * optarg;
+//! const char * str = "default_string";
+//! int count = 0, xflag = 0, hello = 0;
+//! int errors = 0, ngroups = 0;
+//!
+//! Options opts(*argv, optv);
+//! OptArgvIter iter(--argc, ++argv);
+//!
+//! while( optchar = opts(iter, optarg) ) {
+//! switch (optchar) {
+//! case 'H' :
+//! opts.usage(cout, "files ...");
+//! exit(0);
+//! break;
+//! case 'g' :
+//! ++ngroups; break; //! the groupname is in "optarg"
+//! case 's' :
+//! str = optarg; break;
+//! case 'x' :
+//! ++xflag; break;
+//! case ' ' :
+//! ++hello; break;
+//! case 'c' :
+//! if (optarg == NULL) ++errors;
+//! else count = (int) atol(optarg);
+//! break;
+//! default : ++errors; break;
+//! } //!switch
+//! }
+//!
+//! if (errors || (iter.index() == argc)) {
+//! if (! errors) {
+//! cerr << opts.name() << ": no filenames given." << endl ;
+//! }
+//! opts.usage(cerr, "files ...");
+//! exit(1);
+//! }
+//!
+//! cout << "xflag=" << ((xflag) ? "ON" : "OFF") << endl
+//! << "hello=" << ((hello) ? "YES" : "NO") << endl
+//! << "count=" << count << endl
+//! << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
+//! << "ngroups=" << ngroups << endl ;
+//!
+//! if (iter.index() < argc) {
+//! cout << "files=" ;
+//! for (int i = iter.index() ; i < argc ; i++) {
+//! cout << "\"" << argv[i] << "\" " ;
+//! }
+//! cout << endl ;
+//! }
+//! }
+//! \endcode
+class Options {
+private:
+ unsigned explicit_end : 1; //!< were we terminated because of "--"?
+ unsigned optctrls : 7; //!< control settings (a set of OptCtrl masks)
+ const char * const * optvec; //!< vector of option-specifications (last=NULL)
+ const char * nextchar; //!< next option-character to process
+ const char * listopt; //!< last list-option we matched
+ const char * cmdname; //!< name of the command
+
+ void
+ check_syntax(void) const;
+
+ const char *
+ match_opt(char opt, int ignore_case =0) const;
+
+ const char *
+ match_longopt(const char * opt, int len, int & ambiguous) const;
+
+ int
+ parse_opt(OptIter & iter, const char * & optarg);
+
+ int
+ parse_longopt(OptIter & iter, const char * & optarg);
+
+public:
+ enum OptCtrl {
+ DEFAULT = 0x00, //!< Default setting
+ ANYCASE = 0x01, //!< Ignore case when matching short-options
+ QUIET = 0x02, //!< Dont print error messages
+ PLUS = 0x04, //!< Allow "+" as a long-option prefix
+ SHORT_ONLY = 0x08, //!< Dont accept long-options
+ LONG_ONLY = 0x10, //!< Dont accept short-options
+ //!< (also allows "-" as a long-option prefix).
+ NOGUESSING = 0x20, //!< Normally, when we see a short (long) option
+ //!< on the command line that doesnt match any
+ //!< known short (long) options, then we try to
+ //!< "guess" by seeing if it will match any known
+ //!< long (short) option. Setting this mask prevents
+ //!< this "guessing" from occurring.
+ PARSE_POS = 0x40 //!< By default, Options will not present positional
+ //!< command-line arguments to the user and will
+ //!< instead stop parsing when the first positonal
+ //!< argument has been encountered. If this flag
+ //!< is given, Options will present positional
+ //!< arguments to the user with a return code of
+ //!< POSITIONAL; ENDOPTS will be returned only
+ //!< when the end of the argument list is reached.
+ } ;
+
+ //! Error return values for operator()
+ //!
+ enum OptRC {
+ ENDOPTS = 0,
+ BADCHAR = -1,
+ BADKWD = -2,
+ AMBIGUOUS = -3,
+ POSITIONAL = -4
+ } ;
+
+ Options(const char * name, const char * const optv[]);
+
+ virtual
+ ~Options(void);
+
+ //! name() returns the command name
+ const char *
+ name(void) const { return cmdname; }
+
+ //! ctrls() (with no arguments) returns the existing control settings
+ unsigned
+ ctrls(void) const { return optctrls; }
+
+ //! ctrls() (with 1 argument) sets new control settings
+ void
+ ctrls(unsigned newctrls) { optctrls = newctrls; }
+
+ //! reset for another pass to parse for options
+ void
+ reset(void) { nextchar = listopt = NULL; }
+
+ //! usage() prints options usage (followed by any positional arguments
+ //! listed in the parameter "positionals") on the given outstream
+ void
+ usage(std::ostream & os, const char * positionals) const ;
+
+ //! operator() iterates through the arguments as necessary (using the
+ //! given iterator) and returns the character value of the option
+ //! (or long-option) that it matched. If the option has a value
+ //! then the value given may be found in optarg (otherwise optarg
+ //! will be NULL).
+ //!
+ //! 0 is returned upon end-of-options. At this point, "iter" may
+ //! be used to process any remaining positional parameters. If the
+ //! PARSE_POS control-flag is set then 0 is returned only when all
+ //! arguments in "iter" have been exhausted.
+ //!
+ //! If an invalid option is found then BADCHAR is returned and *optarg
+ //! is the unrecognized option character.
+ //!
+ //! If an invalid long-option is found then BADKWD is returned and optarg
+ //! points to the bad long-option.
+ //!
+ //! If an ambiguous long-option is found then AMBIGUOUS is returned and
+ //! optarg points to the ambiguous long-option.
+ //!
+ //! If the PARSE_POS control-flag is set then POSITIONAL is returned
+ //! when a positional argument is encountered and optarg points to
+ //! the positonal argument (and "iter" is advanced to the next argument
+ //! in the iterator).
+ //!
+ //! Unless Options::QUIET is used, missing option-arguments and
+ //! invalid options (and the like) will automatically cause error
+ //! messages to be issued to cerr.
+ int
+ operator()(OptIter & iter, const char * & optarg) ;
+
+ //! Call this member function after operator() has returned 0
+ //! if you want to know whether or not options were explicitly
+ //! terminated because "--" appeared on the command-line.
+ //!
+ int
+ explicit_endopts() const { return explicit_end; }
+} ;
+
+#endif /* _options_h */
diff --git a/common/rijndael.cpp b/common/rijndael.cpp
new file mode 100644
index 0000000..5708711
--- /dev/null
+++ b/common/rijndael.cpp
@@ -0,0 +1,1604 @@
+//
+// File : rijndael.cpp
+// Creation date : Sun Nov 5 2000 03:22:10 CEST
+// Author : Szymon Stefanek (stefanek@tin.it)
+//
+// Another implementation of the Rijndael cipher.
+// This is intended to be an easily usable library file.
+// This code is public domain.
+// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
+//
+
+//
+// Original Copyright notice:
+//
+// rijndael-alg-fst.c v2.4 April '2000
+// rijndael-alg-fst.h
+// rijndael-api-fst.c
+// rijndael-api-fst.h
+//
+// Optimised ANSI C code
+//
+// authors: v1.0: Antoon Bosselaers
+// v2.0: Vincent Rijmen, K.U.Leuven
+// v2.3: Paulo Barreto
+// v2.4: Vincent Rijmen, K.U.Leuven
+//
+// This code is placed in the public domain.
+//
+
+//
+// This implementation works on 128 , 192 , 256 bit keys
+// and on 128 bit blocks
+//
+
+#define _RIJNDAEL_CPP_
+
+#include "rijndael.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static uint8_t S[256]=
+{
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
+};
+
+
+static uint8_t T1[256][4]=
+{
+ 0xc6,0x63,0x63,0xa5, 0xf8,0x7c,0x7c,0x84, 0xee,0x77,0x77,0x99, 0xf6,0x7b,0x7b,0x8d,
+ 0xff,0xf2,0xf2,0x0d, 0xd6,0x6b,0x6b,0xbd, 0xde,0x6f,0x6f,0xb1, 0x91,0xc5,0xc5,0x54,
+ 0x60,0x30,0x30,0x50, 0x02,0x01,0x01,0x03, 0xce,0x67,0x67,0xa9, 0x56,0x2b,0x2b,0x7d,
+ 0xe7,0xfe,0xfe,0x19, 0xb5,0xd7,0xd7,0x62, 0x4d,0xab,0xab,0xe6, 0xec,0x76,0x76,0x9a,
+ 0x8f,0xca,0xca,0x45, 0x1f,0x82,0x82,0x9d, 0x89,0xc9,0xc9,0x40, 0xfa,0x7d,0x7d,0x87,
+ 0xef,0xfa,0xfa,0x15, 0xb2,0x59,0x59,0xeb, 0x8e,0x47,0x47,0xc9, 0xfb,0xf0,0xf0,0x0b,
+ 0x41,0xad,0xad,0xec, 0xb3,0xd4,0xd4,0x67, 0x5f,0xa2,0xa2,0xfd, 0x45,0xaf,0xaf,0xea,
+ 0x23,0x9c,0x9c,0xbf, 0x53,0xa4,0xa4,0xf7, 0xe4,0x72,0x72,0x96, 0x9b,0xc0,0xc0,0x5b,
+ 0x75,0xb7,0xb7,0xc2, 0xe1,0xfd,0xfd,0x1c, 0x3d,0x93,0x93,0xae, 0x4c,0x26,0x26,0x6a,
+ 0x6c,0x36,0x36,0x5a, 0x7e,0x3f,0x3f,0x41, 0xf5,0xf7,0xf7,0x02, 0x83,0xcc,0xcc,0x4f,
+ 0x68,0x34,0x34,0x5c, 0x51,0xa5,0xa5,0xf4, 0xd1,0xe5,0xe5,0x34, 0xf9,0xf1,0xf1,0x08,
+ 0xe2,0x71,0x71,0x93, 0xab,0xd8,0xd8,0x73, 0x62,0x31,0x31,0x53, 0x2a,0x15,0x15,0x3f,
+ 0x08,0x04,0x04,0x0c, 0x95,0xc7,0xc7,0x52, 0x46,0x23,0x23,0x65, 0x9d,0xc3,0xc3,0x5e,
+ 0x30,0x18,0x18,0x28, 0x37,0x96,0x96,0xa1, 0x0a,0x05,0x05,0x0f, 0x2f,0x9a,0x9a,0xb5,
+ 0x0e,0x07,0x07,0x09, 0x24,0x12,0x12,0x36, 0x1b,0x80,0x80,0x9b, 0xdf,0xe2,0xe2,0x3d,
+ 0xcd,0xeb,0xeb,0x26, 0x4e,0x27,0x27,0x69, 0x7f,0xb2,0xb2,0xcd, 0xea,0x75,0x75,0x9f,
+ 0x12,0x09,0x09,0x1b, 0x1d,0x83,0x83,0x9e, 0x58,0x2c,0x2c,0x74, 0x34,0x1a,0x1a,0x2e,
+ 0x36,0x1b,0x1b,0x2d, 0xdc,0x6e,0x6e,0xb2, 0xb4,0x5a,0x5a,0xee, 0x5b,0xa0,0xa0,0xfb,
+ 0xa4,0x52,0x52,0xf6, 0x76,0x3b,0x3b,0x4d, 0xb7,0xd6,0xd6,0x61, 0x7d,0xb3,0xb3,0xce,
+ 0x52,0x29,0x29,0x7b, 0xdd,0xe3,0xe3,0x3e, 0x5e,0x2f,0x2f,0x71, 0x13,0x84,0x84,0x97,
+ 0xa6,0x53,0x53,0xf5, 0xb9,0xd1,0xd1,0x68, 0x00,0x00,0x00,0x00, 0xc1,0xed,0xed,0x2c,
+ 0x40,0x20,0x20,0x60, 0xe3,0xfc,0xfc,0x1f, 0x79,0xb1,0xb1,0xc8, 0xb6,0x5b,0x5b,0xed,
+ 0xd4,0x6a,0x6a,0xbe, 0x8d,0xcb,0xcb,0x46, 0x67,0xbe,0xbe,0xd9, 0x72,0x39,0x39,0x4b,
+ 0x94,0x4a,0x4a,0xde, 0x98,0x4c,0x4c,0xd4, 0xb0,0x58,0x58,0xe8, 0x85,0xcf,0xcf,0x4a,
+ 0xbb,0xd0,0xd0,0x6b, 0xc5,0xef,0xef,0x2a, 0x4f,0xaa,0xaa,0xe5, 0xed,0xfb,0xfb,0x16,
+ 0x86,0x43,0x43,0xc5, 0x9a,0x4d,0x4d,0xd7, 0x66,0x33,0x33,0x55, 0x11,0x85,0x85,0x94,
+ 0x8a,0x45,0x45,0xcf, 0xe9,0xf9,0xf9,0x10, 0x04,0x02,0x02,0x06, 0xfe,0x7f,0x7f,0x81,
+ 0xa0,0x50,0x50,0xf0, 0x78,0x3c,0x3c,0x44, 0x25,0x9f,0x9f,0xba, 0x4b,0xa8,0xa8,0xe3,
+ 0xa2,0x51,0x51,0xf3, 0x5d,0xa3,0xa3,0xfe, 0x80,0x40,0x40,0xc0, 0x05,0x8f,0x8f,0x8a,
+ 0x3f,0x92,0x92,0xad, 0x21,0x9d,0x9d,0xbc, 0x70,0x38,0x38,0x48, 0xf1,0xf5,0xf5,0x04,
+ 0x63,0xbc,0xbc,0xdf, 0x77,0xb6,0xb6,0xc1, 0xaf,0xda,0xda,0x75, 0x42,0x21,0x21,0x63,
+ 0x20,0x10,0x10,0x30, 0xe5,0xff,0xff,0x1a, 0xfd,0xf3,0xf3,0x0e, 0xbf,0xd2,0xd2,0x6d,
+ 0x81,0xcd,0xcd,0x4c, 0x18,0x0c,0x0c,0x14, 0x26,0x13,0x13,0x35, 0xc3,0xec,0xec,0x2f,
+ 0xbe,0x5f,0x5f,0xe1, 0x35,0x97,0x97,0xa2, 0x88,0x44,0x44,0xcc, 0x2e,0x17,0x17,0x39,
+ 0x93,0xc4,0xc4,0x57, 0x55,0xa7,0xa7,0xf2, 0xfc,0x7e,0x7e,0x82, 0x7a,0x3d,0x3d,0x47,
+ 0xc8,0x64,0x64,0xac, 0xba,0x5d,0x5d,0xe7, 0x32,0x19,0x19,0x2b, 0xe6,0x73,0x73,0x95,
+ 0xc0,0x60,0x60,0xa0, 0x19,0x81,0x81,0x98, 0x9e,0x4f,0x4f,0xd1, 0xa3,0xdc,0xdc,0x7f,
+ 0x44,0x22,0x22,0x66, 0x54,0x2a,0x2a,0x7e, 0x3b,0x90,0x90,0xab, 0x0b,0x88,0x88,0x83,
+ 0x8c,0x46,0x46,0xca, 0xc7,0xee,0xee,0x29, 0x6b,0xb8,0xb8,0xd3, 0x28,0x14,0x14,0x3c,
+ 0xa7,0xde,0xde,0x79, 0xbc,0x5e,0x5e,0xe2, 0x16,0x0b,0x0b,0x1d, 0xad,0xdb,0xdb,0x76,
+ 0xdb,0xe0,0xe0,0x3b, 0x64,0x32,0x32,0x56, 0x74,0x3a,0x3a,0x4e, 0x14,0x0a,0x0a,0x1e,
+ 0x92,0x49,0x49,0xdb, 0x0c,0x06,0x06,0x0a, 0x48,0x24,0x24,0x6c, 0xb8,0x5c,0x5c,0xe4,
+ 0x9f,0xc2,0xc2,0x5d, 0xbd,0xd3,0xd3,0x6e, 0x43,0xac,0xac,0xef, 0xc4,0x62,0x62,0xa6,
+ 0x39,0x91,0x91,0xa8, 0x31,0x95,0x95,0xa4, 0xd3,0xe4,0xe4,0x37, 0xf2,0x79,0x79,0x8b,
+ 0xd5,0xe7,0xe7,0x32, 0x8b,0xc8,0xc8,0x43, 0x6e,0x37,0x37,0x59, 0xda,0x6d,0x6d,0xb7,
+ 0x01,0x8d,0x8d,0x8c, 0xb1,0xd5,0xd5,0x64, 0x9c,0x4e,0x4e,0xd2, 0x49,0xa9,0xa9,0xe0,
+ 0xd8,0x6c,0x6c,0xb4, 0xac,0x56,0x56,0xfa, 0xf3,0xf4,0xf4,0x07, 0xcf,0xea,0xea,0x25,
+ 0xca,0x65,0x65,0xaf, 0xf4,0x7a,0x7a,0x8e, 0x47,0xae,0xae,0xe9, 0x10,0x08,0x08,0x18,
+ 0x6f,0xba,0xba,0xd5, 0xf0,0x78,0x78,0x88, 0x4a,0x25,0x25,0x6f, 0x5c,0x2e,0x2e,0x72,
+ 0x38,0x1c,0x1c,0x24, 0x57,0xa6,0xa6,0xf1, 0x73,0xb4,0xb4,0xc7, 0x97,0xc6,0xc6,0x51,
+ 0xcb,0xe8,0xe8,0x23, 0xa1,0xdd,0xdd,0x7c, 0xe8,0x74,0x74,0x9c, 0x3e,0x1f,0x1f,0x21,
+ 0x96,0x4b,0x4b,0xdd, 0x61,0xbd,0xbd,0xdc, 0x0d,0x8b,0x8b,0x86, 0x0f,0x8a,0x8a,0x85,
+ 0xe0,0x70,0x70,0x90, 0x7c,0x3e,0x3e,0x42, 0x71,0xb5,0xb5,0xc4, 0xcc,0x66,0x66,0xaa,
+ 0x90,0x48,0x48,0xd8, 0x06,0x03,0x03,0x05, 0xf7,0xf6,0xf6,0x01, 0x1c,0x0e,0x0e,0x12,
+ 0xc2,0x61,0x61,0xa3, 0x6a,0x35,0x35,0x5f, 0xae,0x57,0x57,0xf9, 0x69,0xb9,0xb9,0xd0,
+ 0x17,0x86,0x86,0x91, 0x99,0xc1,0xc1,0x58, 0x3a,0x1d,0x1d,0x27, 0x27,0x9e,0x9e,0xb9,
+ 0xd9,0xe1,0xe1,0x38, 0xeb,0xf8,0xf8,0x13, 0x2b,0x98,0x98,0xb3, 0x22,0x11,0x11,0x33,
+ 0xd2,0x69,0x69,0xbb, 0xa9,0xd9,0xd9,0x70, 0x07,0x8e,0x8e,0x89, 0x33,0x94,0x94,0xa7,
+ 0x2d,0x9b,0x9b,0xb6, 0x3c,0x1e,0x1e,0x22, 0x15,0x87,0x87,0x92, 0xc9,0xe9,0xe9,0x20,
+ 0x87,0xce,0xce,0x49, 0xaa,0x55,0x55,0xff, 0x50,0x28,0x28,0x78, 0xa5,0xdf,0xdf,0x7a,
+ 0x03,0x8c,0x8c,0x8f, 0x59,0xa1,0xa1,0xf8, 0x09,0x89,0x89,0x80, 0x1a,0x0d,0x0d,0x17,
+ 0x65,0xbf,0xbf,0xda, 0xd7,0xe6,0xe6,0x31, 0x84,0x42,0x42,0xc6, 0xd0,0x68,0x68,0xb8,
+ 0x82,0x41,0x41,0xc3, 0x29,0x99,0x99,0xb0, 0x5a,0x2d,0x2d,0x77, 0x1e,0x0f,0x0f,0x11,
+ 0x7b,0xb0,0xb0,0xcb, 0xa8,0x54,0x54,0xfc, 0x6d,0xbb,0xbb,0xd6, 0x2c,0x16,0x16,0x3a
+};
+
+static uint8_t T2[256][4]=
+{
+ 0xa5,0xc6,0x63,0x63, 0x84,0xf8,0x7c,0x7c, 0x99,0xee,0x77,0x77, 0x8d,0xf6,0x7b,0x7b,
+ 0x0d,0xff,0xf2,0xf2, 0xbd,0xd6,0x6b,0x6b, 0xb1,0xde,0x6f,0x6f, 0x54,0x91,0xc5,0xc5,
+ 0x50,0x60,0x30,0x30, 0x03,0x02,0x01,0x01, 0xa9,0xce,0x67,0x67, 0x7d,0x56,0x2b,0x2b,
+ 0x19,0xe7,0xfe,0xfe, 0x62,0xb5,0xd7,0xd7, 0xe6,0x4d,0xab,0xab, 0x9a,0xec,0x76,0x76,
+ 0x45,0x8f,0xca,0xca, 0x9d,0x1f,0x82,0x82, 0x40,0x89,0xc9,0xc9, 0x87,0xfa,0x7d,0x7d,
+ 0x15,0xef,0xfa,0xfa, 0xeb,0xb2,0x59,0x59, 0xc9,0x8e,0x47,0x47, 0x0b,0xfb,0xf0,0xf0,
+ 0xec,0x41,0xad,0xad, 0x67,0xb3,0xd4,0xd4, 0xfd,0x5f,0xa2,0xa2, 0xea,0x45,0xaf,0xaf,
+ 0xbf,0x23,0x9c,0x9c, 0xf7,0x53,0xa4,0xa4, 0x96,0xe4,0x72,0x72, 0x5b,0x9b,0xc0,0xc0,
+ 0xc2,0x75,0xb7,0xb7, 0x1c,0xe1,0xfd,0xfd, 0xae,0x3d,0x93,0x93, 0x6a,0x4c,0x26,0x26,
+ 0x5a,0x6c,0x36,0x36, 0x41,0x7e,0x3f,0x3f, 0x02,0xf5,0xf7,0xf7, 0x4f,0x83,0xcc,0xcc,
+ 0x5c,0x68,0x34,0x34, 0xf4,0x51,0xa5,0xa5, 0x34,0xd1,0xe5,0xe5, 0x08,0xf9,0xf1,0xf1,
+ 0x93,0xe2,0x71,0x71, 0x73,0xab,0xd8,0xd8, 0x53,0x62,0x31,0x31, 0x3f,0x2a,0x15,0x15,
+ 0x0c,0x08,0x04,0x04, 0x52,0x95,0xc7,0xc7, 0x65,0x46,0x23,0x23, 0x5e,0x9d,0xc3,0xc3,
+ 0x28,0x30,0x18,0x18, 0xa1,0x37,0x96,0x96, 0x0f,0x0a,0x05,0x05, 0xb5,0x2f,0x9a,0x9a,
+ 0x09,0x0e,0x07,0x07, 0x36,0x24,0x12,0x12, 0x9b,0x1b,0x80,0x80, 0x3d,0xdf,0xe2,0xe2,
+ 0x26,0xcd,0xeb,0xeb, 0x69,0x4e,0x27,0x27, 0xcd,0x7f,0xb2,0xb2, 0x9f,0xea,0x75,0x75,
+ 0x1b,0x12,0x09,0x09, 0x9e,0x1d,0x83,0x83, 0x74,0x58,0x2c,0x2c, 0x2e,0x34,0x1a,0x1a,
+ 0x2d,0x36,0x1b,0x1b, 0xb2,0xdc,0x6e,0x6e, 0xee,0xb4,0x5a,0x5a, 0xfb,0x5b,0xa0,0xa0,
+ 0xf6,0xa4,0x52,0x52, 0x4d,0x76,0x3b,0x3b, 0x61,0xb7,0xd6,0xd6, 0xce,0x7d,0xb3,0xb3,
+ 0x7b,0x52,0x29,0x29, 0x3e,0xdd,0xe3,0xe3, 0x71,0x5e,0x2f,0x2f, 0x97,0x13,0x84,0x84,
+ 0xf5,0xa6,0x53,0x53, 0x68,0xb9,0xd1,0xd1, 0x00,0x00,0x00,0x00, 0x2c,0xc1,0xed,0xed,
+ 0x60,0x40,0x20,0x20, 0x1f,0xe3,0xfc,0xfc, 0xc8,0x79,0xb1,0xb1, 0xed,0xb6,0x5b,0x5b,
+ 0xbe,0xd4,0x6a,0x6a, 0x46,0x8d,0xcb,0xcb, 0xd9,0x67,0xbe,0xbe, 0x4b,0x72,0x39,0x39,
+ 0xde,0x94,0x4a,0x4a, 0xd4,0x98,0x4c,0x4c, 0xe8,0xb0,0x58,0x58, 0x4a,0x85,0xcf,0xcf,
+ 0x6b,0xbb,0xd0,0xd0, 0x2a,0xc5,0xef,0xef, 0xe5,0x4f,0xaa,0xaa, 0x16,0xed,0xfb,0xfb,
+ 0xc5,0x86,0x43,0x43, 0xd7,0x9a,0x4d,0x4d, 0x55,0x66,0x33,0x33, 0x94,0x11,0x85,0x85,
+ 0xcf,0x8a,0x45,0x45, 0x10,0xe9,0xf9,0xf9, 0x06,0x04,0x02,0x02, 0x81,0xfe,0x7f,0x7f,
+ 0xf0,0xa0,0x50,0x50, 0x44,0x78,0x3c,0x3c, 0xba,0x25,0x9f,0x9f, 0xe3,0x4b,0xa8,0xa8,
+ 0xf3,0xa2,0x51,0x51, 0xfe,0x5d,0xa3,0xa3, 0xc0,0x80,0x40,0x40, 0x8a,0x05,0x8f,0x8f,
+ 0xad,0x3f,0x92,0x92, 0xbc,0x21,0x9d,0x9d, 0x48,0x70,0x38,0x38, 0x04,0xf1,0xf5,0xf5,
+ 0xdf,0x63,0xbc,0xbc, 0xc1,0x77,0xb6,0xb6, 0x75,0xaf,0xda,0xda, 0x63,0x42,0x21,0x21,
+ 0x30,0x20,0x10,0x10, 0x1a,0xe5,0xff,0xff, 0x0e,0xfd,0xf3,0xf3, 0x6d,0xbf,0xd2,0xd2,
+ 0x4c,0x81,0xcd,0xcd, 0x14,0x18,0x0c,0x0c, 0x35,0x26,0x13,0x13, 0x2f,0xc3,0xec,0xec,
+ 0xe1,0xbe,0x5f,0x5f, 0xa2,0x35,0x97,0x97, 0xcc,0x88,0x44,0x44, 0x39,0x2e,0x17,0x17,
+ 0x57,0x93,0xc4,0xc4, 0xf2,0x55,0xa7,0xa7, 0x82,0xfc,0x7e,0x7e, 0x47,0x7a,0x3d,0x3d,
+ 0xac,0xc8,0x64,0x64, 0xe7,0xba,0x5d,0x5d, 0x2b,0x32,0x19,0x19, 0x95,0xe6,0x73,0x73,
+ 0xa0,0xc0,0x60,0x60, 0x98,0x19,0x81,0x81, 0xd1,0x9e,0x4f,0x4f, 0x7f,0xa3,0xdc,0xdc,
+ 0x66,0x44,0x22,0x22, 0x7e,0x54,0x2a,0x2a, 0xab,0x3b,0x90,0x90, 0x83,0x0b,0x88,0x88,
+ 0xca,0x8c,0x46,0x46, 0x29,0xc7,0xee,0xee, 0xd3,0x6b,0xb8,0xb8, 0x3c,0x28,0x14,0x14,
+ 0x79,0xa7,0xde,0xde, 0xe2,0xbc,0x5e,0x5e, 0x1d,0x16,0x0b,0x0b, 0x76,0xad,0xdb,0xdb,
+ 0x3b,0xdb,0xe0,0xe0, 0x56,0x64,0x32,0x32, 0x4e,0x74,0x3a,0x3a, 0x1e,0x14,0x0a,0x0a,
+ 0xdb,0x92,0x49,0x49, 0x0a,0x0c,0x06,0x06, 0x6c,0x48,0x24,0x24, 0xe4,0xb8,0x5c,0x5c,
+ 0x5d,0x9f,0xc2,0xc2, 0x6e,0xbd,0xd3,0xd3, 0xef,0x43,0xac,0xac, 0xa6,0xc4,0x62,0x62,
+ 0xa8,0x39,0x91,0x91, 0xa4,0x31,0x95,0x95, 0x37,0xd3,0xe4,0xe4, 0x8b,0xf2,0x79,0x79,
+ 0x32,0xd5,0xe7,0xe7, 0x43,0x8b,0xc8,0xc8, 0x59,0x6e,0x37,0x37, 0xb7,0xda,0x6d,0x6d,
+ 0x8c,0x01,0x8d,0x8d, 0x64,0xb1,0xd5,0xd5, 0xd2,0x9c,0x4e,0x4e, 0xe0,0x49,0xa9,0xa9,
+ 0xb4,0xd8,0x6c,0x6c, 0xfa,0xac,0x56,0x56, 0x07,0xf3,0xf4,0xf4, 0x25,0xcf,0xea,0xea,
+ 0xaf,0xca,0x65,0x65, 0x8e,0xf4,0x7a,0x7a, 0xe9,0x47,0xae,0xae, 0x18,0x10,0x08,0x08,
+ 0xd5,0x6f,0xba,0xba, 0x88,0xf0,0x78,0x78, 0x6f,0x4a,0x25,0x25, 0x72,0x5c,0x2e,0x2e,
+ 0x24,0x38,0x1c,0x1c, 0xf1,0x57,0xa6,0xa6, 0xc7,0x73,0xb4,0xb4, 0x51,0x97,0xc6,0xc6,
+ 0x23,0xcb,0xe8,0xe8, 0x7c,0xa1,0xdd,0xdd, 0x9c,0xe8,0x74,0x74, 0x21,0x3e,0x1f,0x1f,
+ 0xdd,0x96,0x4b,0x4b, 0xdc,0x61,0xbd,0xbd, 0x86,0x0d,0x8b,0x8b, 0x85,0x0f,0x8a,0x8a,
+ 0x90,0xe0,0x70,0x70, 0x42,0x7c,0x3e,0x3e, 0xc4,0x71,0xb5,0xb5, 0xaa,0xcc,0x66,0x66,
+ 0xd8,0x90,0x48,0x48, 0x05,0x06,0x03,0x03, 0x01,0xf7,0xf6,0xf6, 0x12,0x1c,0x0e,0x0e,
+ 0xa3,0xc2,0x61,0x61, 0x5f,0x6a,0x35,0x35, 0xf9,0xae,0x57,0x57, 0xd0,0x69,0xb9,0xb9,
+ 0x91,0x17,0x86,0x86, 0x58,0x99,0xc1,0xc1, 0x27,0x3a,0x1d,0x1d, 0xb9,0x27,0x9e,0x9e,
+ 0x38,0xd9,0xe1,0xe1, 0x13,0xeb,0xf8,0xf8, 0xb3,0x2b,0x98,0x98, 0x33,0x22,0x11,0x11,
+ 0xbb,0xd2,0x69,0x69, 0x70,0xa9,0xd9,0xd9, 0x89,0x07,0x8e,0x8e, 0xa7,0x33,0x94,0x94,
+ 0xb6,0x2d,0x9b,0x9b, 0x22,0x3c,0x1e,0x1e, 0x92,0x15,0x87,0x87, 0x20,0xc9,0xe9,0xe9,
+ 0x49,0x87,0xce,0xce, 0xff,0xaa,0x55,0x55, 0x78,0x50,0x28,0x28, 0x7a,0xa5,0xdf,0xdf,
+ 0x8f,0x03,0x8c,0x8c, 0xf8,0x59,0xa1,0xa1, 0x80,0x09,0x89,0x89, 0x17,0x1a,0x0d,0x0d,
+ 0xda,0x65,0xbf,0xbf, 0x31,0xd7,0xe6,0xe6, 0xc6,0x84,0x42,0x42, 0xb8,0xd0,0x68,0x68,
+ 0xc3,0x82,0x41,0x41, 0xb0,0x29,0x99,0x99, 0x77,0x5a,0x2d,0x2d, 0x11,0x1e,0x0f,0x0f,
+ 0xcb,0x7b,0xb0,0xb0, 0xfc,0xa8,0x54,0x54, 0xd6,0x6d,0xbb,0xbb, 0x3a,0x2c,0x16,0x16
+};
+
+static uint8_t T3[256][4]=
+{
+ 0x63,0xa5,0xc6,0x63, 0x7c,0x84,0xf8,0x7c, 0x77,0x99,0xee,0x77, 0x7b,0x8d,0xf6,0x7b,
+ 0xf2,0x0d,0xff,0xf2, 0x6b,0xbd,0xd6,0x6b, 0x6f,0xb1,0xde,0x6f, 0xc5,0x54,0x91,0xc5,
+ 0x30,0x50,0x60,0x30, 0x01,0x03,0x02,0x01, 0x67,0xa9,0xce,0x67, 0x2b,0x7d,0x56,0x2b,
+ 0xfe,0x19,0xe7,0xfe, 0xd7,0x62,0xb5,0xd7, 0xab,0xe6,0x4d,0xab, 0x76,0x9a,0xec,0x76,
+ 0xca,0x45,0x8f,0xca, 0x82,0x9d,0x1f,0x82, 0xc9,0x40,0x89,0xc9, 0x7d,0x87,0xfa,0x7d,
+ 0xfa,0x15,0xef,0xfa, 0x59,0xeb,0xb2,0x59, 0x47,0xc9,0x8e,0x47, 0xf0,0x0b,0xfb,0xf0,
+ 0xad,0xec,0x41,0xad, 0xd4,0x67,0xb3,0xd4, 0xa2,0xfd,0x5f,0xa2, 0xaf,0xea,0x45,0xaf,
+ 0x9c,0xbf,0x23,0x9c, 0xa4,0xf7,0x53,0xa4, 0x72,0x96,0xe4,0x72, 0xc0,0x5b,0x9b,0xc0,
+ 0xb7,0xc2,0x75,0xb7, 0xfd,0x1c,0xe1,0xfd, 0x93,0xae,0x3d,0x93, 0x26,0x6a,0x4c,0x26,
+ 0x36,0x5a,0x6c,0x36, 0x3f,0x41,0x7e,0x3f, 0xf7,0x02,0xf5,0xf7, 0xcc,0x4f,0x83,0xcc,
+ 0x34,0x5c,0x68,0x34, 0xa5,0xf4,0x51,0xa5, 0xe5,0x34,0xd1,0xe5, 0xf1,0x08,0xf9,0xf1,
+ 0x71,0x93,0xe2,0x71, 0xd8,0x73,0xab,0xd8, 0x31,0x53,0x62,0x31, 0x15,0x3f,0x2a,0x15,
+ 0x04,0x0c,0x08,0x04, 0xc7,0x52,0x95,0xc7, 0x23,0x65,0x46,0x23, 0xc3,0x5e,0x9d,0xc3,
+ 0x18,0x28,0x30,0x18, 0x96,0xa1,0x37,0x96, 0x05,0x0f,0x0a,0x05, 0x9a,0xb5,0x2f,0x9a,
+ 0x07,0x09,0x0e,0x07, 0x12,0x36,0x24,0x12, 0x80,0x9b,0x1b,0x80, 0xe2,0x3d,0xdf,0xe2,
+ 0xeb,0x26,0xcd,0xeb, 0x27,0x69,0x4e,0x27, 0xb2,0xcd,0x7f,0xb2, 0x75,0x9f,0xea,0x75,
+ 0x09,0x1b,0x12,0x09, 0x83,0x9e,0x1d,0x83, 0x2c,0x74,0x58,0x2c, 0x1a,0x2e,0x34,0x1a,
+ 0x1b,0x2d,0x36,0x1b, 0x6e,0xb2,0xdc,0x6e, 0x5a,0xee,0xb4,0x5a, 0xa0,0xfb,0x5b,0xa0,
+ 0x52,0xf6,0xa4,0x52, 0x3b,0x4d,0x76,0x3b, 0xd6,0x61,0xb7,0xd6, 0xb3,0xce,0x7d,0xb3,
+ 0x29,0x7b,0x52,0x29, 0xe3,0x3e,0xdd,0xe3, 0x2f,0x71,0x5e,0x2f, 0x84,0x97,0x13,0x84,
+ 0x53,0xf5,0xa6,0x53, 0xd1,0x68,0xb9,0xd1, 0x00,0x00,0x00,0x00, 0xed,0x2c,0xc1,0xed,
+ 0x20,0x60,0x40,0x20, 0xfc,0x1f,0xe3,0xfc, 0xb1,0xc8,0x79,0xb1, 0x5b,0xed,0xb6,0x5b,
+ 0x6a,0xbe,0xd4,0x6a, 0xcb,0x46,0x8d,0xcb, 0xbe,0xd9,0x67,0xbe, 0x39,0x4b,0x72,0x39,
+ 0x4a,0xde,0x94,0x4a, 0x4c,0xd4,0x98,0x4c, 0x58,0xe8,0xb0,0x58, 0xcf,0x4a,0x85,0xcf,
+ 0xd0,0x6b,0xbb,0xd0, 0xef,0x2a,0xc5,0xef, 0xaa,0xe5,0x4f,0xaa, 0xfb,0x16,0xed,0xfb,
+ 0x43,0xc5,0x86,0x43, 0x4d,0xd7,0x9a,0x4d, 0x33,0x55,0x66,0x33, 0x85,0x94,0x11,0x85,
+ 0x45,0xcf,0x8a,0x45, 0xf9,0x10,0xe9,0xf9, 0x02,0x06,0x04,0x02, 0x7f,0x81,0xfe,0x7f,
+ 0x50,0xf0,0xa0,0x50, 0x3c,0x44,0x78,0x3c, 0x9f,0xba,0x25,0x9f, 0xa8,0xe3,0x4b,0xa8,
+ 0x51,0xf3,0xa2,0x51, 0xa3,0xfe,0x5d,0xa3, 0x40,0xc0,0x80,0x40, 0x8f,0x8a,0x05,0x8f,
+ 0x92,0xad,0x3f,0x92, 0x9d,0xbc,0x21,0x9d, 0x38,0x48,0x70,0x38, 0xf5,0x04,0xf1,0xf5,
+ 0xbc,0xdf,0x63,0xbc, 0xb6,0xc1,0x77,0xb6, 0xda,0x75,0xaf,0xda, 0x21,0x63,0x42,0x21,
+ 0x10,0x30,0x20,0x10, 0xff,0x1a,0xe5,0xff, 0xf3,0x0e,0xfd,0xf3, 0xd2,0x6d,0xbf,0xd2,
+ 0xcd,0x4c,0x81,0xcd, 0x0c,0x14,0x18,0x0c, 0x13,0x35,0x26,0x13, 0xec,0x2f,0xc3,0xec,
+ 0x5f,0xe1,0xbe,0x5f, 0x97,0xa2,0x35,0x97, 0x44,0xcc,0x88,0x44, 0x17,0x39,0x2e,0x17,
+ 0xc4,0x57,0x93,0xc4, 0xa7,0xf2,0x55,0xa7, 0x7e,0x82,0xfc,0x7e, 0x3d,0x47,0x7a,0x3d,
+ 0x64,0xac,0xc8,0x64, 0x5d,0xe7,0xba,0x5d, 0x19,0x2b,0x32,0x19, 0x73,0x95,0xe6,0x73,
+ 0x60,0xa0,0xc0,0x60, 0x81,0x98,0x19,0x81, 0x4f,0xd1,0x9e,0x4f, 0xdc,0x7f,0xa3,0xdc,
+ 0x22,0x66,0x44,0x22, 0x2a,0x7e,0x54,0x2a, 0x90,0xab,0x3b,0x90, 0x88,0x83,0x0b,0x88,
+ 0x46,0xca,0x8c,0x46, 0xee,0x29,0xc7,0xee, 0xb8,0xd3,0x6b,0xb8, 0x14,0x3c,0x28,0x14,
+ 0xde,0x79,0xa7,0xde, 0x5e,0xe2,0xbc,0x5e, 0x0b,0x1d,0x16,0x0b, 0xdb,0x76,0xad,0xdb,
+ 0xe0,0x3b,0xdb,0xe0, 0x32,0x56,0x64,0x32, 0x3a,0x4e,0x74,0x3a, 0x0a,0x1e,0x14,0x0a,
+ 0x49,0xdb,0x92,0x49, 0x06,0x0a,0x0c,0x06, 0x24,0x6c,0x48,0x24, 0x5c,0xe4,0xb8,0x5c,
+ 0xc2,0x5d,0x9f,0xc2, 0xd3,0x6e,0xbd,0xd3, 0xac,0xef,0x43,0xac, 0x62,0xa6,0xc4,0x62,
+ 0x91,0xa8,0x39,0x91, 0x95,0xa4,0x31,0x95, 0xe4,0x37,0xd3,0xe4, 0x79,0x8b,0xf2,0x79,
+ 0xe7,0x32,0xd5,0xe7, 0xc8,0x43,0x8b,0xc8, 0x37,0x59,0x6e,0x37, 0x6d,0xb7,0xda,0x6d,
+ 0x8d,0x8c,0x01,0x8d, 0xd5,0x64,0xb1,0xd5, 0x4e,0xd2,0x9c,0x4e, 0xa9,0xe0,0x49,0xa9,
+ 0x6c,0xb4,0xd8,0x6c, 0x56,0xfa,0xac,0x56, 0xf4,0x07,0xf3,0xf4, 0xea,0x25,0xcf,0xea,
+ 0x65,0xaf,0xca,0x65, 0x7a,0x8e,0xf4,0x7a, 0xae,0xe9,0x47,0xae, 0x08,0x18,0x10,0x08,
+ 0xba,0xd5,0x6f,0xba, 0x78,0x88,0xf0,0x78, 0x25,0x6f,0x4a,0x25, 0x2e,0x72,0x5c,0x2e,
+ 0x1c,0x24,0x38,0x1c, 0xa6,0xf1,0x57,0xa6, 0xb4,0xc7,0x73,0xb4, 0xc6,0x51,0x97,0xc6,
+ 0xe8,0x23,0xcb,0xe8, 0xdd,0x7c,0xa1,0xdd, 0x74,0x9c,0xe8,0x74, 0x1f,0x21,0x3e,0x1f,
+ 0x4b,0xdd,0x96,0x4b, 0xbd,0xdc,0x61,0xbd, 0x8b,0x86,0x0d,0x8b, 0x8a,0x85,0x0f,0x8a,
+ 0x70,0x90,0xe0,0x70, 0x3e,0x42,0x7c,0x3e, 0xb5,0xc4,0x71,0xb5, 0x66,0xaa,0xcc,0x66,
+ 0x48,0xd8,0x90,0x48, 0x03,0x05,0x06,0x03, 0xf6,0x01,0xf7,0xf6, 0x0e,0x12,0x1c,0x0e,
+ 0x61,0xa3,0xc2,0x61, 0x35,0x5f,0x6a,0x35, 0x57,0xf9,0xae,0x57, 0xb9,0xd0,0x69,0xb9,
+ 0x86,0x91,0x17,0x86, 0xc1,0x58,0x99,0xc1, 0x1d,0x27,0x3a,0x1d, 0x9e,0xb9,0x27,0x9e,
+ 0xe1,0x38,0xd9,0xe1, 0xf8,0x13,0xeb,0xf8, 0x98,0xb3,0x2b,0x98, 0x11,0x33,0x22,0x11,
+ 0x69,0xbb,0xd2,0x69, 0xd9,0x70,0xa9,0xd9, 0x8e,0x89,0x07,0x8e, 0x94,0xa7,0x33,0x94,
+ 0x9b,0xb6,0x2d,0x9b, 0x1e,0x22,0x3c,0x1e, 0x87,0x92,0x15,0x87, 0xe9,0x20,0xc9,0xe9,
+ 0xce,0x49,0x87,0xce, 0x55,0xff,0xaa,0x55, 0x28,0x78,0x50,0x28, 0xdf,0x7a,0xa5,0xdf,
+ 0x8c,0x8f,0x03,0x8c, 0xa1,0xf8,0x59,0xa1, 0x89,0x80,0x09,0x89, 0x0d,0x17,0x1a,0x0d,
+ 0xbf,0xda,0x65,0xbf, 0xe6,0x31,0xd7,0xe6, 0x42,0xc6,0x84,0x42, 0x68,0xb8,0xd0,0x68,
+ 0x41,0xc3,0x82,0x41, 0x99,0xb0,0x29,0x99, 0x2d,0x77,0x5a,0x2d, 0x0f,0x11,0x1e,0x0f,
+ 0xb0,0xcb,0x7b,0xb0, 0x54,0xfc,0xa8,0x54, 0xbb,0xd6,0x6d,0xbb, 0x16,0x3a,0x2c,0x16
+};
+
+static uint8_t T4[256][4]=
+{
+ 0x63,0x63,0xa5,0xc6, 0x7c,0x7c,0x84,0xf8, 0x77,0x77,0x99,0xee, 0x7b,0x7b,0x8d,0xf6,
+ 0xf2,0xf2,0x0d,0xff, 0x6b,0x6b,0xbd,0xd6, 0x6f,0x6f,0xb1,0xde, 0xc5,0xc5,0x54,0x91,
+ 0x30,0x30,0x50,0x60, 0x01,0x01,0x03,0x02, 0x67,0x67,0xa9,0xce, 0x2b,0x2b,0x7d,0x56,
+ 0xfe,0xfe,0x19,0xe7, 0xd7,0xd7,0x62,0xb5, 0xab,0xab,0xe6,0x4d, 0x76,0x76,0x9a,0xec,
+ 0xca,0xca,0x45,0x8f, 0x82,0x82,0x9d,0x1f, 0xc9,0xc9,0x40,0x89, 0x7d,0x7d,0x87,0xfa,
+ 0xfa,0xfa,0x15,0xef, 0x59,0x59,0xeb,0xb2, 0x47,0x47,0xc9,0x8e, 0xf0,0xf0,0x0b,0xfb,
+ 0xad,0xad,0xec,0x41, 0xd4,0xd4,0x67,0xb3, 0xa2,0xa2,0xfd,0x5f, 0xaf,0xaf,0xea,0x45,
+ 0x9c,0x9c,0xbf,0x23, 0xa4,0xa4,0xf7,0x53, 0x72,0x72,0x96,0xe4, 0xc0,0xc0,0x5b,0x9b,
+ 0xb7,0xb7,0xc2,0x75, 0xfd,0xfd,0x1c,0xe1, 0x93,0x93,0xae,0x3d, 0x26,0x26,0x6a,0x4c,
+ 0x36,0x36,0x5a,0x6c, 0x3f,0x3f,0x41,0x7e, 0xf7,0xf7,0x02,0xf5, 0xcc,0xcc,0x4f,0x83,
+ 0x34,0x34,0x5c,0x68, 0xa5,0xa5,0xf4,0x51, 0xe5,0xe5,0x34,0xd1, 0xf1,0xf1,0x08,0xf9,
+ 0x71,0x71,0x93,0xe2, 0xd8,0xd8,0x73,0xab, 0x31,0x31,0x53,0x62, 0x15,0x15,0x3f,0x2a,
+ 0x04,0x04,0x0c,0x08, 0xc7,0xc7,0x52,0x95, 0x23,0x23,0x65,0x46, 0xc3,0xc3,0x5e,0x9d,
+ 0x18,0x18,0x28,0x30, 0x96,0x96,0xa1,0x37, 0x05,0x05,0x0f,0x0a, 0x9a,0x9a,0xb5,0x2f,
+ 0x07,0x07,0x09,0x0e, 0x12,0x12,0x36,0x24, 0x80,0x80,0x9b,0x1b, 0xe2,0xe2,0x3d,0xdf,
+ 0xeb,0xeb,0x26,0xcd, 0x27,0x27,0x69,0x4e, 0xb2,0xb2,0xcd,0x7f, 0x75,0x75,0x9f,0xea,
+ 0x09,0x09,0x1b,0x12, 0x83,0x83,0x9e,0x1d, 0x2c,0x2c,0x74,0x58, 0x1a,0x1a,0x2e,0x34,
+ 0x1b,0x1b,0x2d,0x36, 0x6e,0x6e,0xb2,0xdc, 0x5a,0x5a,0xee,0xb4, 0xa0,0xa0,0xfb,0x5b,
+ 0x52,0x52,0xf6,0xa4, 0x3b,0x3b,0x4d,0x76, 0xd6,0xd6,0x61,0xb7, 0xb3,0xb3,0xce,0x7d,
+ 0x29,0x29,0x7b,0x52, 0xe3,0xe3,0x3e,0xdd, 0x2f,0x2f,0x71,0x5e, 0x84,0x84,0x97,0x13,
+ 0x53,0x53,0xf5,0xa6, 0xd1,0xd1,0x68,0xb9, 0x00,0x00,0x00,0x00, 0xed,0xed,0x2c,0xc1,
+ 0x20,0x20,0x60,0x40, 0xfc,0xfc,0x1f,0xe3, 0xb1,0xb1,0xc8,0x79, 0x5b,0x5b,0xed,0xb6,
+ 0x6a,0x6a,0xbe,0xd4, 0xcb,0xcb,0x46,0x8d, 0xbe,0xbe,0xd9,0x67, 0x39,0x39,0x4b,0x72,
+ 0x4a,0x4a,0xde,0x94, 0x4c,0x4c,0xd4,0x98, 0x58,0x58,0xe8,0xb0, 0xcf,0xcf,0x4a,0x85,
+ 0xd0,0xd0,0x6b,0xbb, 0xef,0xef,0x2a,0xc5, 0xaa,0xaa,0xe5,0x4f, 0xfb,0xfb,0x16,0xed,
+ 0x43,0x43,0xc5,0x86, 0x4d,0x4d,0xd7,0x9a, 0x33,0x33,0x55,0x66, 0x85,0x85,0x94,0x11,
+ 0x45,0x45,0xcf,0x8a, 0xf9,0xf9,0x10,0xe9, 0x02,0x02,0x06,0x04, 0x7f,0x7f,0x81,0xfe,
+ 0x50,0x50,0xf0,0xa0, 0x3c,0x3c,0x44,0x78, 0x9f,0x9f,0xba,0x25, 0xa8,0xa8,0xe3,0x4b,
+ 0x51,0x51,0xf3,0xa2, 0xa3,0xa3,0xfe,0x5d, 0x40,0x40,0xc0,0x80, 0x8f,0x8f,0x8a,0x05,
+ 0x92,0x92,0xad,0x3f, 0x9d,0x9d,0xbc,0x21, 0x38,0x38,0x48,0x70, 0xf5,0xf5,0x04,0xf1,
+ 0xbc,0xbc,0xdf,0x63, 0xb6,0xb6,0xc1,0x77, 0xda,0xda,0x75,0xaf, 0x21,0x21,0x63,0x42,
+ 0x10,0x10,0x30,0x20, 0xff,0xff,0x1a,0xe5, 0xf3,0xf3,0x0e,0xfd, 0xd2,0xd2,0x6d,0xbf,
+ 0xcd,0xcd,0x4c,0x81, 0x0c,0x0c,0x14,0x18, 0x13,0x13,0x35,0x26, 0xec,0xec,0x2f,0xc3,
+ 0x5f,0x5f,0xe1,0xbe, 0x97,0x97,0xa2,0x35, 0x44,0x44,0xcc,0x88, 0x17,0x17,0x39,0x2e,
+ 0xc4,0xc4,0x57,0x93, 0xa7,0xa7,0xf2,0x55, 0x7e,0x7e,0x82,0xfc, 0x3d,0x3d,0x47,0x7a,
+ 0x64,0x64,0xac,0xc8, 0x5d,0x5d,0xe7,0xba, 0x19,0x19,0x2b,0x32, 0x73,0x73,0x95,0xe6,
+ 0x60,0x60,0xa0,0xc0, 0x81,0x81,0x98,0x19, 0x4f,0x4f,0xd1,0x9e, 0xdc,0xdc,0x7f,0xa3,
+ 0x22,0x22,0x66,0x44, 0x2a,0x2a,0x7e,0x54, 0x90,0x90,0xab,0x3b, 0x88,0x88,0x83,0x0b,
+ 0x46,0x46,0xca,0x8c, 0xee,0xee,0x29,0xc7, 0xb8,0xb8,0xd3,0x6b, 0x14,0x14,0x3c,0x28,
+ 0xde,0xde,0x79,0xa7, 0x5e,0x5e,0xe2,0xbc, 0x0b,0x0b,0x1d,0x16, 0xdb,0xdb,0x76,0xad,
+ 0xe0,0xe0,0x3b,0xdb, 0x32,0x32,0x56,0x64, 0x3a,0x3a,0x4e,0x74, 0x0a,0x0a,0x1e,0x14,
+ 0x49,0x49,0xdb,0x92, 0x06,0x06,0x0a,0x0c, 0x24,0x24,0x6c,0x48, 0x5c,0x5c,0xe4,0xb8,
+ 0xc2,0xc2,0x5d,0x9f, 0xd3,0xd3,0x6e,0xbd, 0xac,0xac,0xef,0x43, 0x62,0x62,0xa6,0xc4,
+ 0x91,0x91,0xa8,0x39, 0x95,0x95,0xa4,0x31, 0xe4,0xe4,0x37,0xd3, 0x79,0x79,0x8b,0xf2,
+ 0xe7,0xe7,0x32,0xd5, 0xc8,0xc8,0x43,0x8b, 0x37,0x37,0x59,0x6e, 0x6d,0x6d,0xb7,0xda,
+ 0x8d,0x8d,0x8c,0x01, 0xd5,0xd5,0x64,0xb1, 0x4e,0x4e,0xd2,0x9c, 0xa9,0xa9,0xe0,0x49,
+ 0x6c,0x6c,0xb4,0xd8, 0x56,0x56,0xfa,0xac, 0xf4,0xf4,0x07,0xf3, 0xea,0xea,0x25,0xcf,
+ 0x65,0x65,0xaf,0xca, 0x7a,0x7a,0x8e,0xf4, 0xae,0xae,0xe9,0x47, 0x08,0x08,0x18,0x10,
+ 0xba,0xba,0xd5,0x6f, 0x78,0x78,0x88,0xf0, 0x25,0x25,0x6f,0x4a, 0x2e,0x2e,0x72,0x5c,
+ 0x1c,0x1c,0x24,0x38, 0xa6,0xa6,0xf1,0x57, 0xb4,0xb4,0xc7,0x73, 0xc6,0xc6,0x51,0x97,
+ 0xe8,0xe8,0x23,0xcb, 0xdd,0xdd,0x7c,0xa1, 0x74,0x74,0x9c,0xe8, 0x1f,0x1f,0x21,0x3e,
+ 0x4b,0x4b,0xdd,0x96, 0xbd,0xbd,0xdc,0x61, 0x8b,0x8b,0x86,0x0d, 0x8a,0x8a,0x85,0x0f,
+ 0x70,0x70,0x90,0xe0, 0x3e,0x3e,0x42,0x7c, 0xb5,0xb5,0xc4,0x71, 0x66,0x66,0xaa,0xcc,
+ 0x48,0x48,0xd8,0x90, 0x03,0x03,0x05,0x06, 0xf6,0xf6,0x01,0xf7, 0x0e,0x0e,0x12,0x1c,
+ 0x61,0x61,0xa3,0xc2, 0x35,0x35,0x5f,0x6a, 0x57,0x57,0xf9,0xae, 0xb9,0xb9,0xd0,0x69,
+ 0x86,0x86,0x91,0x17, 0xc1,0xc1,0x58,0x99, 0x1d,0x1d,0x27,0x3a, 0x9e,0x9e,0xb9,0x27,
+ 0xe1,0xe1,0x38,0xd9, 0xf8,0xf8,0x13,0xeb, 0x98,0x98,0xb3,0x2b, 0x11,0x11,0x33,0x22,
+ 0x69,0x69,0xbb,0xd2, 0xd9,0xd9,0x70,0xa9, 0x8e,0x8e,0x89,0x07, 0x94,0x94,0xa7,0x33,
+ 0x9b,0x9b,0xb6,0x2d, 0x1e,0x1e,0x22,0x3c, 0x87,0x87,0x92,0x15, 0xe9,0xe9,0x20,0xc9,
+ 0xce,0xce,0x49,0x87, 0x55,0x55,0xff,0xaa, 0x28,0x28,0x78,0x50, 0xdf,0xdf,0x7a,0xa5,
+ 0x8c,0x8c,0x8f,0x03, 0xa1,0xa1,0xf8,0x59, 0x89,0x89,0x80,0x09, 0x0d,0x0d,0x17,0x1a,
+ 0xbf,0xbf,0xda,0x65, 0xe6,0xe6,0x31,0xd7, 0x42,0x42,0xc6,0x84, 0x68,0x68,0xb8,0xd0,
+ 0x41,0x41,0xc3,0x82, 0x99,0x99,0xb0,0x29, 0x2d,0x2d,0x77,0x5a, 0x0f,0x0f,0x11,0x1e,
+ 0xb0,0xb0,0xcb,0x7b, 0x54,0x54,0xfc,0xa8, 0xbb,0xbb,0xd6,0x6d, 0x16,0x16,0x3a,0x2c
+};
+
+static uint8_t T5[256][4]=
+{
+ 0x51,0xf4,0xa7,0x50, 0x7e,0x41,0x65,0x53, 0x1a,0x17,0xa4,0xc3, 0x3a,0x27,0x5e,0x96,
+ 0x3b,0xab,0x6b,0xcb, 0x1f,0x9d,0x45,0xf1, 0xac,0xfa,0x58,0xab, 0x4b,0xe3,0x03,0x93,
+ 0x20,0x30,0xfa,0x55, 0xad,0x76,0x6d,0xf6, 0x88,0xcc,0x76,0x91, 0xf5,0x02,0x4c,0x25,
+ 0x4f,0xe5,0xd7,0xfc, 0xc5,0x2a,0xcb,0xd7, 0x26,0x35,0x44,0x80, 0xb5,0x62,0xa3,0x8f,
+ 0xde,0xb1,0x5a,0x49, 0x25,0xba,0x1b,0x67, 0x45,0xea,0x0e,0x98, 0x5d,0xfe,0xc0,0xe1,
+ 0xc3,0x2f,0x75,0x02, 0x81,0x4c,0xf0,0x12, 0x8d,0x46,0x97,0xa3, 0x6b,0xd3,0xf9,0xc6,
+ 0x03,0x8f,0x5f,0xe7, 0x15,0x92,0x9c,0x95, 0xbf,0x6d,0x7a,0xeb, 0x95,0x52,0x59,0xda,
+ 0xd4,0xbe,0x83,0x2d, 0x58,0x74,0x21,0xd3, 0x49,0xe0,0x69,0x29, 0x8e,0xc9,0xc8,0x44,
+ 0x75,0xc2,0x89,0x6a, 0xf4,0x8e,0x79,0x78, 0x99,0x58,0x3e,0x6b, 0x27,0xb9,0x71,0xdd,
+ 0xbe,0xe1,0x4f,0xb6, 0xf0,0x88,0xad,0x17, 0xc9,0x20,0xac,0x66, 0x7d,0xce,0x3a,0xb4,
+ 0x63,0xdf,0x4a,0x18, 0xe5,0x1a,0x31,0x82, 0x97,0x51,0x33,0x60, 0x62,0x53,0x7f,0x45,
+ 0xb1,0x64,0x77,0xe0, 0xbb,0x6b,0xae,0x84, 0xfe,0x81,0xa0,0x1c, 0xf9,0x08,0x2b,0x94,
+ 0x70,0x48,0x68,0x58, 0x8f,0x45,0xfd,0x19, 0x94,0xde,0x6c,0x87, 0x52,0x7b,0xf8,0xb7,
+ 0xab,0x73,0xd3,0x23, 0x72,0x4b,0x02,0xe2, 0xe3,0x1f,0x8f,0x57, 0x66,0x55,0xab,0x2a,
+ 0xb2,0xeb,0x28,0x07, 0x2f,0xb5,0xc2,0x03, 0x86,0xc5,0x7b,0x9a, 0xd3,0x37,0x08,0xa5,
+ 0x30,0x28,0x87,0xf2, 0x23,0xbf,0xa5,0xb2, 0x02,0x03,0x6a,0xba, 0xed,0x16,0x82,0x5c,
+ 0x8a,0xcf,0x1c,0x2b, 0xa7,0x79,0xb4,0x92, 0xf3,0x07,0xf2,0xf0, 0x4e,0x69,0xe2,0xa1,
+ 0x65,0xda,0xf4,0xcd, 0x06,0x05,0xbe,0xd5, 0xd1,0x34,0x62,0x1f, 0xc4,0xa6,0xfe,0x8a,
+ 0x34,0x2e,0x53,0x9d, 0xa2,0xf3,0x55,0xa0, 0x05,0x8a,0xe1,0x32, 0xa4,0xf6,0xeb,0x75,
+ 0x0b,0x83,0xec,0x39, 0x40,0x60,0xef,0xaa, 0x5e,0x71,0x9f,0x06, 0xbd,0x6e,0x10,0x51,
+ 0x3e,0x21,0x8a,0xf9, 0x96,0xdd,0x06,0x3d, 0xdd,0x3e,0x05,0xae, 0x4d,0xe6,0xbd,0x46,
+ 0x91,0x54,0x8d,0xb5, 0x71,0xc4,0x5d,0x05, 0x04,0x06,0xd4,0x6f, 0x60,0x50,0x15,0xff,
+ 0x19,0x98,0xfb,0x24, 0xd6,0xbd,0xe9,0x97, 0x89,0x40,0x43,0xcc, 0x67,0xd9,0x9e,0x77,
+ 0xb0,0xe8,0x42,0xbd, 0x07,0x89,0x8b,0x88, 0xe7,0x19,0x5b,0x38, 0x79,0xc8,0xee,0xdb,
+ 0xa1,0x7c,0x0a,0x47, 0x7c,0x42,0x0f,0xe9, 0xf8,0x84,0x1e,0xc9, 0x00,0x00,0x00,0x00,
+ 0x09,0x80,0x86,0x83, 0x32,0x2b,0xed,0x48, 0x1e,0x11,0x70,0xac, 0x6c,0x5a,0x72,0x4e,
+ 0xfd,0x0e,0xff,0xfb, 0x0f,0x85,0x38,0x56, 0x3d,0xae,0xd5,0x1e, 0x36,0x2d,0x39,0x27,
+ 0x0a,0x0f,0xd9,0x64, 0x68,0x5c,0xa6,0x21, 0x9b,0x5b,0x54,0xd1, 0x24,0x36,0x2e,0x3a,
+ 0x0c,0x0a,0x67,0xb1, 0x93,0x57,0xe7,0x0f, 0xb4,0xee,0x96,0xd2, 0x1b,0x9b,0x91,0x9e,
+ 0x80,0xc0,0xc5,0x4f, 0x61,0xdc,0x20,0xa2, 0x5a,0x77,0x4b,0x69, 0x1c,0x12,0x1a,0x16,
+ 0xe2,0x93,0xba,0x0a, 0xc0,0xa0,0x2a,0xe5, 0x3c,0x22,0xe0,0x43, 0x12,0x1b,0x17,0x1d,
+ 0x0e,0x09,0x0d,0x0b, 0xf2,0x8b,0xc7,0xad, 0x2d,0xb6,0xa8,0xb9, 0x14,0x1e,0xa9,0xc8,
+ 0x57,0xf1,0x19,0x85, 0xaf,0x75,0x07,0x4c, 0xee,0x99,0xdd,0xbb, 0xa3,0x7f,0x60,0xfd,
+ 0xf7,0x01,0x26,0x9f, 0x5c,0x72,0xf5,0xbc, 0x44,0x66,0x3b,0xc5, 0x5b,0xfb,0x7e,0x34,
+ 0x8b,0x43,0x29,0x76, 0xcb,0x23,0xc6,0xdc, 0xb6,0xed,0xfc,0x68, 0xb8,0xe4,0xf1,0x63,
+ 0xd7,0x31,0xdc,0xca, 0x42,0x63,0x85,0x10, 0x13,0x97,0x22,0x40, 0x84,0xc6,0x11,0x20,
+ 0x85,0x4a,0x24,0x7d, 0xd2,0xbb,0x3d,0xf8, 0xae,0xf9,0x32,0x11, 0xc7,0x29,0xa1,0x6d,
+ 0x1d,0x9e,0x2f,0x4b, 0xdc,0xb2,0x30,0xf3, 0x0d,0x86,0x52,0xec, 0x77,0xc1,0xe3,0xd0,
+ 0x2b,0xb3,0x16,0x6c, 0xa9,0x70,0xb9,0x99, 0x11,0x94,0x48,0xfa, 0x47,0xe9,0x64,0x22,
+ 0xa8,0xfc,0x8c,0xc4, 0xa0,0xf0,0x3f,0x1a, 0x56,0x7d,0x2c,0xd8, 0x22,0x33,0x90,0xef,
+ 0x87,0x49,0x4e,0xc7, 0xd9,0x38,0xd1,0xc1, 0x8c,0xca,0xa2,0xfe, 0x98,0xd4,0x0b,0x36,
+ 0xa6,0xf5,0x81,0xcf, 0xa5,0x7a,0xde,0x28, 0xda,0xb7,0x8e,0x26, 0x3f,0xad,0xbf,0xa4,
+ 0x2c,0x3a,0x9d,0xe4, 0x50,0x78,0x92,0x0d, 0x6a,0x5f,0xcc,0x9b, 0x54,0x7e,0x46,0x62,
+ 0xf6,0x8d,0x13,0xc2, 0x90,0xd8,0xb8,0xe8, 0x2e,0x39,0xf7,0x5e, 0x82,0xc3,0xaf,0xf5,
+ 0x9f,0x5d,0x80,0xbe, 0x69,0xd0,0x93,0x7c, 0x6f,0xd5,0x2d,0xa9, 0xcf,0x25,0x12,0xb3,
+ 0xc8,0xac,0x99,0x3b, 0x10,0x18,0x7d,0xa7, 0xe8,0x9c,0x63,0x6e, 0xdb,0x3b,0xbb,0x7b,
+ 0xcd,0x26,0x78,0x09, 0x6e,0x59,0x18,0xf4, 0xec,0x9a,0xb7,0x01, 0x83,0x4f,0x9a,0xa8,
+ 0xe6,0x95,0x6e,0x65, 0xaa,0xff,0xe6,0x7e, 0x21,0xbc,0xcf,0x08, 0xef,0x15,0xe8,0xe6,
+ 0xba,0xe7,0x9b,0xd9, 0x4a,0x6f,0x36,0xce, 0xea,0x9f,0x09,0xd4, 0x29,0xb0,0x7c,0xd6,
+ 0x31,0xa4,0xb2,0xaf, 0x2a,0x3f,0x23,0x31, 0xc6,0xa5,0x94,0x30, 0x35,0xa2,0x66,0xc0,
+ 0x74,0x4e,0xbc,0x37, 0xfc,0x82,0xca,0xa6, 0xe0,0x90,0xd0,0xb0, 0x33,0xa7,0xd8,0x15,
+ 0xf1,0x04,0x98,0x4a, 0x41,0xec,0xda,0xf7, 0x7f,0xcd,0x50,0x0e, 0x17,0x91,0xf6,0x2f,
+ 0x76,0x4d,0xd6,0x8d, 0x43,0xef,0xb0,0x4d, 0xcc,0xaa,0x4d,0x54, 0xe4,0x96,0x04,0xdf,
+ 0x9e,0xd1,0xb5,0xe3, 0x4c,0x6a,0x88,0x1b, 0xc1,0x2c,0x1f,0xb8, 0x46,0x65,0x51,0x7f,
+ 0x9d,0x5e,0xea,0x04, 0x01,0x8c,0x35,0x5d, 0xfa,0x87,0x74,0x73, 0xfb,0x0b,0x41,0x2e,
+ 0xb3,0x67,0x1d,0x5a, 0x92,0xdb,0xd2,0x52, 0xe9,0x10,0x56,0x33, 0x6d,0xd6,0x47,0x13,
+ 0x9a,0xd7,0x61,0x8c, 0x37,0xa1,0x0c,0x7a, 0x59,0xf8,0x14,0x8e, 0xeb,0x13,0x3c,0x89,
+ 0xce,0xa9,0x27,0xee, 0xb7,0x61,0xc9,0x35, 0xe1,0x1c,0xe5,0xed, 0x7a,0x47,0xb1,0x3c,
+ 0x9c,0xd2,0xdf,0x59, 0x55,0xf2,0x73,0x3f, 0x18,0x14,0xce,0x79, 0x73,0xc7,0x37,0xbf,
+ 0x53,0xf7,0xcd,0xea, 0x5f,0xfd,0xaa,0x5b, 0xdf,0x3d,0x6f,0x14, 0x78,0x44,0xdb,0x86,
+ 0xca,0xaf,0xf3,0x81, 0xb9,0x68,0xc4,0x3e, 0x38,0x24,0x34,0x2c, 0xc2,0xa3,0x40,0x5f,
+ 0x16,0x1d,0xc3,0x72, 0xbc,0xe2,0x25,0x0c, 0x28,0x3c,0x49,0x8b, 0xff,0x0d,0x95,0x41,
+ 0x39,0xa8,0x01,0x71, 0x08,0x0c,0xb3,0xde, 0xd8,0xb4,0xe4,0x9c, 0x64,0x56,0xc1,0x90,
+ 0x7b,0xcb,0x84,0x61, 0xd5,0x32,0xb6,0x70, 0x48,0x6c,0x5c,0x74, 0xd0,0xb8,0x57,0x42
+};
+
+static uint8_t T6[256][4]=
+{
+ 0x50,0x51,0xf4,0xa7, 0x53,0x7e,0x41,0x65, 0xc3,0x1a,0x17,0xa4, 0x96,0x3a,0x27,0x5e,
+ 0xcb,0x3b,0xab,0x6b, 0xf1,0x1f,0x9d,0x45, 0xab,0xac,0xfa,0x58, 0x93,0x4b,0xe3,0x03,
+ 0x55,0x20,0x30,0xfa, 0xf6,0xad,0x76,0x6d, 0x91,0x88,0xcc,0x76, 0x25,0xf5,0x02,0x4c,
+ 0xfc,0x4f,0xe5,0xd7, 0xd7,0xc5,0x2a,0xcb, 0x80,0x26,0x35,0x44, 0x8f,0xb5,0x62,0xa3,
+ 0x49,0xde,0xb1,0x5a, 0x67,0x25,0xba,0x1b, 0x98,0x45,0xea,0x0e, 0xe1,0x5d,0xfe,0xc0,
+ 0x02,0xc3,0x2f,0x75, 0x12,0x81,0x4c,0xf0, 0xa3,0x8d,0x46,0x97, 0xc6,0x6b,0xd3,0xf9,
+ 0xe7,0x03,0x8f,0x5f, 0x95,0x15,0x92,0x9c, 0xeb,0xbf,0x6d,0x7a, 0xda,0x95,0x52,0x59,
+ 0x2d,0xd4,0xbe,0x83, 0xd3,0x58,0x74,0x21, 0x29,0x49,0xe0,0x69, 0x44,0x8e,0xc9,0xc8,
+ 0x6a,0x75,0xc2,0x89, 0x78,0xf4,0x8e,0x79, 0x6b,0x99,0x58,0x3e, 0xdd,0x27,0xb9,0x71,
+ 0xb6,0xbe,0xe1,0x4f, 0x17,0xf0,0x88,0xad, 0x66,0xc9,0x20,0xac, 0xb4,0x7d,0xce,0x3a,
+ 0x18,0x63,0xdf,0x4a, 0x82,0xe5,0x1a,0x31, 0x60,0x97,0x51,0x33, 0x45,0x62,0x53,0x7f,
+ 0xe0,0xb1,0x64,0x77, 0x84,0xbb,0x6b,0xae, 0x1c,0xfe,0x81,0xa0, 0x94,0xf9,0x08,0x2b,
+ 0x58,0x70,0x48,0x68, 0x19,0x8f,0x45,0xfd, 0x87,0x94,0xde,0x6c, 0xb7,0x52,0x7b,0xf8,
+ 0x23,0xab,0x73,0xd3, 0xe2,0x72,0x4b,0x02, 0x57,0xe3,0x1f,0x8f, 0x2a,0x66,0x55,0xab,
+ 0x07,0xb2,0xeb,0x28, 0x03,0x2f,0xb5,0xc2, 0x9a,0x86,0xc5,0x7b, 0xa5,0xd3,0x37,0x08,
+ 0xf2,0x30,0x28,0x87, 0xb2,0x23,0xbf,0xa5, 0xba,0x02,0x03,0x6a, 0x5c,0xed,0x16,0x82,
+ 0x2b,0x8a,0xcf,0x1c, 0x92,0xa7,0x79,0xb4, 0xf0,0xf3,0x07,0xf2, 0xa1,0x4e,0x69,0xe2,
+ 0xcd,0x65,0xda,0xf4, 0xd5,0x06,0x05,0xbe, 0x1f,0xd1,0x34,0x62, 0x8a,0xc4,0xa6,0xfe,
+ 0x9d,0x34,0x2e,0x53, 0xa0,0xa2,0xf3,0x55, 0x32,0x05,0x8a,0xe1, 0x75,0xa4,0xf6,0xeb,
+ 0x39,0x0b,0x83,0xec, 0xaa,0x40,0x60,0xef, 0x06,0x5e,0x71,0x9f, 0x51,0xbd,0x6e,0x10,
+ 0xf9,0x3e,0x21,0x8a, 0x3d,0x96,0xdd,0x06, 0xae,0xdd,0x3e,0x05, 0x46,0x4d,0xe6,0xbd,
+ 0xb5,0x91,0x54,0x8d, 0x05,0x71,0xc4,0x5d, 0x6f,0x04,0x06,0xd4, 0xff,0x60,0x50,0x15,
+ 0x24,0x19,0x98,0xfb, 0x97,0xd6,0xbd,0xe9, 0xcc,0x89,0x40,0x43, 0x77,0x67,0xd9,0x9e,
+ 0xbd,0xb0,0xe8,0x42, 0x88,0x07,0x89,0x8b, 0x38,0xe7,0x19,0x5b, 0xdb,0x79,0xc8,0xee,
+ 0x47,0xa1,0x7c,0x0a, 0xe9,0x7c,0x42,0x0f, 0xc9,0xf8,0x84,0x1e, 0x00,0x00,0x00,0x00,
+ 0x83,0x09,0x80,0x86, 0x48,0x32,0x2b,0xed, 0xac,0x1e,0x11,0x70, 0x4e,0x6c,0x5a,0x72,
+ 0xfb,0xfd,0x0e,0xff, 0x56,0x0f,0x85,0x38, 0x1e,0x3d,0xae,0xd5, 0x27,0x36,0x2d,0x39,
+ 0x64,0x0a,0x0f,0xd9, 0x21,0x68,0x5c,0xa6, 0xd1,0x9b,0x5b,0x54, 0x3a,0x24,0x36,0x2e,
+ 0xb1,0x0c,0x0a,0x67, 0x0f,0x93,0x57,0xe7, 0xd2,0xb4,0xee,0x96, 0x9e,0x1b,0x9b,0x91,
+ 0x4f,0x80,0xc0,0xc5, 0xa2,0x61,0xdc,0x20, 0x69,0x5a,0x77,0x4b, 0x16,0x1c,0x12,0x1a,
+ 0x0a,0xe2,0x93,0xba, 0xe5,0xc0,0xa0,0x2a, 0x43,0x3c,0x22,0xe0, 0x1d,0x12,0x1b,0x17,
+ 0x0b,0x0e,0x09,0x0d, 0xad,0xf2,0x8b,0xc7, 0xb9,0x2d,0xb6,0xa8, 0xc8,0x14,0x1e,0xa9,
+ 0x85,0x57,0xf1,0x19, 0x4c,0xaf,0x75,0x07, 0xbb,0xee,0x99,0xdd, 0xfd,0xa3,0x7f,0x60,
+ 0x9f,0xf7,0x01,0x26, 0xbc,0x5c,0x72,0xf5, 0xc5,0x44,0x66,0x3b, 0x34,0x5b,0xfb,0x7e,
+ 0x76,0x8b,0x43,0x29, 0xdc,0xcb,0x23,0xc6, 0x68,0xb6,0xed,0xfc, 0x63,0xb8,0xe4,0xf1,
+ 0xca,0xd7,0x31,0xdc, 0x10,0x42,0x63,0x85, 0x40,0x13,0x97,0x22, 0x20,0x84,0xc6,0x11,
+ 0x7d,0x85,0x4a,0x24, 0xf8,0xd2,0xbb,0x3d, 0x11,0xae,0xf9,0x32, 0x6d,0xc7,0x29,0xa1,
+ 0x4b,0x1d,0x9e,0x2f, 0xf3,0xdc,0xb2,0x30, 0xec,0x0d,0x86,0x52, 0xd0,0x77,0xc1,0xe3,
+ 0x6c,0x2b,0xb3,0x16, 0x99,0xa9,0x70,0xb9, 0xfa,0x11,0x94,0x48, 0x22,0x47,0xe9,0x64,
+ 0xc4,0xa8,0xfc,0x8c, 0x1a,0xa0,0xf0,0x3f, 0xd8,0x56,0x7d,0x2c, 0xef,0x22,0x33,0x90,
+ 0xc7,0x87,0x49,0x4e, 0xc1,0xd9,0x38,0xd1, 0xfe,0x8c,0xca,0xa2, 0x36,0x98,0xd4,0x0b,
+ 0xcf,0xa6,0xf5,0x81, 0x28,0xa5,0x7a,0xde, 0x26,0xda,0xb7,0x8e, 0xa4,0x3f,0xad,0xbf,
+ 0xe4,0x2c,0x3a,0x9d, 0x0d,0x50,0x78,0x92, 0x9b,0x6a,0x5f,0xcc, 0x62,0x54,0x7e,0x46,
+ 0xc2,0xf6,0x8d,0x13, 0xe8,0x90,0xd8,0xb8, 0x5e,0x2e,0x39,0xf7, 0xf5,0x82,0xc3,0xaf,
+ 0xbe,0x9f,0x5d,0x80, 0x7c,0x69,0xd0,0x93, 0xa9,0x6f,0xd5,0x2d, 0xb3,0xcf,0x25,0x12,
+ 0x3b,0xc8,0xac,0x99, 0xa7,0x10,0x18,0x7d, 0x6e,0xe8,0x9c,0x63, 0x7b,0xdb,0x3b,0xbb,
+ 0x09,0xcd,0x26,0x78, 0xf4,0x6e,0x59,0x18, 0x01,0xec,0x9a,0xb7, 0xa8,0x83,0x4f,0x9a,
+ 0x65,0xe6,0x95,0x6e, 0x7e,0xaa,0xff,0xe6, 0x08,0x21,0xbc,0xcf, 0xe6,0xef,0x15,0xe8,
+ 0xd9,0xba,0xe7,0x9b, 0xce,0x4a,0x6f,0x36, 0xd4,0xea,0x9f,0x09, 0xd6,0x29,0xb0,0x7c,
+ 0xaf,0x31,0xa4,0xb2, 0x31,0x2a,0x3f,0x23, 0x30,0xc6,0xa5,0x94, 0xc0,0x35,0xa2,0x66,
+ 0x37,0x74,0x4e,0xbc, 0xa6,0xfc,0x82,0xca, 0xb0,0xe0,0x90,0xd0, 0x15,0x33,0xa7,0xd8,
+ 0x4a,0xf1,0x04,0x98, 0xf7,0x41,0xec,0xda, 0x0e,0x7f,0xcd,0x50, 0x2f,0x17,0x91,0xf6,
+ 0x8d,0x76,0x4d,0xd6, 0x4d,0x43,0xef,0xb0, 0x54,0xcc,0xaa,0x4d, 0xdf,0xe4,0x96,0x04,
+ 0xe3,0x9e,0xd1,0xb5, 0x1b,0x4c,0x6a,0x88, 0xb8,0xc1,0x2c,0x1f, 0x7f,0x46,0x65,0x51,
+ 0x04,0x9d,0x5e,0xea, 0x5d,0x01,0x8c,0x35, 0x73,0xfa,0x87,0x74, 0x2e,0xfb,0x0b,0x41,
+ 0x5a,0xb3,0x67,0x1d, 0x52,0x92,0xdb,0xd2, 0x33,0xe9,0x10,0x56, 0x13,0x6d,0xd6,0x47,
+ 0x8c,0x9a,0xd7,0x61, 0x7a,0x37,0xa1,0x0c, 0x8e,0x59,0xf8,0x14, 0x89,0xeb,0x13,0x3c,
+ 0xee,0xce,0xa9,0x27, 0x35,0xb7,0x61,0xc9, 0xed,0xe1,0x1c,0xe5, 0x3c,0x7a,0x47,0xb1,
+ 0x59,0x9c,0xd2,0xdf, 0x3f,0x55,0xf2,0x73, 0x79,0x18,0x14,0xce, 0xbf,0x73,0xc7,0x37,
+ 0xea,0x53,0xf7,0xcd, 0x5b,0x5f,0xfd,0xaa, 0x14,0xdf,0x3d,0x6f, 0x86,0x78,0x44,0xdb,
+ 0x81,0xca,0xaf,0xf3, 0x3e,0xb9,0x68,0xc4, 0x2c,0x38,0x24,0x34, 0x5f,0xc2,0xa3,0x40,
+ 0x72,0x16,0x1d,0xc3, 0x0c,0xbc,0xe2,0x25, 0x8b,0x28,0x3c,0x49, 0x41,0xff,0x0d,0x95,
+ 0x71,0x39,0xa8,0x01, 0xde,0x08,0x0c,0xb3, 0x9c,0xd8,0xb4,0xe4, 0x90,0x64,0x56,0xc1,
+ 0x61,0x7b,0xcb,0x84, 0x70,0xd5,0x32,0xb6, 0x74,0x48,0x6c,0x5c, 0x42,0xd0,0xb8,0x57
+};
+
+static uint8_t T7[256][4]=
+{
+ 0xa7,0x50,0x51,0xf4, 0x65,0x53,0x7e,0x41, 0xa4,0xc3,0x1a,0x17, 0x5e,0x96,0x3a,0x27,
+ 0x6b,0xcb,0x3b,0xab, 0x45,0xf1,0x1f,0x9d, 0x58,0xab,0xac,0xfa, 0x03,0x93,0x4b,0xe3,
+ 0xfa,0x55,0x20,0x30, 0x6d,0xf6,0xad,0x76, 0x76,0x91,0x88,0xcc, 0x4c,0x25,0xf5,0x02,
+ 0xd7,0xfc,0x4f,0xe5, 0xcb,0xd7,0xc5,0x2a, 0x44,0x80,0x26,0x35, 0xa3,0x8f,0xb5,0x62,
+ 0x5a,0x49,0xde,0xb1, 0x1b,0x67,0x25,0xba, 0x0e,0x98,0x45,0xea, 0xc0,0xe1,0x5d,0xfe,
+ 0x75,0x02,0xc3,0x2f, 0xf0,0x12,0x81,0x4c, 0x97,0xa3,0x8d,0x46, 0xf9,0xc6,0x6b,0xd3,
+ 0x5f,0xe7,0x03,0x8f, 0x9c,0x95,0x15,0x92, 0x7a,0xeb,0xbf,0x6d, 0x59,0xda,0x95,0x52,
+ 0x83,0x2d,0xd4,0xbe, 0x21,0xd3,0x58,0x74, 0x69,0x29,0x49,0xe0, 0xc8,0x44,0x8e,0xc9,
+ 0x89,0x6a,0x75,0xc2, 0x79,0x78,0xf4,0x8e, 0x3e,0x6b,0x99,0x58, 0x71,0xdd,0x27,0xb9,
+ 0x4f,0xb6,0xbe,0xe1, 0xad,0x17,0xf0,0x88, 0xac,0x66,0xc9,0x20, 0x3a,0xb4,0x7d,0xce,
+ 0x4a,0x18,0x63,0xdf, 0x31,0x82,0xe5,0x1a, 0x33,0x60,0x97,0x51, 0x7f,0x45,0x62,0x53,
+ 0x77,0xe0,0xb1,0x64, 0xae,0x84,0xbb,0x6b, 0xa0,0x1c,0xfe,0x81, 0x2b,0x94,0xf9,0x08,
+ 0x68,0x58,0x70,0x48, 0xfd,0x19,0x8f,0x45, 0x6c,0x87,0x94,0xde, 0xf8,0xb7,0x52,0x7b,
+ 0xd3,0x23,0xab,0x73, 0x02,0xe2,0x72,0x4b, 0x8f,0x57,0xe3,0x1f, 0xab,0x2a,0x66,0x55,
+ 0x28,0x07,0xb2,0xeb, 0xc2,0x03,0x2f,0xb5, 0x7b,0x9a,0x86,0xc5, 0x08,0xa5,0xd3,0x37,
+ 0x87,0xf2,0x30,0x28, 0xa5,0xb2,0x23,0xbf, 0x6a,0xba,0x02,0x03, 0x82,0x5c,0xed,0x16,
+ 0x1c,0x2b,0x8a,0xcf, 0xb4,0x92,0xa7,0x79, 0xf2,0xf0,0xf3,0x07, 0xe2,0xa1,0x4e,0x69,
+ 0xf4,0xcd,0x65,0xda, 0xbe,0xd5,0x06,0x05, 0x62,0x1f,0xd1,0x34, 0xfe,0x8a,0xc4,0xa6,
+ 0x53,0x9d,0x34,0x2e, 0x55,0xa0,0xa2,0xf3, 0xe1,0x32,0x05,0x8a, 0xeb,0x75,0xa4,0xf6,
+ 0xec,0x39,0x0b,0x83, 0xef,0xaa,0x40,0x60, 0x9f,0x06,0x5e,0x71, 0x10,0x51,0xbd,0x6e,
+ 0x8a,0xf9,0x3e,0x21, 0x06,0x3d,0x96,0xdd, 0x05,0xae,0xdd,0x3e, 0xbd,0x46,0x4d,0xe6,
+ 0x8d,0xb5,0x91,0x54, 0x5d,0x05,0x71,0xc4, 0xd4,0x6f,0x04,0x06, 0x15,0xff,0x60,0x50,
+ 0xfb,0x24,0x19,0x98, 0xe9,0x97,0xd6,0xbd, 0x43,0xcc,0x89,0x40, 0x9e,0x77,0x67,0xd9,
+ 0x42,0xbd,0xb0,0xe8, 0x8b,0x88,0x07,0x89, 0x5b,0x38,0xe7,0x19, 0xee,0xdb,0x79,0xc8,
+ 0x0a,0x47,0xa1,0x7c, 0x0f,0xe9,0x7c,0x42, 0x1e,0xc9,0xf8,0x84, 0x00,0x00,0x00,0x00,
+ 0x86,0x83,0x09,0x80, 0xed,0x48,0x32,0x2b, 0x70,0xac,0x1e,0x11, 0x72,0x4e,0x6c,0x5a,
+ 0xff,0xfb,0xfd,0x0e, 0x38,0x56,0x0f,0x85, 0xd5,0x1e,0x3d,0xae, 0x39,0x27,0x36,0x2d,
+ 0xd9,0x64,0x0a,0x0f, 0xa6,0x21,0x68,0x5c, 0x54,0xd1,0x9b,0x5b, 0x2e,0x3a,0x24,0x36,
+ 0x67,0xb1,0x0c,0x0a, 0xe7,0x0f,0x93,0x57, 0x96,0xd2,0xb4,0xee, 0x91,0x9e,0x1b,0x9b,
+ 0xc5,0x4f,0x80,0xc0, 0x20,0xa2,0x61,0xdc, 0x4b,0x69,0x5a,0x77, 0x1a,0x16,0x1c,0x12,
+ 0xba,0x0a,0xe2,0x93, 0x2a,0xe5,0xc0,0xa0, 0xe0,0x43,0x3c,0x22, 0x17,0x1d,0x12,0x1b,
+ 0x0d,0x0b,0x0e,0x09, 0xc7,0xad,0xf2,0x8b, 0xa8,0xb9,0x2d,0xb6, 0xa9,0xc8,0x14,0x1e,
+ 0x19,0x85,0x57,0xf1, 0x07,0x4c,0xaf,0x75, 0xdd,0xbb,0xee,0x99, 0x60,0xfd,0xa3,0x7f,
+ 0x26,0x9f,0xf7,0x01, 0xf5,0xbc,0x5c,0x72, 0x3b,0xc5,0x44,0x66, 0x7e,0x34,0x5b,0xfb,
+ 0x29,0x76,0x8b,0x43, 0xc6,0xdc,0xcb,0x23, 0xfc,0x68,0xb6,0xed, 0xf1,0x63,0xb8,0xe4,
+ 0xdc,0xca,0xd7,0x31, 0x85,0x10,0x42,0x63, 0x22,0x40,0x13,0x97, 0x11,0x20,0x84,0xc6,
+ 0x24,0x7d,0x85,0x4a, 0x3d,0xf8,0xd2,0xbb, 0x32,0x11,0xae,0xf9, 0xa1,0x6d,0xc7,0x29,
+ 0x2f,0x4b,0x1d,0x9e, 0x30,0xf3,0xdc,0xb2, 0x52,0xec,0x0d,0x86, 0xe3,0xd0,0x77,0xc1,
+ 0x16,0x6c,0x2b,0xb3, 0xb9,0x99,0xa9,0x70, 0x48,0xfa,0x11,0x94, 0x64,0x22,0x47,0xe9,
+ 0x8c,0xc4,0xa8,0xfc, 0x3f,0x1a,0xa0,0xf0, 0x2c,0xd8,0x56,0x7d, 0x90,0xef,0x22,0x33,
+ 0x4e,0xc7,0x87,0x49, 0xd1,0xc1,0xd9,0x38, 0xa2,0xfe,0x8c,0xca, 0x0b,0x36,0x98,0xd4,
+ 0x81,0xcf,0xa6,0xf5, 0xde,0x28,0xa5,0x7a, 0x8e,0x26,0xda,0xb7, 0xbf,0xa4,0x3f,0xad,
+ 0x9d,0xe4,0x2c,0x3a, 0x92,0x0d,0x50,0x78, 0xcc,0x9b,0x6a,0x5f, 0x46,0x62,0x54,0x7e,
+ 0x13,0xc2,0xf6,0x8d, 0xb8,0xe8,0x90,0xd8, 0xf7,0x5e,0x2e,0x39, 0xaf,0xf5,0x82,0xc3,
+ 0x80,0xbe,0x9f,0x5d, 0x93,0x7c,0x69,0xd0, 0x2d,0xa9,0x6f,0xd5, 0x12,0xb3,0xcf,0x25,
+ 0x99,0x3b,0xc8,0xac, 0x7d,0xa7,0x10,0x18, 0x63,0x6e,0xe8,0x9c, 0xbb,0x7b,0xdb,0x3b,
+ 0x78,0x09,0xcd,0x26, 0x18,0xf4,0x6e,0x59, 0xb7,0x01,0xec,0x9a, 0x9a,0xa8,0x83,0x4f,
+ 0x6e,0x65,0xe6,0x95, 0xe6,0x7e,0xaa,0xff, 0xcf,0x08,0x21,0xbc, 0xe8,0xe6,0xef,0x15,
+ 0x9b,0xd9,0xba,0xe7, 0x36,0xce,0x4a,0x6f, 0x09,0xd4,0xea,0x9f, 0x7c,0xd6,0x29,0xb0,
+ 0xb2,0xaf,0x31,0xa4, 0x23,0x31,0x2a,0x3f, 0x94,0x30,0xc6,0xa5, 0x66,0xc0,0x35,0xa2,
+ 0xbc,0x37,0x74,0x4e, 0xca,0xa6,0xfc,0x82, 0xd0,0xb0,0xe0,0x90, 0xd8,0x15,0x33,0xa7,
+ 0x98,0x4a,0xf1,0x04, 0xda,0xf7,0x41,0xec, 0x50,0x0e,0x7f,0xcd, 0xf6,0x2f,0x17,0x91,
+ 0xd6,0x8d,0x76,0x4d, 0xb0,0x4d,0x43,0xef, 0x4d,0x54,0xcc,0xaa, 0x04,0xdf,0xe4,0x96,
+ 0xb5,0xe3,0x9e,0xd1, 0x88,0x1b,0x4c,0x6a, 0x1f,0xb8,0xc1,0x2c, 0x51,0x7f,0x46,0x65,
+ 0xea,0x04,0x9d,0x5e, 0x35,0x5d,0x01,0x8c, 0x74,0x73,0xfa,0x87, 0x41,0x2e,0xfb,0x0b,
+ 0x1d,0x5a,0xb3,0x67, 0xd2,0x52,0x92,0xdb, 0x56,0x33,0xe9,0x10, 0x47,0x13,0x6d,0xd6,
+ 0x61,0x8c,0x9a,0xd7, 0x0c,0x7a,0x37,0xa1, 0x14,0x8e,0x59,0xf8, 0x3c,0x89,0xeb,0x13,
+ 0x27,0xee,0xce,0xa9, 0xc9,0x35,0xb7,0x61, 0xe5,0xed,0xe1,0x1c, 0xb1,0x3c,0x7a,0x47,
+ 0xdf,0x59,0x9c,0xd2, 0x73,0x3f,0x55,0xf2, 0xce,0x79,0x18,0x14, 0x37,0xbf,0x73,0xc7,
+ 0xcd,0xea,0x53,0xf7, 0xaa,0x5b,0x5f,0xfd, 0x6f,0x14,0xdf,0x3d, 0xdb,0x86,0x78,0x44,
+ 0xf3,0x81,0xca,0xaf, 0xc4,0x3e,0xb9,0x68, 0x34,0x2c,0x38,0x24, 0x40,0x5f,0xc2,0xa3,
+ 0xc3,0x72,0x16,0x1d, 0x25,0x0c,0xbc,0xe2, 0x49,0x8b,0x28,0x3c, 0x95,0x41,0xff,0x0d,
+ 0x01,0x71,0x39,0xa8, 0xb3,0xde,0x08,0x0c, 0xe4,0x9c,0xd8,0xb4, 0xc1,0x90,0x64,0x56,
+ 0x84,0x61,0x7b,0xcb, 0xb6,0x70,0xd5,0x32, 0x5c,0x74,0x48,0x6c, 0x57,0x42,0xd0,0xb8
+};
+
+static uint8_t T8[256][4]=
+{
+ 0xf4,0xa7,0x50,0x51, 0x41,0x65,0x53,0x7e, 0x17,0xa4,0xc3,0x1a, 0x27,0x5e,0x96,0x3a,
+ 0xab,0x6b,0xcb,0x3b, 0x9d,0x45,0xf1,0x1f, 0xfa,0x58,0xab,0xac, 0xe3,0x03,0x93,0x4b,
+ 0x30,0xfa,0x55,0x20, 0x76,0x6d,0xf6,0xad, 0xcc,0x76,0x91,0x88, 0x02,0x4c,0x25,0xf5,
+ 0xe5,0xd7,0xfc,0x4f, 0x2a,0xcb,0xd7,0xc5, 0x35,0x44,0x80,0x26, 0x62,0xa3,0x8f,0xb5,
+ 0xb1,0x5a,0x49,0xde, 0xba,0x1b,0x67,0x25, 0xea,0x0e,0x98,0x45, 0xfe,0xc0,0xe1,0x5d,
+ 0x2f,0x75,0x02,0xc3, 0x4c,0xf0,0x12,0x81, 0x46,0x97,0xa3,0x8d, 0xd3,0xf9,0xc6,0x6b,
+ 0x8f,0x5f,0xe7,0x03, 0x92,0x9c,0x95,0x15, 0x6d,0x7a,0xeb,0xbf, 0x52,0x59,0xda,0x95,
+ 0xbe,0x83,0x2d,0xd4, 0x74,0x21,0xd3,0x58, 0xe0,0x69,0x29,0x49, 0xc9,0xc8,0x44,0x8e,
+ 0xc2,0x89,0x6a,0x75, 0x8e,0x79,0x78,0xf4, 0x58,0x3e,0x6b,0x99, 0xb9,0x71,0xdd,0x27,
+ 0xe1,0x4f,0xb6,0xbe, 0x88,0xad,0x17,0xf0, 0x20,0xac,0x66,0xc9, 0xce,0x3a,0xb4,0x7d,
+ 0xdf,0x4a,0x18,0x63, 0x1a,0x31,0x82,0xe5, 0x51,0x33,0x60,0x97, 0x53,0x7f,0x45,0x62,
+ 0x64,0x77,0xe0,0xb1, 0x6b,0xae,0x84,0xbb, 0x81,0xa0,0x1c,0xfe, 0x08,0x2b,0x94,0xf9,
+ 0x48,0x68,0x58,0x70, 0x45,0xfd,0x19,0x8f, 0xde,0x6c,0x87,0x94, 0x7b,0xf8,0xb7,0x52,
+ 0x73,0xd3,0x23,0xab, 0x4b,0x02,0xe2,0x72, 0x1f,0x8f,0x57,0xe3, 0x55,0xab,0x2a,0x66,
+ 0xeb,0x28,0x07,0xb2, 0xb5,0xc2,0x03,0x2f, 0xc5,0x7b,0x9a,0x86, 0x37,0x08,0xa5,0xd3,
+ 0x28,0x87,0xf2,0x30, 0xbf,0xa5,0xb2,0x23, 0x03,0x6a,0xba,0x02, 0x16,0x82,0x5c,0xed,
+ 0xcf,0x1c,0x2b,0x8a, 0x79,0xb4,0x92,0xa7, 0x07,0xf2,0xf0,0xf3, 0x69,0xe2,0xa1,0x4e,
+ 0xda,0xf4,0xcd,0x65, 0x05,0xbe,0xd5,0x06, 0x34,0x62,0x1f,0xd1, 0xa6,0xfe,0x8a,0xc4,
+ 0x2e,0x53,0x9d,0x34, 0xf3,0x55,0xa0,0xa2, 0x8a,0xe1,0x32,0x05, 0xf6,0xeb,0x75,0xa4,
+ 0x83,0xec,0x39,0x0b, 0x60,0xef,0xaa,0x40, 0x71,0x9f,0x06,0x5e, 0x6e,0x10,0x51,0xbd,
+ 0x21,0x8a,0xf9,0x3e, 0xdd,0x06,0x3d,0x96, 0x3e,0x05,0xae,0xdd, 0xe6,0xbd,0x46,0x4d,
+ 0x54,0x8d,0xb5,0x91, 0xc4,0x5d,0x05,0x71, 0x06,0xd4,0x6f,0x04, 0x50,0x15,0xff,0x60,
+ 0x98,0xfb,0x24,0x19, 0xbd,0xe9,0x97,0xd6, 0x40,0x43,0xcc,0x89, 0xd9,0x9e,0x77,0x67,
+ 0xe8,0x42,0xbd,0xb0, 0x89,0x8b,0x88,0x07, 0x19,0x5b,0x38,0xe7, 0xc8,0xee,0xdb,0x79,
+ 0x7c,0x0a,0x47,0xa1, 0x42,0x0f,0xe9,0x7c, 0x84,0x1e,0xc9,0xf8, 0x00,0x00,0x00,0x00,
+ 0x80,0x86,0x83,0x09, 0x2b,0xed,0x48,0x32, 0x11,0x70,0xac,0x1e, 0x5a,0x72,0x4e,0x6c,
+ 0x0e,0xff,0xfb,0xfd, 0x85,0x38,0x56,0x0f, 0xae,0xd5,0x1e,0x3d, 0x2d,0x39,0x27,0x36,
+ 0x0f,0xd9,0x64,0x0a, 0x5c,0xa6,0x21,0x68, 0x5b,0x54,0xd1,0x9b, 0x36,0x2e,0x3a,0x24,
+ 0x0a,0x67,0xb1,0x0c, 0x57,0xe7,0x0f,0x93, 0xee,0x96,0xd2,0xb4, 0x9b,0x91,0x9e,0x1b,
+ 0xc0,0xc5,0x4f,0x80, 0xdc,0x20,0xa2,0x61, 0x77,0x4b,0x69,0x5a, 0x12,0x1a,0x16,0x1c,
+ 0x93,0xba,0x0a,0xe2, 0xa0,0x2a,0xe5,0xc0, 0x22,0xe0,0x43,0x3c, 0x1b,0x17,0x1d,0x12,
+ 0x09,0x0d,0x0b,0x0e, 0x8b,0xc7,0xad,0xf2, 0xb6,0xa8,0xb9,0x2d, 0x1e,0xa9,0xc8,0x14,
+ 0xf1,0x19,0x85,0x57, 0x75,0x07,0x4c,0xaf, 0x99,0xdd,0xbb,0xee, 0x7f,0x60,0xfd,0xa3,
+ 0x01,0x26,0x9f,0xf7, 0x72,0xf5,0xbc,0x5c, 0x66,0x3b,0xc5,0x44, 0xfb,0x7e,0x34,0x5b,
+ 0x43,0x29,0x76,0x8b, 0x23,0xc6,0xdc,0xcb, 0xed,0xfc,0x68,0xb6, 0xe4,0xf1,0x63,0xb8,
+ 0x31,0xdc,0xca,0xd7, 0x63,0x85,0x10,0x42, 0x97,0x22,0x40,0x13, 0xc6,0x11,0x20,0x84,
+ 0x4a,0x24,0x7d,0x85, 0xbb,0x3d,0xf8,0xd2, 0xf9,0x32,0x11,0xae, 0x29,0xa1,0x6d,0xc7,
+ 0x9e,0x2f,0x4b,0x1d, 0xb2,0x30,0xf3,0xdc, 0x86,0x52,0xec,0x0d, 0xc1,0xe3,0xd0,0x77,
+ 0xb3,0x16,0x6c,0x2b, 0x70,0xb9,0x99,0xa9, 0x94,0x48,0xfa,0x11, 0xe9,0x64,0x22,0x47,
+ 0xfc,0x8c,0xc4,0xa8, 0xf0,0x3f,0x1a,0xa0, 0x7d,0x2c,0xd8,0x56, 0x33,0x90,0xef,0x22,
+ 0x49,0x4e,0xc7,0x87, 0x38,0xd1,0xc1,0xd9, 0xca,0xa2,0xfe,0x8c, 0xd4,0x0b,0x36,0x98,
+ 0xf5,0x81,0xcf,0xa6, 0x7a,0xde,0x28,0xa5, 0xb7,0x8e,0x26,0xda, 0xad,0xbf,0xa4,0x3f,
+ 0x3a,0x9d,0xe4,0x2c, 0x78,0x92,0x0d,0x50, 0x5f,0xcc,0x9b,0x6a, 0x7e,0x46,0x62,0x54,
+ 0x8d,0x13,0xc2,0xf6, 0xd8,0xb8,0xe8,0x90, 0x39,0xf7,0x5e,0x2e, 0xc3,0xaf,0xf5,0x82,
+ 0x5d,0x80,0xbe,0x9f, 0xd0,0x93,0x7c,0x69, 0xd5,0x2d,0xa9,0x6f, 0x25,0x12,0xb3,0xcf,
+ 0xac,0x99,0x3b,0xc8, 0x18,0x7d,0xa7,0x10, 0x9c,0x63,0x6e,0xe8, 0x3b,0xbb,0x7b,0xdb,
+ 0x26,0x78,0x09,0xcd, 0x59,0x18,0xf4,0x6e, 0x9a,0xb7,0x01,0xec, 0x4f,0x9a,0xa8,0x83,
+ 0x95,0x6e,0x65,0xe6, 0xff,0xe6,0x7e,0xaa, 0xbc,0xcf,0x08,0x21, 0x15,0xe8,0xe6,0xef,
+ 0xe7,0x9b,0xd9,0xba, 0x6f,0x36,0xce,0x4a, 0x9f,0x09,0xd4,0xea, 0xb0,0x7c,0xd6,0x29,
+ 0xa4,0xb2,0xaf,0x31, 0x3f,0x23,0x31,0x2a, 0xa5,0x94,0x30,0xc6, 0xa2,0x66,0xc0,0x35,
+ 0x4e,0xbc,0x37,0x74, 0x82,0xca,0xa6,0xfc, 0x90,0xd0,0xb0,0xe0, 0xa7,0xd8,0x15,0x33,
+ 0x04,0x98,0x4a,0xf1, 0xec,0xda,0xf7,0x41, 0xcd,0x50,0x0e,0x7f, 0x91,0xf6,0x2f,0x17,
+ 0x4d,0xd6,0x8d,0x76, 0xef,0xb0,0x4d,0x43, 0xaa,0x4d,0x54,0xcc, 0x96,0x04,0xdf,0xe4,
+ 0xd1,0xb5,0xe3,0x9e, 0x6a,0x88,0x1b,0x4c, 0x2c,0x1f,0xb8,0xc1, 0x65,0x51,0x7f,0x46,
+ 0x5e,0xea,0x04,0x9d, 0x8c,0x35,0x5d,0x01, 0x87,0x74,0x73,0xfa, 0x0b,0x41,0x2e,0xfb,
+ 0x67,0x1d,0x5a,0xb3, 0xdb,0xd2,0x52,0x92, 0x10,0x56,0x33,0xe9, 0xd6,0x47,0x13,0x6d,
+ 0xd7,0x61,0x8c,0x9a, 0xa1,0x0c,0x7a,0x37, 0xf8,0x14,0x8e,0x59, 0x13,0x3c,0x89,0xeb,
+ 0xa9,0x27,0xee,0xce, 0x61,0xc9,0x35,0xb7, 0x1c,0xe5,0xed,0xe1, 0x47,0xb1,0x3c,0x7a,
+ 0xd2,0xdf,0x59,0x9c, 0xf2,0x73,0x3f,0x55, 0x14,0xce,0x79,0x18, 0xc7,0x37,0xbf,0x73,
+ 0xf7,0xcd,0xea,0x53, 0xfd,0xaa,0x5b,0x5f, 0x3d,0x6f,0x14,0xdf, 0x44,0xdb,0x86,0x78,
+ 0xaf,0xf3,0x81,0xca, 0x68,0xc4,0x3e,0xb9, 0x24,0x34,0x2c,0x38, 0xa3,0x40,0x5f,0xc2,
+ 0x1d,0xc3,0x72,0x16, 0xe2,0x25,0x0c,0xbc, 0x3c,0x49,0x8b,0x28, 0x0d,0x95,0x41,0xff,
+ 0xa8,0x01,0x71,0x39, 0x0c,0xb3,0xde,0x08, 0xb4,0xe4,0x9c,0xd8, 0x56,0xc1,0x90,0x64,
+ 0xcb,0x84,0x61,0x7b, 0x32,0xb6,0x70,0xd5, 0x6c,0x5c,0x74,0x48, 0xb8,0x57,0x42,0xd0
+};
+
+static uint8_t S5[256]=
+{
+ 0x52,0x09,0x6a,0xd5,
+ 0x30,0x36,0xa5,0x38,
+ 0xbf,0x40,0xa3,0x9e,
+ 0x81,0xf3,0xd7,0xfb,
+ 0x7c,0xe3,0x39,0x82,
+ 0x9b,0x2f,0xff,0x87,
+ 0x34,0x8e,0x43,0x44,
+ 0xc4,0xde,0xe9,0xcb,
+ 0x54,0x7b,0x94,0x32,
+ 0xa6,0xc2,0x23,0x3d,
+ 0xee,0x4c,0x95,0x0b,
+ 0x42,0xfa,0xc3,0x4e,
+ 0x08,0x2e,0xa1,0x66,
+ 0x28,0xd9,0x24,0xb2,
+ 0x76,0x5b,0xa2,0x49,
+ 0x6d,0x8b,0xd1,0x25,
+ 0x72,0xf8,0xf6,0x64,
+ 0x86,0x68,0x98,0x16,
+ 0xd4,0xa4,0x5c,0xcc,
+ 0x5d,0x65,0xb6,0x92,
+ 0x6c,0x70,0x48,0x50,
+ 0xfd,0xed,0xb9,0xda,
+ 0x5e,0x15,0x46,0x57,
+ 0xa7,0x8d,0x9d,0x84,
+ 0x90,0xd8,0xab,0x00,
+ 0x8c,0xbc,0xd3,0x0a,
+ 0xf7,0xe4,0x58,0x05,
+ 0xb8,0xb3,0x45,0x06,
+ 0xd0,0x2c,0x1e,0x8f,
+ 0xca,0x3f,0x0f,0x02,
+ 0xc1,0xaf,0xbd,0x03,
+ 0x01,0x13,0x8a,0x6b,
+ 0x3a,0x91,0x11,0x41,
+ 0x4f,0x67,0xdc,0xea,
+ 0x97,0xf2,0xcf,0xce,
+ 0xf0,0xb4,0xe6,0x73,
+ 0x96,0xac,0x74,0x22,
+ 0xe7,0xad,0x35,0x85,
+ 0xe2,0xf9,0x37,0xe8,
+ 0x1c,0x75,0xdf,0x6e,
+ 0x47,0xf1,0x1a,0x71,
+ 0x1d,0x29,0xc5,0x89,
+ 0x6f,0xb7,0x62,0x0e,
+ 0xaa,0x18,0xbe,0x1b,
+ 0xfc,0x56,0x3e,0x4b,
+ 0xc6,0xd2,0x79,0x20,
+ 0x9a,0xdb,0xc0,0xfe,
+ 0x78,0xcd,0x5a,0xf4,
+ 0x1f,0xdd,0xa8,0x33,
+ 0x88,0x07,0xc7,0x31,
+ 0xb1,0x12,0x10,0x59,
+ 0x27,0x80,0xec,0x5f,
+ 0x60,0x51,0x7f,0xa9,
+ 0x19,0xb5,0x4a,0x0d,
+ 0x2d,0xe5,0x7a,0x9f,
+ 0x93,0xc9,0x9c,0xef,
+ 0xa0,0xe0,0x3b,0x4d,
+ 0xae,0x2a,0xf5,0xb0,
+ 0xc8,0xeb,0xbb,0x3c,
+ 0x83,0x53,0x99,0x61,
+ 0x17,0x2b,0x04,0x7e,
+ 0xba,0x77,0xd6,0x26,
+ 0xe1,0x69,0x14,0x63,
+ 0x55,0x21,0x0c,0x7d
+};
+
+static uint8_t U1[256][4]=
+{
+ 0x00,0x00,0x00,0x00, 0x0e,0x09,0x0d,0x0b, 0x1c,0x12,0x1a,0x16, 0x12,0x1b,0x17,0x1d,
+ 0x38,0x24,0x34,0x2c, 0x36,0x2d,0x39,0x27, 0x24,0x36,0x2e,0x3a, 0x2a,0x3f,0x23,0x31,
+ 0x70,0x48,0x68,0x58, 0x7e,0x41,0x65,0x53, 0x6c,0x5a,0x72,0x4e, 0x62,0x53,0x7f,0x45,
+ 0x48,0x6c,0x5c,0x74, 0x46,0x65,0x51,0x7f, 0x54,0x7e,0x46,0x62, 0x5a,0x77,0x4b,0x69,
+ 0xe0,0x90,0xd0,0xb0, 0xee,0x99,0xdd,0xbb, 0xfc,0x82,0xca,0xa6, 0xf2,0x8b,0xc7,0xad,
+ 0xd8,0xb4,0xe4,0x9c, 0xd6,0xbd,0xe9,0x97, 0xc4,0xa6,0xfe,0x8a, 0xca,0xaf,0xf3,0x81,
+ 0x90,0xd8,0xb8,0xe8, 0x9e,0xd1,0xb5,0xe3, 0x8c,0xca,0xa2,0xfe, 0x82,0xc3,0xaf,0xf5,
+ 0xa8,0xfc,0x8c,0xc4, 0xa6,0xf5,0x81,0xcf, 0xb4,0xee,0x96,0xd2, 0xba,0xe7,0x9b,0xd9,
+ 0xdb,0x3b,0xbb,0x7b, 0xd5,0x32,0xb6,0x70, 0xc7,0x29,0xa1,0x6d, 0xc9,0x20,0xac,0x66,
+ 0xe3,0x1f,0x8f,0x57, 0xed,0x16,0x82,0x5c, 0xff,0x0d,0x95,0x41, 0xf1,0x04,0x98,0x4a,
+ 0xab,0x73,0xd3,0x23, 0xa5,0x7a,0xde,0x28, 0xb7,0x61,0xc9,0x35, 0xb9,0x68,0xc4,0x3e,
+ 0x93,0x57,0xe7,0x0f, 0x9d,0x5e,0xea,0x04, 0x8f,0x45,0xfd,0x19, 0x81,0x4c,0xf0,0x12,
+ 0x3b,0xab,0x6b,0xcb, 0x35,0xa2,0x66,0xc0, 0x27,0xb9,0x71,0xdd, 0x29,0xb0,0x7c,0xd6,
+ 0x03,0x8f,0x5f,0xe7, 0x0d,0x86,0x52,0xec, 0x1f,0x9d,0x45,0xf1, 0x11,0x94,0x48,0xfa,
+ 0x4b,0xe3,0x03,0x93, 0x45,0xea,0x0e,0x98, 0x57,0xf1,0x19,0x85, 0x59,0xf8,0x14,0x8e,
+ 0x73,0xc7,0x37,0xbf, 0x7d,0xce,0x3a,0xb4, 0x6f,0xd5,0x2d,0xa9, 0x61,0xdc,0x20,0xa2,
+ 0xad,0x76,0x6d,0xf6, 0xa3,0x7f,0x60,0xfd, 0xb1,0x64,0x77,0xe0, 0xbf,0x6d,0x7a,0xeb,
+ 0x95,0x52,0x59,0xda, 0x9b,0x5b,0x54,0xd1, 0x89,0x40,0x43,0xcc, 0x87,0x49,0x4e,0xc7,
+ 0xdd,0x3e,0x05,0xae, 0xd3,0x37,0x08,0xa5, 0xc1,0x2c,0x1f,0xb8, 0xcf,0x25,0x12,0xb3,
+ 0xe5,0x1a,0x31,0x82, 0xeb,0x13,0x3c,0x89, 0xf9,0x08,0x2b,0x94, 0xf7,0x01,0x26,0x9f,
+ 0x4d,0xe6,0xbd,0x46, 0x43,0xef,0xb0,0x4d, 0x51,0xf4,0xa7,0x50, 0x5f,0xfd,0xaa,0x5b,
+ 0x75,0xc2,0x89,0x6a, 0x7b,0xcb,0x84,0x61, 0x69,0xd0,0x93,0x7c, 0x67,0xd9,0x9e,0x77,
+ 0x3d,0xae,0xd5,0x1e, 0x33,0xa7,0xd8,0x15, 0x21,0xbc,0xcf,0x08, 0x2f,0xb5,0xc2,0x03,
+ 0x05,0x8a,0xe1,0x32, 0x0b,0x83,0xec,0x39, 0x19,0x98,0xfb,0x24, 0x17,0x91,0xf6,0x2f,
+ 0x76,0x4d,0xd6,0x8d, 0x78,0x44,0xdb,0x86, 0x6a,0x5f,0xcc,0x9b, 0x64,0x56,0xc1,0x90,
+ 0x4e,0x69,0xe2,0xa1, 0x40,0x60,0xef,0xaa, 0x52,0x7b,0xf8,0xb7, 0x5c,0x72,0xf5,0xbc,
+ 0x06,0x05,0xbe,0xd5, 0x08,0x0c,0xb3,0xde, 0x1a,0x17,0xa4,0xc3, 0x14,0x1e,0xa9,0xc8,
+ 0x3e,0x21,0x8a,0xf9, 0x30,0x28,0x87,0xf2, 0x22,0x33,0x90,0xef, 0x2c,0x3a,0x9d,0xe4,
+ 0x96,0xdd,0x06,0x3d, 0x98,0xd4,0x0b,0x36, 0x8a,0xcf,0x1c,0x2b, 0x84,0xc6,0x11,0x20,
+ 0xae,0xf9,0x32,0x11, 0xa0,0xf0,0x3f,0x1a, 0xb2,0xeb,0x28,0x07, 0xbc,0xe2,0x25,0x0c,
+ 0xe6,0x95,0x6e,0x65, 0xe8,0x9c,0x63,0x6e, 0xfa,0x87,0x74,0x73, 0xf4,0x8e,0x79,0x78,
+ 0xde,0xb1,0x5a,0x49, 0xd0,0xb8,0x57,0x42, 0xc2,0xa3,0x40,0x5f, 0xcc,0xaa,0x4d,0x54,
+ 0x41,0xec,0xda,0xf7, 0x4f,0xe5,0xd7,0xfc, 0x5d,0xfe,0xc0,0xe1, 0x53,0xf7,0xcd,0xea,
+ 0x79,0xc8,0xee,0xdb, 0x77,0xc1,0xe3,0xd0, 0x65,0xda,0xf4,0xcd, 0x6b,0xd3,0xf9,0xc6,
+ 0x31,0xa4,0xb2,0xaf, 0x3f,0xad,0xbf,0xa4, 0x2d,0xb6,0xa8,0xb9, 0x23,0xbf,0xa5,0xb2,
+ 0x09,0x80,0x86,0x83, 0x07,0x89,0x8b,0x88, 0x15,0x92,0x9c,0x95, 0x1b,0x9b,0x91,0x9e,
+ 0xa1,0x7c,0x0a,0x47, 0xaf,0x75,0x07,0x4c, 0xbd,0x6e,0x10,0x51, 0xb3,0x67,0x1d,0x5a,
+ 0x99,0x58,0x3e,0x6b, 0x97,0x51,0x33,0x60, 0x85,0x4a,0x24,0x7d, 0x8b,0x43,0x29,0x76,
+ 0xd1,0x34,0x62,0x1f, 0xdf,0x3d,0x6f,0x14, 0xcd,0x26,0x78,0x09, 0xc3,0x2f,0x75,0x02,
+ 0xe9,0x10,0x56,0x33, 0xe7,0x19,0x5b,0x38, 0xf5,0x02,0x4c,0x25, 0xfb,0x0b,0x41,0x2e,
+ 0x9a,0xd7,0x61,0x8c, 0x94,0xde,0x6c,0x87, 0x86,0xc5,0x7b,0x9a, 0x88,0xcc,0x76,0x91,
+ 0xa2,0xf3,0x55,0xa0, 0xac,0xfa,0x58,0xab, 0xbe,0xe1,0x4f,0xb6, 0xb0,0xe8,0x42,0xbd,
+ 0xea,0x9f,0x09,0xd4, 0xe4,0x96,0x04,0xdf, 0xf6,0x8d,0x13,0xc2, 0xf8,0x84,0x1e,0xc9,
+ 0xd2,0xbb,0x3d,0xf8, 0xdc,0xb2,0x30,0xf3, 0xce,0xa9,0x27,0xee, 0xc0,0xa0,0x2a,0xe5,
+ 0x7a,0x47,0xb1,0x3c, 0x74,0x4e,0xbc,0x37, 0x66,0x55,0xab,0x2a, 0x68,0x5c,0xa6,0x21,
+ 0x42,0x63,0x85,0x10, 0x4c,0x6a,0x88,0x1b, 0x5e,0x71,0x9f,0x06, 0x50,0x78,0x92,0x0d,
+ 0x0a,0x0f,0xd9,0x64, 0x04,0x06,0xd4,0x6f, 0x16,0x1d,0xc3,0x72, 0x18,0x14,0xce,0x79,
+ 0x32,0x2b,0xed,0x48, 0x3c,0x22,0xe0,0x43, 0x2e,0x39,0xf7,0x5e, 0x20,0x30,0xfa,0x55,
+ 0xec,0x9a,0xb7,0x01, 0xe2,0x93,0xba,0x0a, 0xf0,0x88,0xad,0x17, 0xfe,0x81,0xa0,0x1c,
+ 0xd4,0xbe,0x83,0x2d, 0xda,0xb7,0x8e,0x26, 0xc8,0xac,0x99,0x3b, 0xc6,0xa5,0x94,0x30,
+ 0x9c,0xd2,0xdf,0x59, 0x92,0xdb,0xd2,0x52, 0x80,0xc0,0xc5,0x4f, 0x8e,0xc9,0xc8,0x44,
+ 0xa4,0xf6,0xeb,0x75, 0xaa,0xff,0xe6,0x7e, 0xb8,0xe4,0xf1,0x63, 0xb6,0xed,0xfc,0x68,
+ 0x0c,0x0a,0x67,0xb1, 0x02,0x03,0x6a,0xba, 0x10,0x18,0x7d,0xa7, 0x1e,0x11,0x70,0xac,
+ 0x34,0x2e,0x53,0x9d, 0x3a,0x27,0x5e,0x96, 0x28,0x3c,0x49,0x8b, 0x26,0x35,0x44,0x80,
+ 0x7c,0x42,0x0f,0xe9, 0x72,0x4b,0x02,0xe2, 0x60,0x50,0x15,0xff, 0x6e,0x59,0x18,0xf4,
+ 0x44,0x66,0x3b,0xc5, 0x4a,0x6f,0x36,0xce, 0x58,0x74,0x21,0xd3, 0x56,0x7d,0x2c,0xd8,
+ 0x37,0xa1,0x0c,0x7a, 0x39,0xa8,0x01,0x71, 0x2b,0xb3,0x16,0x6c, 0x25,0xba,0x1b,0x67,
+ 0x0f,0x85,0x38,0x56, 0x01,0x8c,0x35,0x5d, 0x13,0x97,0x22,0x40, 0x1d,0x9e,0x2f,0x4b,
+ 0x47,0xe9,0x64,0x22, 0x49,0xe0,0x69,0x29, 0x5b,0xfb,0x7e,0x34, 0x55,0xf2,0x73,0x3f,
+ 0x7f,0xcd,0x50,0x0e, 0x71,0xc4,0x5d,0x05, 0x63,0xdf,0x4a,0x18, 0x6d,0xd6,0x47,0x13,
+ 0xd7,0x31,0xdc,0xca, 0xd9,0x38,0xd1,0xc1, 0xcb,0x23,0xc6,0xdc, 0xc5,0x2a,0xcb,0xd7,
+ 0xef,0x15,0xe8,0xe6, 0xe1,0x1c,0xe5,0xed, 0xf3,0x07,0xf2,0xf0, 0xfd,0x0e,0xff,0xfb,
+ 0xa7,0x79,0xb4,0x92, 0xa9,0x70,0xb9,0x99, 0xbb,0x6b,0xae,0x84, 0xb5,0x62,0xa3,0x8f,
+ 0x9f,0x5d,0x80,0xbe, 0x91,0x54,0x8d,0xb5, 0x83,0x4f,0x9a,0xa8, 0x8d,0x46,0x97,0xa3
+};
+
+static uint8_t U2[256][4]=
+{
+ 0x00,0x00,0x00,0x00, 0x0b,0x0e,0x09,0x0d, 0x16,0x1c,0x12,0x1a, 0x1d,0x12,0x1b,0x17,
+ 0x2c,0x38,0x24,0x34, 0x27,0x36,0x2d,0x39, 0x3a,0x24,0x36,0x2e, 0x31,0x2a,0x3f,0x23,
+ 0x58,0x70,0x48,0x68, 0x53,0x7e,0x41,0x65, 0x4e,0x6c,0x5a,0x72, 0x45,0x62,0x53,0x7f,
+ 0x74,0x48,0x6c,0x5c, 0x7f,0x46,0x65,0x51, 0x62,0x54,0x7e,0x46, 0x69,0x5a,0x77,0x4b,
+ 0xb0,0xe0,0x90,0xd0, 0xbb,0xee,0x99,0xdd, 0xa6,0xfc,0x82,0xca, 0xad,0xf2,0x8b,0xc7,
+ 0x9c,0xd8,0xb4,0xe4, 0x97,0xd6,0xbd,0xe9, 0x8a,0xc4,0xa6,0xfe, 0x81,0xca,0xaf,0xf3,
+ 0xe8,0x90,0xd8,0xb8, 0xe3,0x9e,0xd1,0xb5, 0xfe,0x8c,0xca,0xa2, 0xf5,0x82,0xc3,0xaf,
+ 0xc4,0xa8,0xfc,0x8c, 0xcf,0xa6,0xf5,0x81, 0xd2,0xb4,0xee,0x96, 0xd9,0xba,0xe7,0x9b,
+ 0x7b,0xdb,0x3b,0xbb, 0x70,0xd5,0x32,0xb6, 0x6d,0xc7,0x29,0xa1, 0x66,0xc9,0x20,0xac,
+ 0x57,0xe3,0x1f,0x8f, 0x5c,0xed,0x16,0x82, 0x41,0xff,0x0d,0x95, 0x4a,0xf1,0x04,0x98,
+ 0x23,0xab,0x73,0xd3, 0x28,0xa5,0x7a,0xde, 0x35,0xb7,0x61,0xc9, 0x3e,0xb9,0x68,0xc4,
+ 0x0f,0x93,0x57,0xe7, 0x04,0x9d,0x5e,0xea, 0x19,0x8f,0x45,0xfd, 0x12,0x81,0x4c,0xf0,
+ 0xcb,0x3b,0xab,0x6b, 0xc0,0x35,0xa2,0x66, 0xdd,0x27,0xb9,0x71, 0xd6,0x29,0xb0,0x7c,
+ 0xe7,0x03,0x8f,0x5f, 0xec,0x0d,0x86,0x52, 0xf1,0x1f,0x9d,0x45, 0xfa,0x11,0x94,0x48,
+ 0x93,0x4b,0xe3,0x03, 0x98,0x45,0xea,0x0e, 0x85,0x57,0xf1,0x19, 0x8e,0x59,0xf8,0x14,
+ 0xbf,0x73,0xc7,0x37, 0xb4,0x7d,0xce,0x3a, 0xa9,0x6f,0xd5,0x2d, 0xa2,0x61,0xdc,0x20,
+ 0xf6,0xad,0x76,0x6d, 0xfd,0xa3,0x7f,0x60, 0xe0,0xb1,0x64,0x77, 0xeb,0xbf,0x6d,0x7a,
+ 0xda,0x95,0x52,0x59, 0xd1,0x9b,0x5b,0x54, 0xcc,0x89,0x40,0x43, 0xc7,0x87,0x49,0x4e,
+ 0xae,0xdd,0x3e,0x05, 0xa5,0xd3,0x37,0x08, 0xb8,0xc1,0x2c,0x1f, 0xb3,0xcf,0x25,0x12,
+ 0x82,0xe5,0x1a,0x31, 0x89,0xeb,0x13,0x3c, 0x94,0xf9,0x08,0x2b, 0x9f,0xf7,0x01,0x26,
+ 0x46,0x4d,0xe6,0xbd, 0x4d,0x43,0xef,0xb0, 0x50,0x51,0xf4,0xa7, 0x5b,0x5f,0xfd,0xaa,
+ 0x6a,0x75,0xc2,0x89, 0x61,0x7b,0xcb,0x84, 0x7c,0x69,0xd0,0x93, 0x77,0x67,0xd9,0x9e,
+ 0x1e,0x3d,0xae,0xd5, 0x15,0x33,0xa7,0xd8, 0x08,0x21,0xbc,0xcf, 0x03,0x2f,0xb5,0xc2,
+ 0x32,0x05,0x8a,0xe1, 0x39,0x0b,0x83,0xec, 0x24,0x19,0x98,0xfb, 0x2f,0x17,0x91,0xf6,
+ 0x8d,0x76,0x4d,0xd6, 0x86,0x78,0x44,0xdb, 0x9b,0x6a,0x5f,0xcc, 0x90,0x64,0x56,0xc1,
+ 0xa1,0x4e,0x69,0xe2, 0xaa,0x40,0x60,0xef, 0xb7,0x52,0x7b,0xf8, 0xbc,0x5c,0x72,0xf5,
+ 0xd5,0x06,0x05,0xbe, 0xde,0x08,0x0c,0xb3, 0xc3,0x1a,0x17,0xa4, 0xc8,0x14,0x1e,0xa9,
+ 0xf9,0x3e,0x21,0x8a, 0xf2,0x30,0x28,0x87, 0xef,0x22,0x33,0x90, 0xe4,0x2c,0x3a,0x9d,
+ 0x3d,0x96,0xdd,0x06, 0x36,0x98,0xd4,0x0b, 0x2b,0x8a,0xcf,0x1c, 0x20,0x84,0xc6,0x11,
+ 0x11,0xae,0xf9,0x32, 0x1a,0xa0,0xf0,0x3f, 0x07,0xb2,0xeb,0x28, 0x0c,0xbc,0xe2,0x25,
+ 0x65,0xe6,0x95,0x6e, 0x6e,0xe8,0x9c,0x63, 0x73,0xfa,0x87,0x74, 0x78,0xf4,0x8e,0x79,
+ 0x49,0xde,0xb1,0x5a, 0x42,0xd0,0xb8,0x57, 0x5f,0xc2,0xa3,0x40, 0x54,0xcc,0xaa,0x4d,
+ 0xf7,0x41,0xec,0xda, 0xfc,0x4f,0xe5,0xd7, 0xe1,0x5d,0xfe,0xc0, 0xea,0x53,0xf7,0xcd,
+ 0xdb,0x79,0xc8,0xee, 0xd0,0x77,0xc1,0xe3, 0xcd,0x65,0xda,0xf4, 0xc6,0x6b,0xd3,0xf9,
+ 0xaf,0x31,0xa4,0xb2, 0xa4,0x3f,0xad,0xbf, 0xb9,0x2d,0xb6,0xa8, 0xb2,0x23,0xbf,0xa5,
+ 0x83,0x09,0x80,0x86, 0x88,0x07,0x89,0x8b, 0x95,0x15,0x92,0x9c, 0x9e,0x1b,0x9b,0x91,
+ 0x47,0xa1,0x7c,0x0a, 0x4c,0xaf,0x75,0x07, 0x51,0xbd,0x6e,0x10, 0x5a,0xb3,0x67,0x1d,
+ 0x6b,0x99,0x58,0x3e, 0x60,0x97,0x51,0x33, 0x7d,0x85,0x4a,0x24, 0x76,0x8b,0x43,0x29,
+ 0x1f,0xd1,0x34,0x62, 0x14,0xdf,0x3d,0x6f, 0x09,0xcd,0x26,0x78, 0x02,0xc3,0x2f,0x75,
+ 0x33,0xe9,0x10,0x56, 0x38,0xe7,0x19,0x5b, 0x25,0xf5,0x02,0x4c, 0x2e,0xfb,0x0b,0x41,
+ 0x8c,0x9a,0xd7,0x61, 0x87,0x94,0xde,0x6c, 0x9a,0x86,0xc5,0x7b, 0x91,0x88,0xcc,0x76,
+ 0xa0,0xa2,0xf3,0x55, 0xab,0xac,0xfa,0x58, 0xb6,0xbe,0xe1,0x4f, 0xbd,0xb0,0xe8,0x42,
+ 0xd4,0xea,0x9f,0x09, 0xdf,0xe4,0x96,0x04, 0xc2,0xf6,0x8d,0x13, 0xc9,0xf8,0x84,0x1e,
+ 0xf8,0xd2,0xbb,0x3d, 0xf3,0xdc,0xb2,0x30, 0xee,0xce,0xa9,0x27, 0xe5,0xc0,0xa0,0x2a,
+ 0x3c,0x7a,0x47,0xb1, 0x37,0x74,0x4e,0xbc, 0x2a,0x66,0x55,0xab, 0x21,0x68,0x5c,0xa6,
+ 0x10,0x42,0x63,0x85, 0x1b,0x4c,0x6a,0x88, 0x06,0x5e,0x71,0x9f, 0x0d,0x50,0x78,0x92,
+ 0x64,0x0a,0x0f,0xd9, 0x6f,0x04,0x06,0xd4, 0x72,0x16,0x1d,0xc3, 0x79,0x18,0x14,0xce,
+ 0x48,0x32,0x2b,0xed, 0x43,0x3c,0x22,0xe0, 0x5e,0x2e,0x39,0xf7, 0x55,0x20,0x30,0xfa,
+ 0x01,0xec,0x9a,0xb7, 0x0a,0xe2,0x93,0xba, 0x17,0xf0,0x88,0xad, 0x1c,0xfe,0x81,0xa0,
+ 0x2d,0xd4,0xbe,0x83, 0x26,0xda,0xb7,0x8e, 0x3b,0xc8,0xac,0x99, 0x30,0xc6,0xa5,0x94,
+ 0x59,0x9c,0xd2,0xdf, 0x52,0x92,0xdb,0xd2, 0x4f,0x80,0xc0,0xc5, 0x44,0x8e,0xc9,0xc8,
+ 0x75,0xa4,0xf6,0xeb, 0x7e,0xaa,0xff,0xe6, 0x63,0xb8,0xe4,0xf1, 0x68,0xb6,0xed,0xfc,
+ 0xb1,0x0c,0x0a,0x67, 0xba,0x02,0x03,0x6a, 0xa7,0x10,0x18,0x7d, 0xac,0x1e,0x11,0x70,
+ 0x9d,0x34,0x2e,0x53, 0x96,0x3a,0x27,0x5e, 0x8b,0x28,0x3c,0x49, 0x80,0x26,0x35,0x44,
+ 0xe9,0x7c,0x42,0x0f, 0xe2,0x72,0x4b,0x02, 0xff,0x60,0x50,0x15, 0xf4,0x6e,0x59,0x18,
+ 0xc5,0x44,0x66,0x3b, 0xce,0x4a,0x6f,0x36, 0xd3,0x58,0x74,0x21, 0xd8,0x56,0x7d,0x2c,
+ 0x7a,0x37,0xa1,0x0c, 0x71,0x39,0xa8,0x01, 0x6c,0x2b,0xb3,0x16, 0x67,0x25,0xba,0x1b,
+ 0x56,0x0f,0x85,0x38, 0x5d,0x01,0x8c,0x35, 0x40,0x13,0x97,0x22, 0x4b,0x1d,0x9e,0x2f,
+ 0x22,0x47,0xe9,0x64, 0x29,0x49,0xe0,0x69, 0x34,0x5b,0xfb,0x7e, 0x3f,0x55,0xf2,0x73,
+ 0x0e,0x7f,0xcd,0x50, 0x05,0x71,0xc4,0x5d, 0x18,0x63,0xdf,0x4a, 0x13,0x6d,0xd6,0x47,
+ 0xca,0xd7,0x31,0xdc, 0xc1,0xd9,0x38,0xd1, 0xdc,0xcb,0x23,0xc6, 0xd7,0xc5,0x2a,0xcb,
+ 0xe6,0xef,0x15,0xe8, 0xed,0xe1,0x1c,0xe5, 0xf0,0xf3,0x07,0xf2, 0xfb,0xfd,0x0e,0xff,
+ 0x92,0xa7,0x79,0xb4, 0x99,0xa9,0x70,0xb9, 0x84,0xbb,0x6b,0xae, 0x8f,0xb5,0x62,0xa3,
+ 0xbe,0x9f,0x5d,0x80, 0xb5,0x91,0x54,0x8d, 0xa8,0x83,0x4f,0x9a, 0xa3,0x8d,0x46,0x97
+};
+
+static uint8_t U3[256][4]=
+{
+ 0x00,0x00,0x00,0x00, 0x0d,0x0b,0x0e,0x09, 0x1a,0x16,0x1c,0x12, 0x17,0x1d,0x12,0x1b,
+ 0x34,0x2c,0x38,0x24, 0x39,0x27,0x36,0x2d, 0x2e,0x3a,0x24,0x36, 0x23,0x31,0x2a,0x3f,
+ 0x68,0x58,0x70,0x48, 0x65,0x53,0x7e,0x41, 0x72,0x4e,0x6c,0x5a, 0x7f,0x45,0x62,0x53,
+ 0x5c,0x74,0x48,0x6c, 0x51,0x7f,0x46,0x65, 0x46,0x62,0x54,0x7e, 0x4b,0x69,0x5a,0x77,
+ 0xd0,0xb0,0xe0,0x90, 0xdd,0xbb,0xee,0x99, 0xca,0xa6,0xfc,0x82, 0xc7,0xad,0xf2,0x8b,
+ 0xe4,0x9c,0xd8,0xb4, 0xe9,0x97,0xd6,0xbd, 0xfe,0x8a,0xc4,0xa6, 0xf3,0x81,0xca,0xaf,
+ 0xb8,0xe8,0x90,0xd8, 0xb5,0xe3,0x9e,0xd1, 0xa2,0xfe,0x8c,0xca, 0xaf,0xf5,0x82,0xc3,
+ 0x8c,0xc4,0xa8,0xfc, 0x81,0xcf,0xa6,0xf5, 0x96,0xd2,0xb4,0xee, 0x9b,0xd9,0xba,0xe7,
+ 0xbb,0x7b,0xdb,0x3b, 0xb6,0x70,0xd5,0x32, 0xa1,0x6d,0xc7,0x29, 0xac,0x66,0xc9,0x20,
+ 0x8f,0x57,0xe3,0x1f, 0x82,0x5c,0xed,0x16, 0x95,0x41,0xff,0x0d, 0x98,0x4a,0xf1,0x04,
+ 0xd3,0x23,0xab,0x73, 0xde,0x28,0xa5,0x7a, 0xc9,0x35,0xb7,0x61, 0xc4,0x3e,0xb9,0x68,
+ 0xe7,0x0f,0x93,0x57, 0xea,0x04,0x9d,0x5e, 0xfd,0x19,0x8f,0x45, 0xf0,0x12,0x81,0x4c,
+ 0x6b,0xcb,0x3b,0xab, 0x66,0xc0,0x35,0xa2, 0x71,0xdd,0x27,0xb9, 0x7c,0xd6,0x29,0xb0,
+ 0x5f,0xe7,0x03,0x8f, 0x52,0xec,0x0d,0x86, 0x45,0xf1,0x1f,0x9d, 0x48,0xfa,0x11,0x94,
+ 0x03,0x93,0x4b,0xe3, 0x0e,0x98,0x45,0xea, 0x19,0x85,0x57,0xf1, 0x14,0x8e,0x59,0xf8,
+ 0x37,0xbf,0x73,0xc7, 0x3a,0xb4,0x7d,0xce, 0x2d,0xa9,0x6f,0xd5, 0x20,0xa2,0x61,0xdc,
+ 0x6d,0xf6,0xad,0x76, 0x60,0xfd,0xa3,0x7f, 0x77,0xe0,0xb1,0x64, 0x7a,0xeb,0xbf,0x6d,
+ 0x59,0xda,0x95,0x52, 0x54,0xd1,0x9b,0x5b, 0x43,0xcc,0x89,0x40, 0x4e,0xc7,0x87,0x49,
+ 0x05,0xae,0xdd,0x3e, 0x08,0xa5,0xd3,0x37, 0x1f,0xb8,0xc1,0x2c, 0x12,0xb3,0xcf,0x25,
+ 0x31,0x82,0xe5,0x1a, 0x3c,0x89,0xeb,0x13, 0x2b,0x94,0xf9,0x08, 0x26,0x9f,0xf7,0x01,
+ 0xbd,0x46,0x4d,0xe6, 0xb0,0x4d,0x43,0xef, 0xa7,0x50,0x51,0xf4, 0xaa,0x5b,0x5f,0xfd,
+ 0x89,0x6a,0x75,0xc2, 0x84,0x61,0x7b,0xcb, 0x93,0x7c,0x69,0xd0, 0x9e,0x77,0x67,0xd9,
+ 0xd5,0x1e,0x3d,0xae, 0xd8,0x15,0x33,0xa7, 0xcf,0x08,0x21,0xbc, 0xc2,0x03,0x2f,0xb5,
+ 0xe1,0x32,0x05,0x8a, 0xec,0x39,0x0b,0x83, 0xfb,0x24,0x19,0x98, 0xf6,0x2f,0x17,0x91,
+ 0xd6,0x8d,0x76,0x4d, 0xdb,0x86,0x78,0x44, 0xcc,0x9b,0x6a,0x5f, 0xc1,0x90,0x64,0x56,
+ 0xe2,0xa1,0x4e,0x69, 0xef,0xaa,0x40,0x60, 0xf8,0xb7,0x52,0x7b, 0xf5,0xbc,0x5c,0x72,
+ 0xbe,0xd5,0x06,0x05, 0xb3,0xde,0x08,0x0c, 0xa4,0xc3,0x1a,0x17, 0xa9,0xc8,0x14,0x1e,
+ 0x8a,0xf9,0x3e,0x21, 0x87,0xf2,0x30,0x28, 0x90,0xef,0x22,0x33, 0x9d,0xe4,0x2c,0x3a,
+ 0x06,0x3d,0x96,0xdd, 0x0b,0x36,0x98,0xd4, 0x1c,0x2b,0x8a,0xcf, 0x11,0x20,0x84,0xc6,
+ 0x32,0x11,0xae,0xf9, 0x3f,0x1a,0xa0,0xf0, 0x28,0x07,0xb2,0xeb, 0x25,0x0c,0xbc,0xe2,
+ 0x6e,0x65,0xe6,0x95, 0x63,0x6e,0xe8,0x9c, 0x74,0x73,0xfa,0x87, 0x79,0x78,0xf4,0x8e,
+ 0x5a,0x49,0xde,0xb1, 0x57,0x42,0xd0,0xb8, 0x40,0x5f,0xc2,0xa3, 0x4d,0x54,0xcc,0xaa,
+ 0xda,0xf7,0x41,0xec, 0xd7,0xfc,0x4f,0xe5, 0xc0,0xe1,0x5d,0xfe, 0xcd,0xea,0x53,0xf7,
+ 0xee,0xdb,0x79,0xc8, 0xe3,0xd0,0x77,0xc1, 0xf4,0xcd,0x65,0xda, 0xf9,0xc6,0x6b,0xd3,
+ 0xb2,0xaf,0x31,0xa4, 0xbf,0xa4,0x3f,0xad, 0xa8,0xb9,0x2d,0xb6, 0xa5,0xb2,0x23,0xbf,
+ 0x86,0x83,0x09,0x80, 0x8b,0x88,0x07,0x89, 0x9c,0x95,0x15,0x92, 0x91,0x9e,0x1b,0x9b,
+ 0x0a,0x47,0xa1,0x7c, 0x07,0x4c,0xaf,0x75, 0x10,0x51,0xbd,0x6e, 0x1d,0x5a,0xb3,0x67,
+ 0x3e,0x6b,0x99,0x58, 0x33,0x60,0x97,0x51, 0x24,0x7d,0x85,0x4a, 0x29,0x76,0x8b,0x43,
+ 0x62,0x1f,0xd1,0x34, 0x6f,0x14,0xdf,0x3d, 0x78,0x09,0xcd,0x26, 0x75,0x02,0xc3,0x2f,
+ 0x56,0x33,0xe9,0x10, 0x5b,0x38,0xe7,0x19, 0x4c,0x25,0xf5,0x02, 0x41,0x2e,0xfb,0x0b,
+ 0x61,0x8c,0x9a,0xd7, 0x6c,0x87,0x94,0xde, 0x7b,0x9a,0x86,0xc5, 0x76,0x91,0x88,0xcc,
+ 0x55,0xa0,0xa2,0xf3, 0x58,0xab,0xac,0xfa, 0x4f,0xb6,0xbe,0xe1, 0x42,0xbd,0xb0,0xe8,
+ 0x09,0xd4,0xea,0x9f, 0x04,0xdf,0xe4,0x96, 0x13,0xc2,0xf6,0x8d, 0x1e,0xc9,0xf8,0x84,
+ 0x3d,0xf8,0xd2,0xbb, 0x30,0xf3,0xdc,0xb2, 0x27,0xee,0xce,0xa9, 0x2a,0xe5,0xc0,0xa0,
+ 0xb1,0x3c,0x7a,0x47, 0xbc,0x37,0x74,0x4e, 0xab,0x2a,0x66,0x55, 0xa6,0x21,0x68,0x5c,
+ 0x85,0x10,0x42,0x63, 0x88,0x1b,0x4c,0x6a, 0x9f,0x06,0x5e,0x71, 0x92,0x0d,0x50,0x78,
+ 0xd9,0x64,0x0a,0x0f, 0xd4,0x6f,0x04,0x06, 0xc3,0x72,0x16,0x1d, 0xce,0x79,0x18,0x14,
+ 0xed,0x48,0x32,0x2b, 0xe0,0x43,0x3c,0x22, 0xf7,0x5e,0x2e,0x39, 0xfa,0x55,0x20,0x30,
+ 0xb7,0x01,0xec,0x9a, 0xba,0x0a,0xe2,0x93, 0xad,0x17,0xf0,0x88, 0xa0,0x1c,0xfe,0x81,
+ 0x83,0x2d,0xd4,0xbe, 0x8e,0x26,0xda,0xb7, 0x99,0x3b,0xc8,0xac, 0x94,0x30,0xc6,0xa5,
+ 0xdf,0x59,0x9c,0xd2, 0xd2,0x52,0x92,0xdb, 0xc5,0x4f,0x80,0xc0, 0xc8,0x44,0x8e,0xc9,
+ 0xeb,0x75,0xa4,0xf6, 0xe6,0x7e,0xaa,0xff, 0xf1,0x63,0xb8,0xe4, 0xfc,0x68,0xb6,0xed,
+ 0x67,0xb1,0x0c,0x0a, 0x6a,0xba,0x02,0x03, 0x7d,0xa7,0x10,0x18, 0x70,0xac,0x1e,0x11,
+ 0x53,0x9d,0x34,0x2e, 0x5e,0x96,0x3a,0x27, 0x49,0x8b,0x28,0x3c, 0x44,0x80,0x26,0x35,
+ 0x0f,0xe9,0x7c,0x42, 0x02,0xe2,0x72,0x4b, 0x15,0xff,0x60,0x50, 0x18,0xf4,0x6e,0x59,
+ 0x3b,0xc5,0x44,0x66, 0x36,0xce,0x4a,0x6f, 0x21,0xd3,0x58,0x74, 0x2c,0xd8,0x56,0x7d,
+ 0x0c,0x7a,0x37,0xa1, 0x01,0x71,0x39,0xa8, 0x16,0x6c,0x2b,0xb3, 0x1b,0x67,0x25,0xba,
+ 0x38,0x56,0x0f,0x85, 0x35,0x5d,0x01,0x8c, 0x22,0x40,0x13,0x97, 0x2f,0x4b,0x1d,0x9e,
+ 0x64,0x22,0x47,0xe9, 0x69,0x29,0x49,0xe0, 0x7e,0x34,0x5b,0xfb, 0x73,0x3f,0x55,0xf2,
+ 0x50,0x0e,0x7f,0xcd, 0x5d,0x05,0x71,0xc4, 0x4a,0x18,0x63,0xdf, 0x47,0x13,0x6d,0xd6,
+ 0xdc,0xca,0xd7,0x31, 0xd1,0xc1,0xd9,0x38, 0xc6,0xdc,0xcb,0x23, 0xcb,0xd7,0xc5,0x2a,
+ 0xe8,0xe6,0xef,0x15, 0xe5,0xed,0xe1,0x1c, 0xf2,0xf0,0xf3,0x07, 0xff,0xfb,0xfd,0x0e,
+ 0xb4,0x92,0xa7,0x79, 0xb9,0x99,0xa9,0x70, 0xae,0x84,0xbb,0x6b, 0xa3,0x8f,0xb5,0x62,
+ 0x80,0xbe,0x9f,0x5d, 0x8d,0xb5,0x91,0x54, 0x9a,0xa8,0x83,0x4f, 0x97,0xa3,0x8d,0x46
+};
+
+static uint8_t U4[256][4]=
+{
+ 0x00,0x00,0x00,0x00, 0x09,0x0d,0x0b,0x0e, 0x12,0x1a,0x16,0x1c, 0x1b,0x17,0x1d,0x12,
+ 0x24,0x34,0x2c,0x38, 0x2d,0x39,0x27,0x36, 0x36,0x2e,0x3a,0x24, 0x3f,0x23,0x31,0x2a,
+ 0x48,0x68,0x58,0x70, 0x41,0x65,0x53,0x7e, 0x5a,0x72,0x4e,0x6c, 0x53,0x7f,0x45,0x62,
+ 0x6c,0x5c,0x74,0x48, 0x65,0x51,0x7f,0x46, 0x7e,0x46,0x62,0x54, 0x77,0x4b,0x69,0x5a,
+ 0x90,0xd0,0xb0,0xe0, 0x99,0xdd,0xbb,0xee, 0x82,0xca,0xa6,0xfc, 0x8b,0xc7,0xad,0xf2,
+ 0xb4,0xe4,0x9c,0xd8, 0xbd,0xe9,0x97,0xd6, 0xa6,0xfe,0x8a,0xc4, 0xaf,0xf3,0x81,0xca,
+ 0xd8,0xb8,0xe8,0x90, 0xd1,0xb5,0xe3,0x9e, 0xca,0xa2,0xfe,0x8c, 0xc3,0xaf,0xf5,0x82,
+ 0xfc,0x8c,0xc4,0xa8, 0xf5,0x81,0xcf,0xa6, 0xee,0x96,0xd2,0xb4, 0xe7,0x9b,0xd9,0xba,
+ 0x3b,0xbb,0x7b,0xdb, 0x32,0xb6,0x70,0xd5, 0x29,0xa1,0x6d,0xc7, 0x20,0xac,0x66,0xc9,
+ 0x1f,0x8f,0x57,0xe3, 0x16,0x82,0x5c,0xed, 0x0d,0x95,0x41,0xff, 0x04,0x98,0x4a,0xf1,
+ 0x73,0xd3,0x23,0xab, 0x7a,0xde,0x28,0xa5, 0x61,0xc9,0x35,0xb7, 0x68,0xc4,0x3e,0xb9,
+ 0x57,0xe7,0x0f,0x93, 0x5e,0xea,0x04,0x9d, 0x45,0xfd,0x19,0x8f, 0x4c,0xf0,0x12,0x81,
+ 0xab,0x6b,0xcb,0x3b, 0xa2,0x66,0xc0,0x35, 0xb9,0x71,0xdd,0x27, 0xb0,0x7c,0xd6,0x29,
+ 0x8f,0x5f,0xe7,0x03, 0x86,0x52,0xec,0x0d, 0x9d,0x45,0xf1,0x1f, 0x94,0x48,0xfa,0x11,
+ 0xe3,0x03,0x93,0x4b, 0xea,0x0e,0x98,0x45, 0xf1,0x19,0x85,0x57, 0xf8,0x14,0x8e,0x59,
+ 0xc7,0x37,0xbf,0x73, 0xce,0x3a,0xb4,0x7d, 0xd5,0x2d,0xa9,0x6f, 0xdc,0x20,0xa2,0x61,
+ 0x76,0x6d,0xf6,0xad, 0x7f,0x60,0xfd,0xa3, 0x64,0x77,0xe0,0xb1, 0x6d,0x7a,0xeb,0xbf,
+ 0x52,0x59,0xda,0x95, 0x5b,0x54,0xd1,0x9b, 0x40,0x43,0xcc,0x89, 0x49,0x4e,0xc7,0x87,
+ 0x3e,0x05,0xae,0xdd, 0x37,0x08,0xa5,0xd3, 0x2c,0x1f,0xb8,0xc1, 0x25,0x12,0xb3,0xcf,
+ 0x1a,0x31,0x82,0xe5, 0x13,0x3c,0x89,0xeb, 0x08,0x2b,0x94,0xf9, 0x01,0x26,0x9f,0xf7,
+ 0xe6,0xbd,0x46,0x4d, 0xef,0xb0,0x4d,0x43, 0xf4,0xa7,0x50,0x51, 0xfd,0xaa,0x5b,0x5f,
+ 0xc2,0x89,0x6a,0x75, 0xcb,0x84,0x61,0x7b, 0xd0,0x93,0x7c,0x69, 0xd9,0x9e,0x77,0x67,
+ 0xae,0xd5,0x1e,0x3d, 0xa7,0xd8,0x15,0x33, 0xbc,0xcf,0x08,0x21, 0xb5,0xc2,0x03,0x2f,
+ 0x8a,0xe1,0x32,0x05, 0x83,0xec,0x39,0x0b, 0x98,0xfb,0x24,0x19, 0x91,0xf6,0x2f,0x17,
+ 0x4d,0xd6,0x8d,0x76, 0x44,0xdb,0x86,0x78, 0x5f,0xcc,0x9b,0x6a, 0x56,0xc1,0x90,0x64,
+ 0x69,0xe2,0xa1,0x4e, 0x60,0xef,0xaa,0x40, 0x7b,0xf8,0xb7,0x52, 0x72,0xf5,0xbc,0x5c,
+ 0x05,0xbe,0xd5,0x06, 0x0c,0xb3,0xde,0x08, 0x17,0xa4,0xc3,0x1a, 0x1e,0xa9,0xc8,0x14,
+ 0x21,0x8a,0xf9,0x3e, 0x28,0x87,0xf2,0x30, 0x33,0x90,0xef,0x22, 0x3a,0x9d,0xe4,0x2c,
+ 0xdd,0x06,0x3d,0x96, 0xd4,0x0b,0x36,0x98, 0xcf,0x1c,0x2b,0x8a, 0xc6,0x11,0x20,0x84,
+ 0xf9,0x32,0x11,0xae, 0xf0,0x3f,0x1a,0xa0, 0xeb,0x28,0x07,0xb2, 0xe2,0x25,0x0c,0xbc,
+ 0x95,0x6e,0x65,0xe6, 0x9c,0x63,0x6e,0xe8, 0x87,0x74,0x73,0xfa, 0x8e,0x79,0x78,0xf4,
+ 0xb1,0x5a,0x49,0xde, 0xb8,0x57,0x42,0xd0, 0xa3,0x40,0x5f,0xc2, 0xaa,0x4d,0x54,0xcc,
+ 0xec,0xda,0xf7,0x41, 0xe5,0xd7,0xfc,0x4f, 0xfe,0xc0,0xe1,0x5d, 0xf7,0xcd,0xea,0x53,
+ 0xc8,0xee,0xdb,0x79, 0xc1,0xe3,0xd0,0x77, 0xda,0xf4,0xcd,0x65, 0xd3,0xf9,0xc6,0x6b,
+ 0xa4,0xb2,0xaf,0x31, 0xad,0xbf,0xa4,0x3f, 0xb6,0xa8,0xb9,0x2d, 0xbf,0xa5,0xb2,0x23,
+ 0x80,0x86,0x83,0x09, 0x89,0x8b,0x88,0x07, 0x92,0x9c,0x95,0x15, 0x9b,0x91,0x9e,0x1b,
+ 0x7c,0x0a,0x47,0xa1, 0x75,0x07,0x4c,0xaf, 0x6e,0x10,0x51,0xbd, 0x67,0x1d,0x5a,0xb3,
+ 0x58,0x3e,0x6b,0x99, 0x51,0x33,0x60,0x97, 0x4a,0x24,0x7d,0x85, 0x43,0x29,0x76,0x8b,
+ 0x34,0x62,0x1f,0xd1, 0x3d,0x6f,0x14,0xdf, 0x26,0x78,0x09,0xcd, 0x2f,0x75,0x02,0xc3,
+ 0x10,0x56,0x33,0xe9, 0x19,0x5b,0x38,0xe7, 0x02,0x4c,0x25,0xf5, 0x0b,0x41,0x2e,0xfb,
+ 0xd7,0x61,0x8c,0x9a, 0xde,0x6c,0x87,0x94, 0xc5,0x7b,0x9a,0x86, 0xcc,0x76,0x91,0x88,
+ 0xf3,0x55,0xa0,0xa2, 0xfa,0x58,0xab,0xac, 0xe1,0x4f,0xb6,0xbe, 0xe8,0x42,0xbd,0xb0,
+ 0x9f,0x09,0xd4,0xea, 0x96,0x04,0xdf,0xe4, 0x8d,0x13,0xc2,0xf6, 0x84,0x1e,0xc9,0xf8,
+ 0xbb,0x3d,0xf8,0xd2, 0xb2,0x30,0xf3,0xdc, 0xa9,0x27,0xee,0xce, 0xa0,0x2a,0xe5,0xc0,
+ 0x47,0xb1,0x3c,0x7a, 0x4e,0xbc,0x37,0x74, 0x55,0xab,0x2a,0x66, 0x5c,0xa6,0x21,0x68,
+ 0x63,0x85,0x10,0x42, 0x6a,0x88,0x1b,0x4c, 0x71,0x9f,0x06,0x5e, 0x78,0x92,0x0d,0x50,
+ 0x0f,0xd9,0x64,0x0a, 0x06,0xd4,0x6f,0x04, 0x1d,0xc3,0x72,0x16, 0x14,0xce,0x79,0x18,
+ 0x2b,0xed,0x48,0x32, 0x22,0xe0,0x43,0x3c, 0x39,0xf7,0x5e,0x2e, 0x30,0xfa,0x55,0x20,
+ 0x9a,0xb7,0x01,0xec, 0x93,0xba,0x0a,0xe2, 0x88,0xad,0x17,0xf0, 0x81,0xa0,0x1c,0xfe,
+ 0xbe,0x83,0x2d,0xd4, 0xb7,0x8e,0x26,0xda, 0xac,0x99,0x3b,0xc8, 0xa5,0x94,0x30,0xc6,
+ 0xd2,0xdf,0x59,0x9c, 0xdb,0xd2,0x52,0x92, 0xc0,0xc5,0x4f,0x80, 0xc9,0xc8,0x44,0x8e,
+ 0xf6,0xeb,0x75,0xa4, 0xff,0xe6,0x7e,0xaa, 0xe4,0xf1,0x63,0xb8, 0xed,0xfc,0x68,0xb6,
+ 0x0a,0x67,0xb1,0x0c, 0x03,0x6a,0xba,0x02, 0x18,0x7d,0xa7,0x10, 0x11,0x70,0xac,0x1e,
+ 0x2e,0x53,0x9d,0x34, 0x27,0x5e,0x96,0x3a, 0x3c,0x49,0x8b,0x28, 0x35,0x44,0x80,0x26,
+ 0x42,0x0f,0xe9,0x7c, 0x4b,0x02,0xe2,0x72, 0x50,0x15,0xff,0x60, 0x59,0x18,0xf4,0x6e,
+ 0x66,0x3b,0xc5,0x44, 0x6f,0x36,0xce,0x4a, 0x74,0x21,0xd3,0x58, 0x7d,0x2c,0xd8,0x56,
+ 0xa1,0x0c,0x7a,0x37, 0xa8,0x01,0x71,0x39, 0xb3,0x16,0x6c,0x2b, 0xba,0x1b,0x67,0x25,
+ 0x85,0x38,0x56,0x0f, 0x8c,0x35,0x5d,0x01, 0x97,0x22,0x40,0x13, 0x9e,0x2f,0x4b,0x1d,
+ 0xe9,0x64,0x22,0x47, 0xe0,0x69,0x29,0x49, 0xfb,0x7e,0x34,0x5b, 0xf2,0x73,0x3f,0x55,
+ 0xcd,0x50,0x0e,0x7f, 0xc4,0x5d,0x05,0x71, 0xdf,0x4a,0x18,0x63, 0xd6,0x47,0x13,0x6d,
+ 0x31,0xdc,0xca,0xd7, 0x38,0xd1,0xc1,0xd9, 0x23,0xc6,0xdc,0xcb, 0x2a,0xcb,0xd7,0xc5,
+ 0x15,0xe8,0xe6,0xef, 0x1c,0xe5,0xed,0xe1, 0x07,0xf2,0xf0,0xf3, 0x0e,0xff,0xfb,0xfd,
+ 0x79,0xb4,0x92,0xa7, 0x70,0xb9,0x99,0xa9, 0x6b,0xae,0x84,0xbb, 0x62,0xa3,0x8f,0xb5,
+ 0x5d,0x80,0xbe,0x9f, 0x54,0x8d,0xb5,0x91, 0x4f,0x9a,0xa8,0x83, 0x46,0x97,0xa3,0x8d
+};
+
+static uint32_t rcon[30]=
+{
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
+ 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
+ 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// API
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Rijndael::Rijndael()
+{
+ m_state = Invalid;
+}
+
+Rijndael::~Rijndael()
+{
+ // nothing here
+}
+
+int Rijndael::init(Mode mode,Direction dir,const uint8_t * key,KeyLength keyLen,uint8_t * initVector)
+{
+ // Not initialized yet
+ m_state = Invalid;
+
+ // Check the mode
+ if((mode != CBC) && (mode != ECB) && (mode != CFB1))return RIJNDAEL_UNSUPPORTED_MODE;
+ m_mode = mode;
+
+ // And the direction
+ if((dir != Encrypt) && (dir != Decrypt))return RIJNDAEL_UNSUPPORTED_DIRECTION;
+ m_direction = dir;
+
+ // Allow to set an init vector
+ if(initVector)
+ {
+ // specified init vector
+ for(int i = 0;i < MAX_IV_SIZE;i++)
+ {
+ m_initVector[i] = initVector[i];
+ }
+ } else {
+ // zero init vector
+ for(int i = 0;i < MAX_IV_SIZE;i++)
+ {
+ m_initVector[i] = 0;
+ }
+ }
+
+ uint32_t uKeyLenInBytes;
+
+ // And check the key length
+ switch(keyLen)
+ {
+ case Key16Bytes:
+ uKeyLenInBytes = 16;
+ m_uRounds = 10;
+ break;
+ case Key24Bytes:
+ uKeyLenInBytes = 24;
+ m_uRounds = 12;
+ break;
+ case Key32Bytes:
+ uKeyLenInBytes = 32;
+ m_uRounds = 14;
+ break;
+ default:
+ return RIJNDAEL_UNSUPPORTED_KEY_LENGTH;
+ break;
+ }
+ // The number of rounds is calculated as
+ // m_uRounds = (m_uKeyLenInBits / 32) + 6;
+
+ if(!key)return RIJNDAEL_BAD_KEY;
+
+ uint8_t keyMatrix[_MAX_KEY_COLUMNS][4];
+
+ for(uint32_t i = 0;i < uKeyLenInBytes;i++)keyMatrix[i >> 2][i & 3] = key[i];
+
+ keySched(keyMatrix);
+
+ if(m_direction == Decrypt)keyEncToDec();
+
+ m_state = Valid;
+
+ return RIJNDAEL_SUCCESS;
+}
+
+int Rijndael::blockEncrypt(const uint8_t *input,int inputLen,uint8_t *outBuffer)
+{
+ int i, k, numBlocks;
+ uint8_t block[16], iv[4][4];
+
+ if(m_state != Valid)return RIJNDAEL_NOT_INITIALIZED;
+ if(m_direction != Encrypt)return RIJNDAEL_BAD_DIRECTION;
+
+ if(input == 0 || inputLen <= 0)return 0;
+
+ numBlocks = inputLen/128;
+
+ switch(m_mode){
+ case ECB:
+ for(i = numBlocks;i > 0;i--)
+ {
+ encrypt(input,outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+ case CBC:
+ ((uint32_t*)block)[0] = ((uint32_t*)m_initVector)[0] ^ ((uint32_t*)input)[0];
+ ((uint32_t*)block)[1] = ((uint32_t*)m_initVector)[1] ^ ((uint32_t*)input)[1];
+ ((uint32_t*)block)[2] = ((uint32_t*)m_initVector)[2] ^ ((uint32_t*)input)[2];
+ ((uint32_t*)block)[3] = ((uint32_t*)m_initVector)[3] ^ ((uint32_t*)input)[3];
+ encrypt(block,outBuffer);
+ input += 16;
+ for(i = numBlocks - 1;i > 0;i--)
+ {
+ ((uint32_t*)block)[0] = ((uint32_t*)outBuffer)[0] ^ ((uint32_t*)input)[0];
+ ((uint32_t*)block)[1] = ((uint32_t*)outBuffer)[1] ^ ((uint32_t*)input)[1];
+ ((uint32_t*)block)[2] = ((uint32_t*)outBuffer)[2] ^ ((uint32_t*)input)[2];
+ ((uint32_t*)block)[3] = ((uint32_t*)outBuffer)[3] ^ ((uint32_t*)input)[3];
+ outBuffer += 16;
+ encrypt(block,outBuffer);
+ input += 16;
+ }
+ break;
+ case CFB1:
+#if STRICT_ALIGN
+ memcpy(iv,m_initVector,16);
+#else /* !STRICT_ALIGN */
+ *((uint32_t*)iv[0]) = *((uint32_t*)(m_initVector ));
+ *((uint32_t*)iv[1]) = *((uint32_t*)(m_initVector + 4));
+ *((uint32_t*)iv[2]) = *((uint32_t*)(m_initVector + 8));
+ *((uint32_t*)iv[3]) = *((uint32_t*)(m_initVector +12));
+#endif /* ?STRICT_ALIGN */
+ for(i = numBlocks; i > 0; i--)
+ {
+ for(k = 0; k < 128; k++)
+ {
+ *((uint32_t*) block ) = *((uint32_t*)iv[0]);
+ *((uint32_t*)(block+ 4)) = *((uint32_t*)iv[1]);
+ *((uint32_t*)(block+ 8)) = *((uint32_t*)iv[2]);
+ *((uint32_t*)(block+12)) = *((uint32_t*)iv[3]);
+ encrypt(block,block);
+ outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
+ iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
+ iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
+ iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
+ iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
+ iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
+ iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
+ iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
+ iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
+ iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
+ iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
+ iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
+ iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
+ iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
+ iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
+ iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
+ iv[3][3] = (iv[3][3] << 1) | (outBuffer[k/8] >> (7-(k&7))) & 1;
+ }
+ }
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 128 * numBlocks;
+}
+
+int Rijndael::padEncrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer)
+{
+ int i, numBlocks, padLen;
+ uint8_t block[16], *iv;
+
+ if(m_state != Valid)return RIJNDAEL_NOT_INITIALIZED;
+ if(m_direction != Encrypt)return RIJNDAEL_NOT_INITIALIZED;
+
+ if(input == 0 || inputOctets <= 0)return 0;
+
+ numBlocks = inputOctets/16;
+
+ switch(m_mode)
+ {
+ case ECB:
+ for(i = numBlocks; i > 0; i--)
+ {
+ encrypt(input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ padLen = 16 - (inputOctets - 16*numBlocks);
+// assert(padLen > 0 && padLen <= 16);
+ memcpy(block, input, 16 - padLen);
+ memset(block + 16 - padLen, padLen, padLen);
+ encrypt(block,outBuffer);
+ break;
+ case CBC:
+ iv = m_initVector;
+ for(i = numBlocks; i > 0; i--)
+ {
+ ((uint32_t*)block)[0] = ((uint32_t*)input)[0] ^ ((uint32_t*)iv)[0];
+ ((uint32_t*)block)[1] = ((uint32_t*)input)[1] ^ ((uint32_t*)iv)[1];
+ ((uint32_t*)block)[2] = ((uint32_t*)input)[2] ^ ((uint32_t*)iv)[2];
+ ((uint32_t*)block)[3] = ((uint32_t*)input)[3] ^ ((uint32_t*)iv)[3];
+ encrypt(block, outBuffer);
+ iv = outBuffer;
+ input += 16;
+ outBuffer += 16;
+ }
+ padLen = 16 - (inputOctets - 16*numBlocks);
+// assert(padLen > 0 && padLen <= 16); // DO SOMETHING HERE ?
+ for (i = 0; i < 16 - padLen; i++) {
+ block[i] = input[i] ^ iv[i];
+ }
+ for (i = 16 - padLen; i < 16; i++) {
+ block[i] = (uint8_t)padLen ^ iv[i];
+ }
+ encrypt(block,outBuffer);
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 16*(numBlocks + 1);
+}
+
+int Rijndael::blockDecrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer)
+{
+ int i, k, numBlocks;
+ uint8_t block[16], iv[4][4];
+
+ if(m_state != Valid)return RIJNDAEL_NOT_INITIALIZED;
+ if((m_mode != CFB1) && (m_direction == Encrypt))return RIJNDAEL_BAD_DIRECTION;
+
+ if (input == 0 || inputLen <= 0)return 0;
+
+ numBlocks = inputLen/128;
+
+ switch(m_mode)
+ {
+ case ECB:
+ for (i = numBlocks; i > 0; i--)
+ {
+ decrypt(input,outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+ case CBC:
+#if STRICT_ALIGN
+ memcpy(iv,m_initVector,16);
+#else
+ *((uint32_t*)iv[0]) = *((uint32_t*)(m_initVector ));
+ *((uint32_t*)iv[1]) = *((uint32_t*)(m_initVector+ 4));
+ *((uint32_t*)iv[2]) = *((uint32_t*)(m_initVector+ 8));
+ *((uint32_t*)iv[3]) = *((uint32_t*)(m_initVector+12));
+#endif
+ for (i = numBlocks; i > 0; i--)
+ {
+ decrypt(input, block);
+ ((uint32_t*)block)[0] ^= *((uint32_t*)iv[0]);
+ ((uint32_t*)block)[1] ^= *((uint32_t*)iv[1]);
+ ((uint32_t*)block)[2] ^= *((uint32_t*)iv[2]);
+ ((uint32_t*)block)[3] ^= *((uint32_t*)iv[3]);
+#if STRICT_ALIGN
+ memcpy(iv, input, 16);
+ memcpy(outBuf, block, 16);
+#else
+ *((uint32_t*)iv[0]) = ((uint32_t*)input)[0]; ((uint32_t*)outBuffer)[0] = ((uint32_t*)block)[0];
+ *((uint32_t*)iv[1]) = ((uint32_t*)input)[1]; ((uint32_t*)outBuffer)[1] = ((uint32_t*)block)[1];
+ *((uint32_t*)iv[2]) = ((uint32_t*)input)[2]; ((uint32_t*)outBuffer)[2] = ((uint32_t*)block)[2];
+ *((uint32_t*)iv[3]) = ((uint32_t*)input)[3]; ((uint32_t*)outBuffer)[3] = ((uint32_t*)block)[3];
+#endif
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+ case CFB1:
+#if STRICT_ALIGN
+ memcpy(iv, m_initVector, 16);
+#else
+ *((uint32_t*)iv[0]) = *((uint32_t*)(m_initVector));
+ *((uint32_t*)iv[1]) = *((uint32_t*)(m_initVector+ 4));
+ *((uint32_t*)iv[2]) = *((uint32_t*)(m_initVector+ 8));
+ *((uint32_t*)iv[3]) = *((uint32_t*)(m_initVector+12));
+#endif
+ for(i = numBlocks; i > 0; i--)
+ {
+ for(k = 0; k < 128; k++)
+ {
+ *((uint32_t*) block ) = *((uint32_t*)iv[0]);
+ *((uint32_t*)(block+ 4)) = *((uint32_t*)iv[1]);
+ *((uint32_t*)(block+ 8)) = *((uint32_t*)iv[2]);
+ *((uint32_t*)(block+12)) = *((uint32_t*)iv[3]);
+ encrypt(block, block);
+ iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
+ iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
+ iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
+ iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
+ iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
+ iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
+ iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
+ iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
+ iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
+ iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
+ iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
+ iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
+ iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
+ iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
+ iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
+ iv[3][3] = (iv[3][3] << 1) | (input[k/8] >> (7-(k&7))) & 1;
+ outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
+ }
+ }
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 128*numBlocks;
+}
+
+int Rijndael::padDecrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer)
+{
+ int i, numBlocks, padLen;
+ uint8_t block[16];
+ uint32_t iv[4];
+
+ if(m_state != Valid)return RIJNDAEL_NOT_INITIALIZED;
+ if(m_direction != Decrypt)return RIJNDAEL_BAD_DIRECTION;
+
+ if(input == 0 || inputOctets <= 0)return 0;
+
+ if((inputOctets % 16) != 0)return RIJNDAEL_CORRUPTED_DATA;
+
+ numBlocks = inputOctets/16;
+
+ switch(m_mode){
+ case ECB:
+ for (i = numBlocks - 1; i > 0; i--)
+ {
+ decrypt(input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+
+ decrypt(input, block);
+ padLen = block[15];
+ if (padLen >= 16)return RIJNDAEL_CORRUPTED_DATA;
+ for(i = 16 - padLen; i < 16; i++)
+ {
+ if(block[i] != padLen)return RIJNDAEL_CORRUPTED_DATA;
+ }
+ memcpy(outBuffer, block, 16 - padLen);
+ break;
+ case CBC:
+ memcpy(iv, m_initVector, 16);
+ /* all blocks but last */
+ for (i = numBlocks - 1; i > 0; i--)
+ {
+ decrypt(input, block);
+ ((uint32_t*)block)[0] ^= iv[0];
+ ((uint32_t*)block)[1] ^= iv[1];
+ ((uint32_t*)block)[2] ^= iv[2];
+ ((uint32_t*)block)[3] ^= iv[3];
+ memcpy(iv, input, 16);
+ memcpy(outBuffer, block, 16);
+ input += 16;
+ outBuffer += 16;
+ }
+ /* last block */
+ decrypt(input, block);
+ ((uint32_t*)block)[0] ^= iv[0];
+ ((uint32_t*)block)[1] ^= iv[1];
+ ((uint32_t*)block)[2] ^= iv[2];
+ ((uint32_t*)block)[3] ^= iv[3];
+ padLen = block[15];
+ if(padLen <= 0 || padLen > 16)return RIJNDAEL_CORRUPTED_DATA;
+ for(i = 16 - padLen; i < 16; i++)
+ {
+ if(block[i] != padLen)return RIJNDAEL_CORRUPTED_DATA;
+ }
+ memcpy(outBuffer, block, 16 - padLen);
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return 16*numBlocks - padLen;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ALGORITHM
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+void Rijndael::keySched(uint8_t key[_MAX_KEY_COLUMNS][4])
+{
+ unsigned j,rconpointer = 0;
+
+ // Calculate the necessary round keys
+ // The number of calculations depends on keyBits and blockBits
+ unsigned uKeyColumns = m_uRounds - 6;
+
+ uint8_t tempKey[_MAX_KEY_COLUMNS][4];
+
+ // Copy the input key to the temporary key matrix
+
+ for(j = 0;j < uKeyColumns;j++)
+ {
+ *((uint32_t*)(tempKey[j])) = *((uint32_t*)(key[j]));
+ }
+
+ unsigned r = 0;
+ unsigned t = 0;
+
+ // copy values into round key array
+ for(j = 0;(j < uKeyColumns) && (r <= m_uRounds); )
+ {
+ for(;(j < uKeyColumns) && (t < 4); j++, t++)
+ {
+ *((uint32_t*)m_expandedKey[r][t]) = *((uint32_t*)tempKey[j]);
+ }
+
+
+ if(t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+
+ while(r <= m_uRounds)
+ {
+ tempKey[0][0] ^= S[tempKey[uKeyColumns-1][1]];
+ tempKey[0][1] ^= S[tempKey[uKeyColumns-1][2]];
+ tempKey[0][2] ^= S[tempKey[uKeyColumns-1][3]];
+ tempKey[0][3] ^= S[tempKey[uKeyColumns-1][0]];
+ tempKey[0][0] ^= rcon[rconpointer++];
+
+ if (uKeyColumns != 8)
+ {
+ for(j = 1; j < uKeyColumns; j++)
+ {
+ *((uint32_t*)tempKey[j]) ^= *((uint32_t*)tempKey[j-1]);
+ }
+ } else {
+ for(j = 1; j < uKeyColumns/2; j++)
+ {
+ *((uint32_t*)tempKey[j]) ^= *((uint32_t*)tempKey[j-1]);
+ }
+ tempKey[uKeyColumns/2][0] ^= S[tempKey[uKeyColumns/2 - 1][0]];
+ tempKey[uKeyColumns/2][1] ^= S[tempKey[uKeyColumns/2 - 1][1]];
+ tempKey[uKeyColumns/2][2] ^= S[tempKey[uKeyColumns/2 - 1][2]];
+ tempKey[uKeyColumns/2][3] ^= S[tempKey[uKeyColumns/2 - 1][3]];
+ for(j = uKeyColumns/2 + 1; j < uKeyColumns; j++)
+ {
+ *((uint32_t*)tempKey[j]) ^= *((uint32_t*)tempKey[j-1]);
+ }
+ }
+ for(j = 0; (j < uKeyColumns) && (r <= m_uRounds); )
+ {
+ for(; (j < uKeyColumns) && (t < 4); j++, t++)
+ {
+ *((uint32_t*)m_expandedKey[r][t]) = *((uint32_t*)tempKey[j]);
+ }
+ if(t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+ }
+}
+
+void Rijndael::keyEncToDec()
+{
+ unsigned r;
+ uint8_t *w;
+
+ for(r = 1; r < m_uRounds; r++)
+ {
+ w = m_expandedKey[r][0];
+ *((uint32_t*)w) = *((uint32_t*)U1[w[0]]) ^ *((uint32_t*)U2[w[1]]) ^ *((uint32_t*)U3[w[2]]) ^ *((uint32_t*)U4[w[3]]);
+ w = m_expandedKey[r][1];
+ *((uint32_t*)w) = *((uint32_t*)U1[w[0]]) ^ *((uint32_t*)U2[w[1]]) ^ *((uint32_t*)U3[w[2]]) ^ *((uint32_t*)U4[w[3]]);
+ w = m_expandedKey[r][2];
+ *((uint32_t*)w) = *((uint32_t*)U1[w[0]]) ^ *((uint32_t*)U2[w[1]]) ^ *((uint32_t*)U3[w[2]]) ^ *((uint32_t*)U4[w[3]]);
+ w = m_expandedKey[r][3];
+ *((uint32_t*)w) = *((uint32_t*)U1[w[0]]) ^ *((uint32_t*)U2[w[1]]) ^ *((uint32_t*)U3[w[2]]) ^ *((uint32_t*)U4[w[3]]);
+ }
+}
+
+void Rijndael::encrypt(const uint8_t a[16], uint8_t b[16])
+{
+ unsigned r;
+ uint8_t temp[4][4];
+
+ *((uint32_t*)temp[0]) = *((uint32_t*)(a )) ^ *((uint32_t*)m_expandedKey[0][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(a+ 4)) ^ *((uint32_t*)m_expandedKey[0][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(a+ 8)) ^ *((uint32_t*)m_expandedKey[0][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(a+12)) ^ *((uint32_t*)m_expandedKey[0][3]);
+ *((uint32_t*)(b )) = *((uint32_t*)T1[temp[0][0]])
+ ^ *((uint32_t*)T2[temp[1][1]])
+ ^ *((uint32_t*)T3[temp[2][2]])
+ ^ *((uint32_t*)T4[temp[3][3]]);
+ *((uint32_t*)(b + 4)) = *((uint32_t*)T1[temp[1][0]])
+ ^ *((uint32_t*)T2[temp[2][1]])
+ ^ *((uint32_t*)T3[temp[3][2]])
+ ^ *((uint32_t*)T4[temp[0][3]]);
+ *((uint32_t*)(b + 8)) = *((uint32_t*)T1[temp[2][0]])
+ ^ *((uint32_t*)T2[temp[3][1]])
+ ^ *((uint32_t*)T3[temp[0][2]])
+ ^ *((uint32_t*)T4[temp[1][3]]);
+ *((uint32_t*)(b +12)) = *((uint32_t*)T1[temp[3][0]])
+ ^ *((uint32_t*)T2[temp[0][1]])
+ ^ *((uint32_t*)T3[temp[1][2]])
+ ^ *((uint32_t*)T4[temp[2][3]]);
+ for(r = 1; r < m_uRounds-1; r++)
+ {
+ *((uint32_t*)temp[0]) = *((uint32_t*)(b )) ^ *((uint32_t*)m_expandedKey[r][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(b+ 4)) ^ *((uint32_t*)m_expandedKey[r][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(b+ 8)) ^ *((uint32_t*)m_expandedKey[r][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(b+12)) ^ *((uint32_t*)m_expandedKey[r][3]);
+
+ *((uint32_t*)(b )) = *((uint32_t*)T1[temp[0][0]])
+ ^ *((uint32_t*)T2[temp[1][1]])
+ ^ *((uint32_t*)T3[temp[2][2]])
+ ^ *((uint32_t*)T4[temp[3][3]]);
+ *((uint32_t*)(b + 4)) = *((uint32_t*)T1[temp[1][0]])
+ ^ *((uint32_t*)T2[temp[2][1]])
+ ^ *((uint32_t*)T3[temp[3][2]])
+ ^ *((uint32_t*)T4[temp[0][3]]);
+ *((uint32_t*)(b + 8)) = *((uint32_t*)T1[temp[2][0]])
+ ^ *((uint32_t*)T2[temp[3][1]])
+ ^ *((uint32_t*)T3[temp[0][2]])
+ ^ *((uint32_t*)T4[temp[1][3]]);
+ *((uint32_t*)(b +12)) = *((uint32_t*)T1[temp[3][0]])
+ ^ *((uint32_t*)T2[temp[0][1]])
+ ^ *((uint32_t*)T3[temp[1][2]])
+ ^ *((uint32_t*)T4[temp[2][3]]);
+ }
+ *((uint32_t*)temp[0]) = *((uint32_t*)(b )) ^ *((uint32_t*)m_expandedKey[m_uRounds-1][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(b+ 4)) ^ *((uint32_t*)m_expandedKey[m_uRounds-1][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(b+ 8)) ^ *((uint32_t*)m_expandedKey[m_uRounds-1][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(b+12)) ^ *((uint32_t*)m_expandedKey[m_uRounds-1][3]);
+ b[ 0] = T1[temp[0][0]][1];
+ b[ 1] = T1[temp[1][1]][1];
+ b[ 2] = T1[temp[2][2]][1];
+ b[ 3] = T1[temp[3][3]][1];
+ b[ 4] = T1[temp[1][0]][1];
+ b[ 5] = T1[temp[2][1]][1];
+ b[ 6] = T1[temp[3][2]][1];
+ b[ 7] = T1[temp[0][3]][1];
+ b[ 8] = T1[temp[2][0]][1];
+ b[ 9] = T1[temp[3][1]][1];
+ b[10] = T1[temp[0][2]][1];
+ b[11] = T1[temp[1][3]][1];
+ b[12] = T1[temp[3][0]][1];
+ b[13] = T1[temp[0][1]][1];
+ b[14] = T1[temp[1][2]][1];
+ b[15] = T1[temp[2][3]][1];
+ *((uint32_t*)(b )) ^= *((uint32_t*)m_expandedKey[m_uRounds][0]);
+ *((uint32_t*)(b+ 4)) ^= *((uint32_t*)m_expandedKey[m_uRounds][1]);
+ *((uint32_t*)(b+ 8)) ^= *((uint32_t*)m_expandedKey[m_uRounds][2]);
+ *((uint32_t*)(b+12)) ^= *((uint32_t*)m_expandedKey[m_uRounds][3]);
+}
+
+void Rijndael::decrypt(const uint8_t a[16], uint8_t b[16])
+{
+ int r;
+ uint8_t temp[4][4];
+
+ *((uint32_t*)temp[0]) = *((uint32_t*)(a )) ^ *((uint32_t*)m_expandedKey[m_uRounds][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(a+ 4)) ^ *((uint32_t*)m_expandedKey[m_uRounds][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(a+ 8)) ^ *((uint32_t*)m_expandedKey[m_uRounds][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(a+12)) ^ *((uint32_t*)m_expandedKey[m_uRounds][3]);
+
+ *((uint32_t*)(b )) = *((uint32_t*)T5[temp[0][0]])
+ ^ *((uint32_t*)T6[temp[3][1]])
+ ^ *((uint32_t*)T7[temp[2][2]])
+ ^ *((uint32_t*)T8[temp[1][3]]);
+ *((uint32_t*)(b+ 4)) = *((uint32_t*)T5[temp[1][0]])
+ ^ *((uint32_t*)T6[temp[0][1]])
+ ^ *((uint32_t*)T7[temp[3][2]])
+ ^ *((uint32_t*)T8[temp[2][3]]);
+ *((uint32_t*)(b+ 8)) = *((uint32_t*)T5[temp[2][0]])
+ ^ *((uint32_t*)T6[temp[1][1]])
+ ^ *((uint32_t*)T7[temp[0][2]])
+ ^ *((uint32_t*)T8[temp[3][3]]);
+ *((uint32_t*)(b+12)) = *((uint32_t*)T5[temp[3][0]])
+ ^ *((uint32_t*)T6[temp[2][1]])
+ ^ *((uint32_t*)T7[temp[1][2]])
+ ^ *((uint32_t*)T8[temp[0][3]]);
+ for(r = m_uRounds-1; r > 1; r--)
+ {
+ *((uint32_t*)temp[0]) = *((uint32_t*)(b )) ^ *((uint32_t*)m_expandedKey[r][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(b+ 4)) ^ *((uint32_t*)m_expandedKey[r][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(b+ 8)) ^ *((uint32_t*)m_expandedKey[r][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(b+12)) ^ *((uint32_t*)m_expandedKey[r][3]);
+ *((uint32_t*)(b )) = *((uint32_t*)T5[temp[0][0]])
+ ^ *((uint32_t*)T6[temp[3][1]])
+ ^ *((uint32_t*)T7[temp[2][2]])
+ ^ *((uint32_t*)T8[temp[1][3]]);
+ *((uint32_t*)(b+ 4)) = *((uint32_t*)T5[temp[1][0]])
+ ^ *((uint32_t*)T6[temp[0][1]])
+ ^ *((uint32_t*)T7[temp[3][2]])
+ ^ *((uint32_t*)T8[temp[2][3]]);
+ *((uint32_t*)(b+ 8)) = *((uint32_t*)T5[temp[2][0]])
+ ^ *((uint32_t*)T6[temp[1][1]])
+ ^ *((uint32_t*)T7[temp[0][2]])
+ ^ *((uint32_t*)T8[temp[3][3]]);
+ *((uint32_t*)(b+12)) = *((uint32_t*)T5[temp[3][0]])
+ ^ *((uint32_t*)T6[temp[2][1]])
+ ^ *((uint32_t*)T7[temp[1][2]])
+ ^ *((uint32_t*)T8[temp[0][3]]);
+ }
+
+ *((uint32_t*)temp[0]) = *((uint32_t*)(b )) ^ *((uint32_t*)m_expandedKey[1][0]);
+ *((uint32_t*)temp[1]) = *((uint32_t*)(b+ 4)) ^ *((uint32_t*)m_expandedKey[1][1]);
+ *((uint32_t*)temp[2]) = *((uint32_t*)(b+ 8)) ^ *((uint32_t*)m_expandedKey[1][2]);
+ *((uint32_t*)temp[3]) = *((uint32_t*)(b+12)) ^ *((uint32_t*)m_expandedKey[1][3]);
+ b[ 0] = S5[temp[0][0]];
+ b[ 1] = S5[temp[3][1]];
+ b[ 2] = S5[temp[2][2]];
+ b[ 3] = S5[temp[1][3]];
+ b[ 4] = S5[temp[1][0]];
+ b[ 5] = S5[temp[0][1]];
+ b[ 6] = S5[temp[3][2]];
+ b[ 7] = S5[temp[2][3]];
+ b[ 8] = S5[temp[2][0]];
+ b[ 9] = S5[temp[1][1]];
+ b[10] = S5[temp[0][2]];
+ b[11] = S5[temp[3][3]];
+ b[12] = S5[temp[3][0]];
+ b[13] = S5[temp[2][1]];
+ b[14] = S5[temp[1][2]];
+ b[15] = S5[temp[0][3]];
+ *((uint32_t*)(b )) ^= *((uint32_t*)m_expandedKey[0][0]);
+ *((uint32_t*)(b+ 4)) ^= *((uint32_t*)m_expandedKey[0][1]);
+ *((uint32_t*)(b+ 8)) ^= *((uint32_t*)m_expandedKey[0][2]);
+ *((uint32_t*)(b+12)) ^= *((uint32_t*)m_expandedKey[0][3]);
+}
diff --git a/common/rijndael.h b/common/rijndael.h
new file mode 100644
index 0000000..79bb8ca
--- /dev/null
+++ b/common/rijndael.h
@@ -0,0 +1,159 @@
+#ifndef _RIJNDAEL_H_
+#define _RIJNDAEL_H_
+
+//
+// File : rijndael.h
+// Creation date : Sun Nov 5 2000 03:21:05 CEST
+// Author : Szymon Stefanek (stefanek@tin.it)
+//
+// Another implementation of the Rijndael cipher.
+// This is intended to be an easily usable library file.
+// This code is public domain.
+// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
+//
+
+//
+// Original Copyright notice:
+//
+// rijndael-alg-fst.c v2.4 April '2000
+// rijndael-alg-fst.h
+// rijndael-api-fst.c
+// rijndael-api-fst.h
+//
+// Optimised ANSI C code
+//
+// authors: v1.0: Antoon Bosselaers
+// v2.0: Vincent Rijmen, K.U.Leuven
+// v2.3: Paulo Barreto
+// v2.4: Vincent Rijmen, K.U.Leuven
+//
+// This code is placed in the public domain.
+//
+
+//
+// This implementation works on 128 , 192 , 256 bit keys
+// and on 128 bit blocks
+//
+
+//
+// Example of usage:
+//
+// // Input data
+// unsigned char key[32]; // The key
+// initializeYour256BitKey(); // Obviously initialized with sth
+// const unsigned char * plainText = getYourPlainText(); // Your plain text
+// int plainTextLen = strlen(plainText); // Plain text length
+//
+// // Encrypting
+// Rijndael rin;
+// unsigned char output[plainTextLen + 16];
+//
+// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
+// // It is a good idea to check the error code
+// int len = rin.padEncrypt(plainText,len,output);
+// if(len >= 0)useYourEncryptedText();
+// else encryptError(len);
+//
+// // Decrypting: we can reuse the same object
+// unsigned char output2[len];
+// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
+// len = rin.padDecrypt(output,len,output2);
+// if(len >= 0)useYourDecryptedText();
+// else decryptError(len);
+//
+
+#include "stdafx.h"
+
+#define _MAX_KEY_COLUMNS (256/32)
+#define _MAX_ROUNDS 14
+#define MAX_IV_SIZE 16
+
+// We assume that unsigned int is 32 bits long....
+//typedef unsigned char uint8_t;
+//typedef unsigned int uint32_t;
+//typedef unsigned short uint16_t;
+
+// Error codes
+#define RIJNDAEL_SUCCESS 0
+#define RIJNDAEL_UNSUPPORTED_MODE -1
+#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
+#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
+#define RIJNDAEL_BAD_KEY -4
+#define RIJNDAEL_NOT_INITIALIZED -5
+#define RIJNDAEL_BAD_DIRECTION -6
+#define RIJNDAEL_CORRUPTED_DATA -7
+
+class Rijndael
+{
+public:
+ enum Direction { Encrypt , Decrypt };
+ enum Mode { ECB , CBC , CFB1 };
+ enum KeyLength { Key16Bytes , Key24Bytes , Key32Bytes };
+ //
+ // Creates a Rijndael cipher object
+ // You have to call init() before you can encrypt or decrypt stuff
+ //
+ Rijndael();
+ ~Rijndael();
+protected:
+ // Internal stuff
+ enum State { Valid , Invalid };
+
+ State m_state;
+ Mode m_mode;
+ Direction m_direction;
+ uint8_t m_initVector[MAX_IV_SIZE];
+ uint32_t m_uRounds;
+ uint8_t m_expandedKey[_MAX_ROUNDS+1][4][4];
+public:
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // API
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ // init(): Initializes the crypt session
+ // Returns RIJNDAEL_SUCCESS or an error code
+ // mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
+ // You have to use the same mode for encrypting and decrypting
+ // dir : Rijndael::Encrypt or Rijndael::Decrypt
+ // A cipher instance works only in one direction
+ // (Well , it could be easily modified to work in both
+ // directions with a single init() call, but it looks
+ // useless to me...anyway , it is a matter of generating
+ // two expanded keys)
+ // key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
+ // this CAN be binary data (it is not expected to be null terminated)
+ // keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
+ // initVector: initialization vector, you will usually use 0 here
+ int init(Mode mode,Direction dir,const uint8_t *key,KeyLength keyLen,uint8_t * initVector = 0);
+ // Encrypts the input array (can be binary data)
+ // The input array length must be a multiple of 16 bytes, the remaining part
+ // is DISCARDED.
+ // so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
+ // Input len is in BITS!
+ // outBuffer must be at least inputLen / 8 bytes long.
+ // Returns the encrypted buffer length in BITS or an error code < 0 in case of error
+ int blockEncrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
+ // Encrypts the input array (can be binary data)
+ // The input array can be any length , it is automatically padded on a 16 byte boundary.
+ // Input len is in BYTES!
+ // outBuffer must be at least (inputLen + 16) bytes long
+ // Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
+ int padEncrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
+ // Decrypts the input vector
+ // Input len is in BITS!
+ // outBuffer must be at least inputLen / 8 bytes long
+ // Returns the decrypted buffer length in BITS and an error code < 0 in case of error
+ int blockDecrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
+ // Decrypts the input vector
+ // Input len is in BYTES!
+ // outBuffer must be at least inputLen bytes long
+ // Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
+ int padDecrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
+protected:
+ void keySched(uint8_t key[_MAX_KEY_COLUMNS][4]);
+ void keyEncToDec();
+ void encrypt(const uint8_t a[16], uint8_t b[16]);
+ void decrypt(const uint8_t a[16], uint8_t b[16]);
+};
+
+#endif // _RIJNDAEL_H_
diff --git a/common/smart_ptr.h b/common/smart_ptr.h
new file mode 100644
index 0000000..dd02345
--- /dev/null
+++ b/common/smart_ptr.h
@@ -0,0 +1,232 @@
+/*
+ * smart_ptr.h
+ * elftosb
+ *
+ * Created by Chris Reed on 4/18/06.
+ * Copyright 2006 __MyCompanyName__. All rights reserved.
+ *
+ */
+#if !defined(_smart_ptr_h_)
+#define _smart_ptr_h_
+
+/*!
+ * \brief Simple, standard smart pointer class.
+ *
+ * This class only supports the single-owner paradigm.
+ */
+template <typename T>
+class smart_ptr
+{
+public:
+ typedef T data_type;
+ typedef T * ptr_type;
+ typedef const T * const_ptr_type;
+ typedef T & ref_type;
+ typedef const T & const_ref_type;
+
+ //! Default constuctor. Initialises with no pointer set.
+ smart_ptr() : _p(0) {}
+
+ //! This constructor takes a pointer to the object to be deleted.
+ smart_ptr(ptr_type p) : _p(p) {}
+
+ //! Destructor. If an object (pointer) has been set, it will be deleted.
+ //! Deletes the object using safe_delete().
+ virtual ~smart_ptr() { safe_delete(); }
+
+ //! Return the current pointer value.
+ ptr_type get() { return _p; }
+
+ //! Return the const form of the current pointer value.
+ const_ptr_type get() const { return _p; }
+
+ //! Change the pointer value, or set if if the default constructor was used.
+ //! If a pointer had previously been associated with the object, and \a p is
+ //! different than that previous pointer, it will be deleted before taking
+ //! ownership of \a p. If this is not desired, call reset() beforehand.
+ void set(ptr_type p)
+ {
+ if (_p && p != _p)
+ {
+ safe_delete();
+ }
+ _p = p;
+ }
+
+ //! Dissociates any previously set pointer value without deleting it.
+ void reset() { _p = 0; }
+
+ //! Dissociates a previously set pointer value, deleting it at the same time.
+ void clear() { safe_delete(); }
+
+ //! Forces immediate deletion of the object. If you are planning on using
+ //! this method, think about just using a normal pointer. It probably makes
+ //! more sense.
+ virtual void safe_delete()
+ {
+ if (_p)
+ {
+ delete _p;
+ _p = 0;
+ }
+ }
+
+ //! \name Operators
+ //@{
+
+ //! Makes the object transparent as the template type.
+ operator ptr_type () { return _p; }
+
+ //! Const version of the pointer operator.
+ operator const_ptr_type () const { return _p; }
+
+ //! Makes the object transparent as a reference of the template type.
+ operator ref_type () { return *_p; }
+
+ //! Const version of the reference operator.
+ operator const_ref_type () const { return *_p; }
+
+ //! Returns a boolean indicating whether the object has a pointer set or not.
+ operator bool () const { return _p != 0; }
+
+ //! To allow setting the pointer directly. Equivalent to a call to set().
+ smart_ptr<T> & operator = (const_ptr_type p)
+ {
+ set(const_cast<ptr_type>(p));
+ return *this;
+ }
+
+ //! Another operator to allow you to treat the object just like a pointer.
+ ptr_type operator ->() { return _p; }
+
+ //! Another operator to allow you to treat the object just like a pointer.
+ const_ptr_type operator ->() const { return _p; }
+
+// //! Pointer dereferencing operator.
+// ref_type operator * () const { return *_p; }
+//
+// //! Const version of the pointer dereference operator.
+// const_ref_type operator * () const { return *_p; }
+
+ //@}
+
+protected:
+ ptr_type _p; //!< The wrapped pointer.
+};
+
+/*!
+ * \brief Simple, standard smart pointer class that uses the array delete operator.
+ *
+ * This class only supports the single-owner paradigm.
+ *
+ * This is almost entirely a copy of smart_ptr since the final C++ specification
+ * does not allow template subclass members to access members of the parent that
+ * do not depend on the template parameter.
+ */
+template <typename T>
+class smart_array_ptr
+{
+public:
+ typedef T data_type;
+ typedef T * ptr_type;
+ typedef const T * const_ptr_type;
+ typedef T & ref_type;
+ typedef const T & const_ref_type;
+
+ //! Default constuctor. Initialises with no pointer set.
+ smart_array_ptr() : _p(0) {}
+
+ //! This constructor takes a pointer to the object to be deleted.
+ smart_array_ptr(ptr_type p) : _p(p) {}
+
+ //! Destructor. If an array has been set, it will be deleted.
+ //! Deletes the array using safe_delete().
+ virtual ~smart_array_ptr() { safe_delete(); }
+
+ //! Return the current pointer value.
+ ptr_type get() { return _p; }
+
+ //! Return the const form of the current pointer value.
+ const_ptr_type get() const { return _p; }
+
+ //! Change the pointer value, or set if if the default constructor was used.
+ //! If a pointer had previously been associated with the object, and \a p is
+ //! different than that previous pointer, it will be deleted before taking
+ //! ownership of \a p. If this is not desired, call reset() beforehand.
+ void set(ptr_type p)
+ {
+ if (_p && p != _p)
+ {
+ safe_delete();
+ }
+ _p = p;
+ }
+
+ //! Dissociates any previously set pointer value without deleting it.
+ void reset() { _p = 0; }
+
+ //! Dissociates a previously set pointer value, deleting it at the same time.
+ void clear() { safe_delete(); }
+
+ //! Forces immediate deletion of the object. If you are planning on using
+ //! this method, think about just using a normal pointer. It probably makes
+ //! more sense.
+ virtual void safe_delete()
+ {
+ if (_p)
+ {
+ delete [] _p;
+ _p = 0;
+ }
+ }
+
+ //! \name Operators
+ //@{
+
+ //! Makes the object transparent as the template type.
+ operator ptr_type () { return _p; }
+
+ //! Const version of the pointer operator.
+ operator const_ptr_type () const { return _p; }
+
+ //! Makes the object transparent as a reference of the template type.
+ operator ref_type () { return *_p; }
+
+ //! Const version of the reference operator.
+ operator const_ref_type () const { return *_p; }
+
+ //! Returns a boolean indicating whether the object has a pointer set or not.
+ operator bool () const { return _p != 0; }
+
+ //! To allow setting the pointer directly. Equivalent to a call to set().
+ smart_array_ptr<T> & operator = (const_ptr_type p)
+ {
+ set(const_cast<ptr_type>(p));
+ return *this;
+ }
+
+ //! Another operator to allow you to treat the object just like a pointer.
+ ptr_type operator ->() { return _p; }
+
+ //! Another operator to allow you to treat the object just like a pointer.
+ const_ptr_type operator ->() const { return _p; }
+
+ //! Indexing operator.
+ ref_type operator [] (unsigned index) { return _p[index]; }
+
+ //! Indexing operator.
+ const_ref_type operator [] (unsigned index) const { return _p[index]; }
+
+// //! Pointer dereferencing operator.
+// ref_type operator * () const { return *_p; }
+//
+// //! Const version of the pointer dereference operator.
+// const_ref_type operator * () const { return *_p; }
+
+ //@}
+
+protected:
+ ptr_type _p; //!< The wrapped pointer.
+};
+
+#endif // _smart_ptr_h_
diff --git a/common/stdafx.cpp b/common/stdafx.cpp
new file mode 100644
index 0000000..9b7c4ac
--- /dev/null
+++ b/common/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// elftosb.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/common/stdafx.h b/common/stdafx.h
new file mode 100644
index 0000000..e6bf9dd
--- /dev/null
+++ b/common/stdafx.h
@@ -0,0 +1,83 @@
+#ifndef stdafx_h_
+#define stdafx_h_
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+// Default to external release.
+#ifndef SGTL_INTERNAL
+ #define SGTL_INTERNAL 0
+#endif
+
+#include <iostream>
+#include <stdexcept>
+
+#if defined(WIN32)
+//#include <tchar.h>
+
+ // define this macro for use in VC++
+ #if !defined(__LITTLE_ENDIAN__)
+ #define __LITTLE_ENDIAN__ 1
+ #endif // !defined(__LITTLE_ENDIAN__)
+#endif // defined(WIN32)
+
+#if defined(Linux)
+// For Linux systems only, types.h only defines the signed
+// integer types. This is not professional code.
+// Update: They are defined in the header files in the more recent version of redhat enterprise gcc.
+#include "/usr/include/sys/types.h"
+#include <stdint.h>
+//typedef unsigned long uint32_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned char uint8_t;
+
+//#define TCHAR char
+//#define _tmain main
+
+ // give a default endian in case one is not defined on Linux (it should be, though)
+ #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+ #define __LITTLE_ENDIAN__ 1
+ #endif // !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+
+#endif // defined(Linux)
+
+// gcc on Mac OS X
+#if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
+ #include <TargetConditionals.h>
+
+ #if defined(TARGET_RT_LITTLE_ENDIAN) && TARGET_RT_LITTLE_ENDIAN
+ #if !defined(__LITTLE_ENDIAN__)
+ #define __LITTLE_ENDIAN__
+ #endif
+ #elif defined(TARGET_RT_BIG_ENDIAN) && TARGET_RT_BIG_ENDIAN
+ #if !defined(__BIG_ENDIAN__)
+ #define __BIG_ENDIAN__
+ #endif
+ #endif
+#endif
+
+#if defined(WIN32) //!defined(Linux) || !defined(__GNUC__)
+// redefine missing typedefs from stdint.h or syst/types.h
+
+typedef unsigned long long uint64_t;
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+
+typedef long long int64_t;
+typedef long int32_t;
+typedef short int16_t;
+typedef char int8_t;
+#endif // !defined(Linux)
+
+#if !defined(TRUE)
+ #define TRUE 1
+#endif // !defined(TRUE)
+
+#if !defined(FALSE)
+ #define FALSE 0
+#endif // !defined(FALSE)
+
+#endif // stdafx_h_
diff --git a/elftosb2/BootImageGenerator.cpp b/elftosb2/BootImageGenerator.cpp
new file mode 100644
index 0000000..63daf26
--- /dev/null
+++ b/elftosb2/BootImageGenerator.cpp
@@ -0,0 +1,80 @@
+/*
+ * BootImageGenerator.cpp
+ * elftosb
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "BootImageGenerator.h"
+#include "Logging.h"
+
+//! Name of product version option.
+#define kProductVersionOption "productVersion"
+
+//! Name of component version option.
+#define kComponentVersionOption "componentVersion"
+
+//! Name of option that specifies the drive tag for this .sb file.
+#define kDriveTagOption "driveTag"
+
+using namespace elftosb;
+
+void BootImageGenerator::processVersionOptions(BootImage * image)
+{
+ // bail if no option context was set
+ if (!m_options)
+ {
+ return;
+ }
+
+ const StringValue * stringValue;
+ version_t version;
+
+ // productVersion
+ if (m_options->hasOption(kProductVersionOption))
+ {
+ stringValue = dynamic_cast<const StringValue *>(m_options->getOption(kProductVersionOption));
+ if (stringValue)
+ {
+ version.set(*stringValue);
+ image->setProductVersion(version);
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: productVersion option is an unexpected type\n");
+ }
+ }
+
+ // componentVersion
+ if (m_options->hasOption(kComponentVersionOption))
+ {
+ stringValue = dynamic_cast<const StringValue *>(m_options->getOption(kComponentVersionOption));
+ if (stringValue)
+ {
+ version.set(*stringValue);
+ image->setComponentVersion(version);
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: componentVersion option is an unexpected type\n");
+ }
+ }
+}
+
+void BootImageGenerator::processDriveTagOption(BootImage * image)
+{
+ if (m_options->hasOption(kDriveTagOption))
+ {
+ const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(m_options->getOption(kDriveTagOption));
+ if (intValue)
+ {
+ image->setDriveTag(intValue->getValue());
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: driveTag option is an unexpected type\n");
+ }
+ }
+}
+
diff --git a/elftosb2/BootImageGenerator.h b/elftosb2/BootImageGenerator.h
new file mode 100644
index 0000000..3d50fbb
--- /dev/null
+++ b/elftosb2/BootImageGenerator.h
@@ -0,0 +1,69 @@
+/*
+ * File: BootImageGenerator.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_BootImageGenerator_h_)
+#define _BootImageGenerator_h_
+
+#include "OutputSection.h"
+#include "BootImage.h"
+#include "OptionContext.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Abstract base class for generators of specific boot image formats.
+ *
+ * Subclasses implement a concrete generator for a certain boot image format, but
+ * they all have the same interface.
+ *
+ * After creating an instance of a subclass the user adds OutputSection objects
+ * to the generator. These objects describe discrete sections within the resulting
+ * boot image file. If the format does not support multiple sections then only
+ * the first will be used.
+ *
+ * Options that are common to all boot image formats are handled by methods
+ * defined in this class. These are the current common options:
+ * - productVersion
+ * - componentVersion
+ * - driveTag
+ */
+class BootImageGenerator
+{
+public:
+ //! \brief Constructor.
+ BootImageGenerator() {}
+
+ //! \brief Destructor.
+ virtual ~BootImageGenerator() {}
+
+ //! \brief Add another section to the output.
+ void addOutputSection(OutputSection * section) { m_sections.push_back(section); }
+
+ //! \brief Set the global option context.
+ void setOptionContext(OptionContext * context) { m_options = context; }
+
+ //! \brief Pure virtual method to generate the output BootImage from input sections.
+ virtual BootImage * generate()=0;
+
+protected:
+ //! Type for a list of model output sections.
+ typedef std::vector<OutputSection*> section_vector_t;
+
+ section_vector_t m_sections; //!< Requested output sections.
+ OptionContext * m_options; //!< Global option context.
+
+ //! \brief Handle common product and component version options.
+ void processVersionOptions(BootImage * image);
+
+ //! \brief Handle the common option which sets the system drive tag.
+ void processDriveTagOption(BootImage * image);
+};
+
+}; // namespace elftosb
+
+#endif // _BootImageGenerator_h_
+
diff --git a/elftosb2/ConversionController.cpp b/elftosb2/ConversionController.cpp
new file mode 100644
index 0000000..dd3341c
--- /dev/null
+++ b/elftosb2/ConversionController.cpp
@@ -0,0 +1,1428 @@
+/*
+ * File: ConversionController.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "ConversionController.h"
+#include <stdexcept>
+#include "EvalContext.h"
+#include "ElftosbErrors.h"
+#include "GlobMatcher.h"
+#include "ExcludesListMatcher.h"
+#include "BootImageGenerator.h"
+#include "EncoreBootImageGenerator.h"
+#include "Logging.h"
+#include "OptionDictionary.h"
+#include "format_string.h"
+#include "SearchPath.h"
+#include "DataSourceImager.h"
+#include "IVTDataSource.h"
+#include <algorithm>
+
+//! Set to 1 to cause the ConversionController to print information about
+//! the values that it processes (options, constants, etc.).
+#define PRINT_VALUES 1
+
+using namespace elftosb;
+
+// Define the parser function prototype;
+extern int yyparse(ElftosbLexer * lexer, CommandFileASTNode ** resultAST);
+
+bool elftosb::g_enableHABSupport = false;
+
+ConversionController::ConversionController()
+: OptionDictionary(),
+ m_commandFilePath(),
+ m_ast(),
+ m_defaultSource(0)
+{
+ m_context.setSourceFileManager(this);
+}
+
+ConversionController::~ConversionController()
+{
+ // clean up sources
+ source_map_t::iterator it = m_sources.begin();
+ for (; it != m_sources.end(); ++it)
+ {
+ if (it->second)
+ {
+ delete it->second;
+ }
+ }
+}
+
+void ConversionController::setCommandFilePath(const std::string & path)
+{
+ m_commandFilePath = new std::string(path);
+}
+
+//! The paths provided to this method are added to an array and accessed with the
+//! "extern(N)" notation in the command file. So the path provided in the third
+//! call to addExternalFilePath() will be found with N=2 in the source definition.
+void ConversionController::addExternalFilePath(const std::string & path)
+{
+ m_externPaths.push_back(path);
+}
+
+bool ConversionController::hasSourceFile(const std::string & name)
+{
+ return m_sources.find(name) != m_sources.end();
+}
+
+SourceFile * ConversionController::getSourceFile(const std::string & name)
+{
+ if (!hasSourceFile(name))
+ {
+ return NULL;
+ }
+
+ return m_sources[name];
+}
+
+SourceFile * ConversionController::getDefaultSourceFile()
+{
+ return m_defaultSource;
+}
+
+//! These steps are executed while running this method:
+//! - The command file is parsed into an abstract syntax tree.
+//! - The list of options is extracted.
+//! - Constant expressions are evaluated.
+//! - The list of source files is extracted and source file objects created.
+//! - Section definitions are extracted.
+//!
+//! This method does not produce any output. It processes the input files and
+//! builds a representation of the output in memory. Use the generateOutput() method
+//! to produce a BootImage object after this method returns.
+//!
+//! \note This method is \e not reentrant. And in fact, the whole class is not designed
+//! to be reentrant.
+//!
+//! \exception std::runtime_error Any number of problems will cause this exception to
+//! be thrown.
+//!
+//! \see parseCommandFile()
+//! \see processOptions()
+//! \see processConstants()
+//! \see processSources()
+//! \see processSections()
+void ConversionController::run()
+{
+#if PRINT_VALUES
+ Log::SetOutputLevel debugLevel(Logger::DEBUG2);
+#endif
+
+ parseCommandFile();
+ assert(m_ast);
+
+ ListASTNode * blocks = m_ast->getBlocks();
+ if (!blocks)
+ {
+ throw std::runtime_error("command file has no blocks");
+ }
+
+ ListASTNode::iterator it = blocks->begin();
+ for (; it != blocks->end(); ++it)
+ {
+ ASTNode * node = *it;
+
+ // Handle an options block.
+ OptionsBlockASTNode * options = dynamic_cast<OptionsBlockASTNode *>(node);
+ if (options)
+ {
+ processOptions(options->getOptions());
+ continue;
+ }
+
+ // Handle a constants block.
+ ConstantsBlockASTNode * constants = dynamic_cast<ConstantsBlockASTNode *>(node);
+ if (constants)
+ {
+ processConstants(constants->getConstants());
+ continue;
+ }
+
+ // Handle a sources block.
+ SourcesBlockASTNode * sources = dynamic_cast<SourcesBlockASTNode *>(node);
+ if (sources)
+ {
+ processSources(sources->getSources());
+ }
+ }
+
+ processSections(m_ast->getSections());
+}
+
+//! Opens the command file and runs it through the lexer and parser. The resulting
+//! abstract syntax tree is held in the m_ast member variable. After parsing, the
+//! command file is closed.
+//!
+//! \exception std::runtime_error Several problems will cause this exception to be
+//! raised, including an unspecified command file path or an error opening the
+//! file.
+void ConversionController::parseCommandFile()
+{
+ if (!m_commandFilePath)
+ {
+ throw std::runtime_error("no command file path was provided");
+ }
+
+ // Search for command file
+ std::string actualPath;
+ bool found = PathSearcher::getGlobalSearcher().search(*m_commandFilePath, PathSearcher::kFindFile, true, actualPath);
+ if (!found)
+ {
+ throw runtime_error(format_string("unable to find command file %s\n", m_commandFilePath->c_str()));
+ }
+
+ // open command file
+ std::ifstream commandFile(actualPath.c_str(), ios_base::in | ios_base::binary);
+ if (!commandFile.is_open())
+ {
+ throw std::runtime_error("could not open command file");
+ }
+
+ try
+ {
+ // create lexer instance
+ ElftosbLexer lexer(commandFile);
+// testLexer(lexer);
+
+ CommandFileASTNode * ast = NULL;
+ int result = yyparse(&lexer, &ast);
+ m_ast = ast;
+
+ // check results
+ if (result || !m_ast)
+ {
+ throw std::runtime_error("failed to parse command file");
+ }
+
+ // dump AST
+// m_ast->printTree(0);
+
+ // close command file
+ commandFile.close();
+ }
+ catch (...)
+ {
+ // close command file
+ commandFile.close();
+
+ // rethrow exception
+ throw;
+ }
+}
+
+//! Iterates over the option definition AST nodes. elftosb::Value objects are created for
+//! each option value and added to the option dictionary.
+//!
+//! \exception std::runtime_error Various errors will cause this exception to be thrown. These
+//! include AST nodes being an unexpected type or expression not evaluating to integers.
+void ConversionController::processOptions(ListASTNode * options)
+{
+ if (!options)
+ {
+ return;
+ }
+
+ ListASTNode::iterator it = options->begin();
+ for (; it != options->end(); ++it)
+ {
+ std::string ident;
+ Value * value = convertAssignmentNodeToValue(*it, ident);
+
+ // check if this option has already been set
+ if (hasOption(ident))
+ {
+ throw semantic_error(format_string("line %d: option already set", (*it)->getFirstLine()));
+ }
+
+ // now save the option value in our map
+ if (value)
+ {
+ setOption(ident, value);
+ }
+ }
+}
+
+//! Scans the constant definition AST nodes, evaluates expression nodes by calling their
+//! elftosb::ExprASTNode::reduce() method, and updates the evaluation context member so
+//! those constant values can be used in other expressions.
+//!
+//! \exception std::runtime_error Various errors will cause this exception to be thrown. These
+//! include AST nodes being an unexpected type or expression not evaluating to integers.
+void ConversionController::processConstants(ListASTNode * constants)
+{
+ if (!constants)
+ {
+ return;
+ }
+
+ ListASTNode::iterator it = constants->begin();
+ for (; it != constants->end(); ++it)
+ {
+ std::string ident;
+ Value * value = convertAssignmentNodeToValue(*it, ident);
+
+ SizedIntegerValue * intValue = dynamic_cast<SizedIntegerValue*>(value);
+ if (!intValue)
+ {
+ throw semantic_error(format_string("line %d: constant value is an invalid type", (*it)->getFirstLine()));
+ }
+
+//#if PRINT_VALUES
+// Log::log("constant ");
+// printIntConstExpr(ident, intValue);
+//#endif
+
+ // record this constant's value in the evaluation context
+ m_context.setVariable(ident, intValue->getValue(), intValue->getWordSize());
+ }
+}
+
+//! \exception std::runtime_error Various errors will cause this exception to be thrown. These
+//! include AST nodes being an unexpected type or expression not evaluating to integers.
+//!
+//! \todo Handle freeing of dict if an exception occurs.
+void ConversionController::processSources(ListASTNode * sources)
+{
+ if (!sources)
+ {
+ return;
+ }
+
+ ListASTNode::iterator it = sources->begin();
+ for (; it != sources->end(); ++it)
+ {
+ SourceDefASTNode * node = dynamic_cast<SourceDefASTNode*>(*it);
+ if (!node)
+ {
+ throw semantic_error(format_string("line %d: source definition node is an unexpected type", node->getFirstLine()));
+ }
+
+ // get source name and check if it has already been defined
+ std::string * name = node->getName();
+ if (m_sources.find(*name) != m_sources.end())
+ {
+ // can't define a source multiple times
+ throw semantic_error(format_string("line %d: source already defined", node->getFirstLine()));
+ }
+
+ // convert attributes into an option dict
+ OptionDictionary * dict = new OptionDictionary(this);
+ ListASTNode * attrsNode = node->getAttributes();
+ if (attrsNode)
+ {
+ ListASTNode::iterator attrIt = attrsNode->begin();
+ for (; attrIt != attrsNode->end(); ++attrIt)
+ {
+ std::string ident;
+ Value * value = convertAssignmentNodeToValue(*attrIt, ident);
+ dict->setOption(ident, value);
+ }
+ }
+
+ // figure out which type of source definition this is
+ PathSourceDefASTNode * pathNode = dynamic_cast<PathSourceDefASTNode*>(node);
+ ExternSourceDefASTNode * externNode = dynamic_cast<ExternSourceDefASTNode*>(node);
+ SourceFile * file = NULL;
+
+ if (pathNode)
+ {
+ // explicit path
+ std::string * path = pathNode->getPath();
+
+#if PRINT_VALUES
+ Log::log("source %s => path(%s)\n", name->c_str(), path->c_str());
+#endif
+
+ try
+ {
+ file = SourceFile::openFile(*path);
+ }
+ catch (...)
+ {
+ // file doesn't exist
+ Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", path->c_str());
+ m_failedSources.push_back(*name);
+ }
+ }
+ else if (externNode)
+ {
+ // externally provided path
+ ExprASTNode * expr = externNode->getSourceNumberExpr()->reduce(m_context);
+ IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(expr);
+ if (!intConst)
+ {
+ throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine()));
+ }
+
+ uint32_t externalFileNumber = static_cast<uint32_t>(intConst->getValue());
+
+ // make sure the extern number is valid
+ if (externalFileNumber >= 0 && externalFileNumber < m_externPaths.size())
+ {
+
+#if PRINT_VALUES
+ Log::log("source %s => extern(%d=%s)\n", name->c_str(), externalFileNumber, m_externPaths[externalFileNumber].c_str());
+#endif
+
+ try
+ {
+ file = SourceFile::openFile(m_externPaths[externalFileNumber]);
+ }
+ catch (...)
+ {
+ Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", m_externPaths[externalFileNumber].c_str());
+ m_failedSources.push_back(*name);
+ }
+ }
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: unexpected source definition node type", node->getFirstLine()));
+ }
+
+ if (file)
+ {
+ // set options
+ file->setOptions(dict);
+
+ // stick the file object in the source map
+ m_sources[*name] = file;
+ }
+ }
+}
+
+void ConversionController::processSections(ListASTNode * sections)
+{
+ if (!sections)
+ {
+ Log::log(Logger::WARNING, "warning: no sections were defined in command file");
+ return;
+ }
+
+ ListASTNode::iterator it = sections->begin();
+ for (; it != sections->end(); ++it)
+ {
+ SectionContentsASTNode * node = dynamic_cast<SectionContentsASTNode*>(*it);
+ if (!node)
+ {
+ throw semantic_error(format_string("line %d: section definition is unexpected type", node->getFirstLine()));
+ }
+
+ // evaluate section number
+ ExprASTNode * idExpr = node->getSectionNumberExpr()->reduce(m_context);
+ IntConstExprASTNode * idConst = dynamic_cast<IntConstExprASTNode*>(idExpr);
+ if (!idConst)
+ {
+ throw semantic_error(format_string("line %d: section number did not evaluate to an integer", idExpr->getFirstLine()));
+ }
+ uint32_t sectionID = idConst->getValue();
+
+ // Create options context for this section. The options context has the
+ // conversion controller as its parent context so it will inherit global options.
+ // The context will be set in the section after the section is created below.
+ OptionDictionary * optionsDict = new OptionDictionary(this);
+ ListASTNode * attrsNode = node->getOptions();
+ if (attrsNode)
+ {
+ ListASTNode::iterator attrIt = attrsNode->begin();
+ for (; attrIt != attrsNode->end(); ++attrIt)
+ {
+ std::string ident;
+ Value * value = convertAssignmentNodeToValue(*attrIt, ident);
+ optionsDict->setOption(ident, value);
+ }
+ }
+
+ // Now create the actual section object based on its type.
+ OutputSection * outputSection = NULL;
+ BootableSectionContentsASTNode * bootableSection;
+ DataSectionContentsASTNode * dataSection;
+ if (bootableSection = dynamic_cast<BootableSectionContentsASTNode*>(node))
+ {
+ // process statements into a sequence of operations
+ ListASTNode * statements = bootableSection->getStatements();
+ OperationSequence * sequence = convertStatementList(statements);
+
+#if 0
+ Log::log("section ID = %d\n", sectionID);
+ statements->printTree(0);
+
+ Log::log("sequence has %d operations\n", sequence->getCount());
+ OperationSequence::iterator_t it = sequence->begin();
+ for (; it != sequence->end(); ++it)
+ {
+ Operation * op = *it;
+ Log::log("op = %p\n", op);
+ }
+#endif
+
+ // create the output section and add it to the list
+ OperationSequenceSection * opSection = new OperationSequenceSection(sectionID);
+ opSection->setOptions(optionsDict);
+ opSection->getSequence() += sequence;
+ outputSection = opSection;
+ }
+ else if (dataSection = dynamic_cast<DataSectionContentsASTNode*>(node))
+ {
+ outputSection = convertDataSection(dataSection, sectionID, optionsDict);
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: unexpected section contents type", node->getFirstLine()));
+ }
+
+ if (outputSection)
+ {
+ m_outputSections.push_back(outputSection);
+ }
+ }
+}
+
+//! Creates an instance of BinaryDataSection from the AST node passed in the
+//! \a dataSection parameter. The section-specific options for this node will
+//! have already been converted into an OptionDictionary, the one passed in
+//! the \a optionsDict parameter.
+//!
+//! The \a dataSection node will have as its contents one of the AST node
+//! classes that represents a source of data. The member function
+//! createSourceFromNode() is used to convert this AST node into an
+//! instance of a DataSource subclass. Then the method imageDataSource()
+//! converts the segments of the DataSource into a raw binary buffer that
+//! becomes the contents of the BinaryDataSection this is returned.
+//!
+//! \param dataSection The AST node for the data section.
+//! \param sectionID Unique tag value the user has assigned to this section.
+//! \param optionsDict Options that apply only to this section. This dictionary
+//! will be assigned as the options dictionary for the resulting section
+//! object. Its parent is the conversion controller itself.
+//! \return An instance of BinaryDataSection. Its contents are a contiguous
+//! binary representation of the contents of \a dataSection.
+OutputSection * ConversionController::convertDataSection(DataSectionContentsASTNode * dataSection, uint32_t sectionID, OptionDictionary * optionsDict)
+{
+ // Create a data source from the section contents AST node.
+ ASTNode * contents = dataSection->getContents();
+ DataSource * dataSource = createSourceFromNode(contents);
+
+ // Convert the data source to a raw buffer.
+ DataSourceImager imager;
+ imager.addDataSource(dataSource);
+
+ // Then make a data section from the buffer.
+ BinaryDataSection * resultSection = new BinaryDataSection(sectionID);
+ resultSection->setOptions(optionsDict);
+ if (imager.getLength())
+ {
+ resultSection->setData(imager.getData(), imager.getLength());
+ }
+
+ return resultSection;
+}
+
+//! @param node The AST node instance for the assignment expression.
+//! @param[out] ident Upon exit this string will be set the the left hand side of the
+//! assignment expression, the identifier name.
+//!
+//! @return An object that is a subclass of Value is returned. The specific subclass will
+//! depend on the type of the right hand side of the assignment expression whose AST
+//! node was provided in the @a node argument.
+//!
+//! @exception semantic_error Thrown for any error where an AST node is an unexpected type.
+//! This may be the @a node argument itself, if it is not an AssignmentASTNode. Or it
+//! may be an unexpected type for either the right or left hand side of the assignment.
+//! The message for the exception will contain a description of the error.
+Value * ConversionController::convertAssignmentNodeToValue(ASTNode * node, std::string & ident)
+{
+ Value * resultValue = NULL;
+
+ // each item of the options list should be an assignment node
+ AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(node);
+ if (!node)
+ {
+ throw semantic_error(format_string("line %d: node is wrong type", assignmentNode->getFirstLine()));
+ }
+
+ // save the left hand side (the identifier) into ident
+ ident = *assignmentNode->getIdent();
+
+ // get the right hand side and convert it to a Value instance
+ ASTNode * valueNode = assignmentNode->getValue();
+ StringConstASTNode * str;
+ ExprASTNode * expr;
+ if (str = dynamic_cast<StringConstASTNode*>(valueNode))
+ {
+ // the option value is a string constant
+ resultValue = new StringValue(str->getString());
+
+//#if PRINT_VALUES
+// Log::log("option %s => \'%s\'\n", ident->c_str(), str->getString()->c_str());
+//#endif
+ }
+ else if (expr = dynamic_cast<ExprASTNode*>(valueNode))
+ {
+ ExprASTNode * reducedExpr = expr->reduce(m_context);
+ IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(reducedExpr);
+ if (!intConst)
+ {
+ throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine()));
+ }
+
+//#if PRINT_VALUES
+// Log::log("option ");
+// printIntConstExpr(*ident, intConst);
+//#endif
+
+ resultValue = new SizedIntegerValue(intConst->getValue(), intConst->getSize());
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: right hand side node is an unexpected type", valueNode->getFirstLine()));
+ }
+
+ return resultValue;
+}
+
+//! Builds up a sequence of Operation objects that are equivalent to the
+//! statements in the \a statements list. The statement list is simply iterated
+//! over and the results of convertOneStatement() are used to build up
+//! the final result sequence.
+//!
+//! \see convertOneStatement()
+OperationSequence * ConversionController::convertStatementList(ListASTNode * statements)
+{
+ OperationSequence * resultSequence = new OperationSequence();
+ ListASTNode::iterator it = statements->begin();
+ for (; it != statements->end(); ++it)
+ {
+ StatementASTNode * statement = dynamic_cast<StatementASTNode*>(*it);
+ if (!statement)
+ {
+ throw semantic_error(format_string("line %d: statement node is unexpected type", (*it)->getFirstLine()));
+ }
+
+ // convert this statement and append it to the result
+ OperationSequence * sequence = convertOneStatement(statement);
+ if (sequence)
+ {
+ *resultSequence += sequence;
+ }
+ }
+
+ return resultSequence;
+}
+
+//! Uses C++ RTTI to identify the particular subclass of StatementASTNode that
+//! the \a statement argument matches. Then the appropriate conversion method
+//! is called.
+//!
+//! \see convertLoadStatement()
+//! \see convertCallStatement()
+//! \see convertFromStatement()
+OperationSequence * ConversionController::convertOneStatement(StatementASTNode * statement)
+{
+ // see if it's a load statement
+ LoadStatementASTNode * load = dynamic_cast<LoadStatementASTNode*>(statement);
+ if (load)
+ {
+ return convertLoadStatement(load);
+ }
+
+ // see if it's a call statement
+ CallStatementASTNode * call = dynamic_cast<CallStatementASTNode*>(statement);
+ if (call)
+ {
+ return convertCallStatement(call);
+ }
+
+ // see if it's a from statement
+ FromStatementASTNode * from = dynamic_cast<FromStatementASTNode*>(statement);
+ if (from)
+ {
+ return convertFromStatement(from);
+ }
+
+ // see if it's a mode statement
+ ModeStatementASTNode * mode = dynamic_cast<ModeStatementASTNode*>(statement);
+ if (mode)
+ {
+ return convertModeStatement(mode);
+ }
+
+ // see if it's an if statement
+ IfStatementASTNode * ifStmt = dynamic_cast<IfStatementASTNode*>(statement);
+ if (ifStmt)
+ {
+ return convertIfStatement(ifStmt);
+ }
+
+ // see if it's a message statement
+ MessageStatementASTNode * messageStmt = dynamic_cast<MessageStatementASTNode*>(statement);
+ if (messageStmt)
+ {
+ // Message statements don't produce operation sequences.
+ handleMessageStatement(messageStmt);
+ return NULL;
+ }
+
+ // didn't match any of the expected statement types
+ throw semantic_error(format_string("line %d: unexpected statement type", statement->getFirstLine()));
+ return NULL;
+}
+
+//! Possible load data node types:
+//! - StringConstASTNode
+//! - ExprASTNode
+//! - SourceASTNode
+//! - SectionMatchListASTNode
+//!
+//! Possible load target node types:
+//! - SymbolASTNode
+//! - NaturalLocationASTNode
+//! - AddressRangeASTNode
+OperationSequence * ConversionController::convertLoadStatement(LoadStatementASTNode * statement)
+{
+ LoadOperation * op = NULL;
+
+ try
+ {
+ // build load operation from source and target
+ op = new LoadOperation();
+ op->setSource(createSourceFromNode(statement->getData()));
+ op->setTarget(createTargetFromNode(statement->getTarget()));
+ op->setDCDLoad(statement->isDCDLoad());
+
+ return new OperationSequence(op);
+ }
+ catch (...)
+ {
+ if (op)
+ {
+ delete op;
+ }
+ throw;
+ }
+}
+
+//! Possible call target node types:
+//! - SymbolASTNode
+//! - ExprASTNode
+//!
+//! Possible call argument node types:
+//! - ExprASTNode
+//! - NULL
+OperationSequence * ConversionController::convertCallStatement(CallStatementASTNode * statement)
+{
+ ExecuteOperation * op = NULL;
+
+ try
+ {
+ // create operation from AST nodes
+ op = new ExecuteOperation();
+
+ bool isHAB = statement->isHAB();
+
+ op->setTarget(createTargetFromNode(statement->getTarget()));
+
+ // set argument value, which defaults to 0 if no expression was provided
+ uint32_t arg = 0;
+ ASTNode * argNode = statement->getArgument();
+ if (argNode)
+ {
+ ExprASTNode * argExprNode = dynamic_cast<ExprASTNode*>(argNode);
+ if (!argExprNode)
+ {
+ throw semantic_error(format_string("line %d: call argument is unexpected type", argNode->getFirstLine()));
+ }
+ argExprNode = argExprNode->reduce(m_context);
+ IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(argExprNode);
+ if (!intNode)
+ {
+ throw semantic_error(format_string("line %d: call argument did not evaluate to an integer", argExprNode->getFirstLine()));
+ }
+
+ arg = intNode->getValue();
+ }
+ op->setArgument(arg);
+
+ // set call type
+ switch (statement->getCallType())
+ {
+ case CallStatementASTNode::kCallType:
+ op->setExecuteType(ExecuteOperation::kCall);
+ break;
+ case CallStatementASTNode::kJumpType:
+ op->setExecuteType(ExecuteOperation::kJump);
+ break;
+ }
+
+ // Set the HAB mode flag.
+ op->setIsHAB(isHAB);
+
+ return new OperationSequence(op);
+ }
+ catch (...)
+ {
+ // delete op and rethrow exception
+ if (op)
+ {
+ delete op;
+ }
+ throw;
+ }
+}
+
+//! First this method sets the default source to the source identified in
+//! the from statement. Then the statements within the from block are
+//! processed recursively by calling convertStatementList(). The resulting
+//! operation sequence is returned.
+OperationSequence * ConversionController::convertFromStatement(FromStatementASTNode * statement)
+{
+ if (m_defaultSource)
+ {
+ throw semantic_error(format_string("line %d: from statements cannot be nested", statement->getFirstLine()));
+ }
+
+ // look up source file instance
+ std::string * fromSourceName = statement->getSourceName();
+ assert(fromSourceName);
+
+ // make sure it's a valid source name
+ source_map_t::iterator sourceIt = m_sources.find(*fromSourceName);
+ if (sourceIt == m_sources.end())
+ {
+ throw semantic_error(format_string("line %d: bad source name", statement->getFirstLine()));
+ }
+
+ // set default source
+ m_defaultSource = sourceIt->second;
+ assert(m_defaultSource);
+
+ // get statements inside the from block
+ ListASTNode * fromStatements = statement->getStatements();
+ assert(fromStatements);
+
+ // produce resulting operation sequence
+ OperationSequence * result = convertStatementList(fromStatements);
+
+ // restore default source to NULL
+ m_defaultSource = NULL;
+
+ return result;
+}
+
+//! Evaluates the expression to get the new boot mode value. Then creates a
+//! BootModeOperation object and returns an OperationSequence containing it.
+//!
+//! \exception elftosb::semantic_error Thrown if a semantic problem is found with
+//! the boot mode expression.
+OperationSequence * ConversionController::convertModeStatement(ModeStatementASTNode * statement)
+{
+ BootModeOperation * op = NULL;
+
+ try
+ {
+ op = new BootModeOperation();
+
+ // evaluate the boot mode expression
+ ExprASTNode * modeExprNode = statement->getModeExpr();
+ if (!modeExprNode)
+ {
+ throw semantic_error(format_string("line %d: mode statement has invalid boot mode expression", statement->getFirstLine()));
+ }
+ modeExprNode = modeExprNode->reduce(m_context);
+ IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(modeExprNode);
+ if (!intNode)
+ {
+ throw semantic_error(format_string("line %d: boot mode did not evaluate to an integer", statement->getFirstLine()));
+ }
+
+ op->setBootMode(intNode->getValue());
+
+ return new OperationSequence(op);
+ }
+ catch (...)
+ {
+ if (op)
+ {
+ delete op;
+ }
+
+ // rethrow exception
+ throw;
+ }
+}
+
+//! Else branches, including else-if, are handled recursively, so there is a limit
+//! on the number of them based on the stack size.
+//!
+//! \return Returns the operation sequence for the branch of the if statement that
+//! evaluated to true. If the statement did not have an else branch and the
+//! condition expression evaluated to false, then NULL will be returned.
+//!
+//! \todo Handle else branches without recursion.
+OperationSequence * ConversionController::convertIfStatement(IfStatementASTNode * statement)
+{
+ // Get the if's conditional expression.
+ ExprASTNode * conditionalExpr = statement->getConditionExpr();
+ if (!conditionalExpr)
+ {
+ throw semantic_error(format_string("line %d: missing or invalid conditional expression", statement->getFirstLine()));
+ }
+
+ // Reduce the conditional to a single integer.
+ conditionalExpr = conditionalExpr->reduce(m_context);
+ IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(conditionalExpr);
+ if (!intNode)
+ {
+ throw semantic_error(format_string("line %d: if statement conditional expression did not evaluate to an integer", statement->getFirstLine()));
+ }
+
+ // Decide which statements to further process by the conditional's boolean value.
+ if (intNode->getValue() && statement->getIfStatements())
+ {
+ return convertStatementList(statement->getIfStatements());
+ }
+ else if (statement->getElseStatements())
+ {
+ return convertStatementList(statement->getElseStatements());
+ }
+ else
+ {
+ // No else branch and the conditional was false, so there are no operations to return.
+ return NULL;
+ }
+}
+
+//! Message statements are executed immediately, by this method. They are
+//! not converted into an abstract operation. All messages are passed through
+//! substituteVariables() before being output.
+//!
+//! \param statement The message statement AST node object.
+void ConversionController::handleMessageStatement(MessageStatementASTNode * statement)
+{
+ string * message = statement->getMessage();
+ if (!message)
+ {
+ throw runtime_error("message statement had no message");
+ }
+
+ smart_ptr<string> finalMessage = substituteVariables(message);
+
+ switch (statement->getType())
+ {
+ case MessageStatementASTNode::kInfo:
+ Log::log(Logger::INFO, "%s\n", finalMessage->c_str());
+ break;
+
+ case MessageStatementASTNode::kWarning:
+ Log::log(Logger::WARNING, "warning: %s\n", finalMessage->c_str());
+ break;
+
+ case MessageStatementASTNode::kError:
+ throw runtime_error(*finalMessage);
+ break;
+ }
+}
+
+//! Performs shell-like variable substitution on the string passed into it.
+//! Both sources and constants can be substituted. Sources will be replaced
+//! with their path and constants with their integer value. The syntax allows
+//! for some simple formatting for constants.
+//!
+//! The syntax is mostly standard. A substitution begins with a dollar-sign
+//! and is followed by the source or constant name in parentheses. For instance,
+//! "$(mysource)" or "$(myconst)". The parentheses are always required.
+//!
+//! Constant names can be prefixed by a single formatting character followed
+//! by a colon. The only formatting characters currently supported are 'd' for
+//! decimal and 'x' for hex. For example, "$(x:myconst)" will be replaced with
+//! the value of the constant named "myconst" formatted as hexadecimal. The
+//! default is decimal, so the 'd' formatting character isn't really ever
+//! needed.
+//!
+//! \param message The string to perform substitution on.
+//! \return Returns a newly allocated std::string object that has all
+//! substitutions replaced with the associated value. The caller is
+//! responsible for freeing the string object using the delete operator.
+std::string * ConversionController::substituteVariables(const std::string * message)
+{
+ string * result = new string();
+ int i;
+ int state = 0;
+ string name;
+
+ for (i=0; i < message->size(); ++i)
+ {
+ char c = (*message)[i];
+ switch (state)
+ {
+ case 0:
+ if (c == '$')
+ {
+ state = 1;
+ }
+ else
+ {
+ (*result) += c;
+ }
+ break;
+
+ case 1:
+ if (c == '(')
+ {
+ state = 2;
+ }
+ else
+ {
+ // Wasn't a variable substitution, so revert to initial state after
+ // inserting the original characters.
+ (*result) += '$';
+ (*result) += c;
+ state = 0;
+ }
+ break;
+
+ case 2:
+ if (c == ')')
+ {
+ // Try the name as a source name first.
+ if (m_sources.find(name) != m_sources.end())
+ {
+ (*result) += m_sources[name]->getPath();
+ }
+ // Otherwise try it as a variable.
+ else
+ {
+ // Select format.
+ const char * fmt = "%d";
+ if (name[1] == ':' && (name[0] == 'd' || name[0] == 'x'))
+ {
+ if (name[0] == 'x')
+ {
+ fmt = "0x%x";
+ }
+
+ // Delete the format characters.
+ name.erase(0, 2);
+ }
+
+ // Now insert the formatted variable if it exists.
+ if (m_context.isVariableDefined(name))
+ {
+ (*result) += format_string(fmt, m_context.getVariableValue(name));
+ }
+ }
+
+ // Switch back to initial state and clear name.
+ state = 0;
+ name.clear();
+ }
+ else
+ {
+ // Just keep building up the variable name.
+ name += c;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+//!
+//! \param generator The generator to use.
+BootImage * ConversionController::generateOutput(BootImageGenerator * generator)
+{
+ // set the generator's option context
+ generator->setOptionContext(this);
+
+ // add output sections to the generator in sequence
+ section_vector_t::iterator it = m_outputSections.begin();
+ for (; it != m_outputSections.end(); ++it)
+ {
+ generator->addOutputSection(*it);
+ }
+
+ // and produce the output
+ BootImage * image = generator->generate();
+// Log::log("boot image = %p\n", image);
+ return image;
+}
+
+//! Takes an AST node that is one of the following subclasses and creates the corresponding
+//! type of DataSource object from it.
+//! - StringConstASTNode
+//! - ExprASTNode
+//! - SourceASTNode
+//! - SectionASTNode
+//! - SectionMatchListASTNode
+//! - BlobConstASTNode
+//! - IVTConstASTNode
+//!
+//! \exception elftosb::semantic_error Thrown if a semantic problem is found with
+//! the data node.
+//! \exception std::runtime_error Thrown if an error occurs that shouldn't be possible
+//! based on the grammar.
+DataSource * ConversionController::createSourceFromNode(ASTNode * dataNode)
+{
+ assert(dataNode);
+
+ DataSource * source = NULL;
+ StringConstASTNode * stringNode;
+ BlobConstASTNode * blobNode;
+ ExprASTNode * exprNode;
+ SourceASTNode * sourceNode;
+ SectionASTNode * sectionNode;
+ SectionMatchListASTNode * matchListNode;
+ IVTConstASTNode * ivtNode;
+
+ if (stringNode = dynamic_cast<StringConstASTNode*>(dataNode))
+ {
+ // create a data source with the string contents
+ std::string * stringData = stringNode->getString();
+ const uint8_t * stringContents = reinterpret_cast<const uint8_t *>(stringData->c_str());
+ source = new UnmappedDataSource(stringContents, static_cast<unsigned>(stringData->size()));
+ }
+ else if (blobNode = dynamic_cast<BlobConstASTNode*>(dataNode))
+ {
+ // create a data source with the raw binary data
+ Blob * blob = blobNode->getBlob();
+ source = new UnmappedDataSource(blob->getData(), blob->getLength());
+ }
+ else if (exprNode = dynamic_cast<ExprASTNode*>(dataNode))
+ {
+ // reduce the expression first
+ exprNode = exprNode->reduce(m_context);
+ IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(exprNode);
+ if (!intNode)
+ {
+ throw semantic_error("load pattern expression did not evaluate to an integer");
+ }
+
+ SizedIntegerValue intValue(intNode->getValue(), intNode->getSize());
+ source = new PatternSource(intValue);
+ }
+ else if (sourceNode = dynamic_cast<SourceASTNode*>(dataNode))
+ {
+ // load the entire source contents
+ SourceFile * sourceFile = getSourceFromName(sourceNode->getSourceName(), sourceNode->getFirstLine());
+ source = sourceFile->createDataSource();
+ }
+ else if (sectionNode = dynamic_cast<SectionASTNode*>(dataNode))
+ {
+ // load some subset of the source
+ SourceFile * sourceFile = getSourceFromName(sectionNode->getSourceName(), sectionNode->getFirstLine());
+ if (!sourceFile->supportsNamedSections())
+ {
+ throw semantic_error(format_string("line %d: source does not support sections", sectionNode->getFirstLine()));
+ }
+
+ // create data source from the section name
+ std::string * sectionName = sectionNode->getSectionName();
+ GlobMatcher globber(*sectionName);
+ source = sourceFile->createDataSource(globber);
+ if (!source)
+ {
+ throw semantic_error(format_string("line %d: no sections match the pattern", sectionNode->getFirstLine()));
+ }
+ }
+ else if (matchListNode = dynamic_cast<SectionMatchListASTNode*>(dataNode))
+ {
+ SourceFile * sourceFile = getSourceFromName(matchListNode->getSourceName(), matchListNode->getFirstLine());
+ if (!sourceFile->supportsNamedSections())
+ {
+ throw semantic_error(format_string("line %d: source type does not support sections", matchListNode->getFirstLine()));
+ }
+
+ // create string matcher
+ ExcludesListMatcher matcher;
+
+ // add each pattern to the matcher
+ ListASTNode * matchList = matchListNode->getSections();
+ ListASTNode::iterator it = matchList->begin();
+ for (; it != matchList->end(); ++it)
+ {
+ ASTNode * node = *it;
+ sectionNode = dynamic_cast<SectionASTNode*>(node);
+ if (!sectionNode)
+ {
+ throw std::runtime_error(format_string("line %d: unexpected node type in section pattern list", (*it)->getFirstLine()));
+ }
+ bool isInclude = sectionNode->getAction() == SectionASTNode::kInclude;
+ matcher.addPattern(isInclude, *(sectionNode->getSectionName()));
+ }
+
+ // create data source from the section match list
+ source = sourceFile->createDataSource(matcher);
+ if (!source)
+ {
+ throw semantic_error(format_string("line %d: no sections match the section pattern list", matchListNode->getFirstLine()));
+ }
+ }
+ else if (ivtNode = dynamic_cast<IVTConstASTNode*>(dataNode))
+ {
+ source = createIVTDataSource(ivtNode);
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: unexpected load data node type", dataNode->getFirstLine()));
+ }
+
+ return source;
+}
+
+DataSource * ConversionController::createIVTDataSource(IVTConstASTNode * ivtNode)
+{
+ IVTDataSource * source = new IVTDataSource;
+
+ // Iterate over the assignment statements in the IVT definition.
+ ListASTNode * fieldList = ivtNode->getFieldAssignments();
+
+ if (fieldList)
+ {
+ ListASTNode::iterator it = fieldList->begin();
+ for (; it != fieldList->end(); ++it)
+ {
+ AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(*it);
+ if (!assignmentNode)
+ {
+ throw std::runtime_error(format_string("line %d: unexpected node type in IVT definition", (*it)->getFirstLine()));
+ }
+
+ // Get the IVT field name.
+ std::string * fieldName = assignmentNode->getIdent();
+
+ // Reduce the field expression and get the integer result.
+ ASTNode * valueNode = assignmentNode->getValue();
+ ExprASTNode * valueExpr = dynamic_cast<ExprASTNode*>(valueNode);
+ if (!valueExpr)
+ {
+ throw semantic_error("IVT field must have a valid expression");
+ }
+ IntConstExprASTNode * valueIntExpr = dynamic_cast<IntConstExprASTNode*>(valueExpr->reduce(m_context));
+ if (!valueIntExpr)
+ {
+ throw semantic_error(format_string("line %d: IVT field '%s' does not evaluate to an integer", valueNode->getFirstLine(), fieldName->c_str()));
+ }
+ uint32_t value = static_cast<uint32_t>(valueIntExpr->getValue());
+
+ // Set the field in the IVT data source.
+ if (!source->setFieldByName(*fieldName, value))
+ {
+ throw semantic_error(format_string("line %d: unknown IVT field '%s'", assignmentNode->getFirstLine(), fieldName->c_str()));
+ }
+ }
+ }
+
+ return source;
+}
+
+//! Takes an AST node subclass and returns an appropriate DataTarget object that contains
+//! the same information. Supported AST node types are:
+//! - SymbolASTNode
+//! - NaturalLocationASTNode
+//! - AddressRangeASTNode
+//!
+//! \exception elftosb::semantic_error Thrown if a semantic problem is found with
+//! the target node.
+DataTarget * ConversionController::createTargetFromNode(ASTNode * targetNode)
+{
+ assert(targetNode);
+
+ DataTarget * target = NULL;
+ SymbolASTNode * symbolNode;
+ NaturalLocationASTNode * naturalNode;
+ AddressRangeASTNode * addressNode;
+
+ if (symbolNode = dynamic_cast<SymbolASTNode*>(targetNode))
+ {
+ SourceFile * sourceFile = getSourceFromName(symbolNode->getSource(), symbolNode->getFirstLine());
+ std::string * symbolName = symbolNode->getSymbolName();
+
+ // symbol name is optional
+ if (symbolName)
+ {
+ if (!sourceFile->supportsNamedSymbols())
+ {
+ throw std::runtime_error(format_string("line %d: source does not support symbols", symbolNode->getFirstLine()));
+ }
+
+ target = sourceFile->createDataTargetForSymbol(*symbolName);
+ if (!target)
+ {
+ throw std::runtime_error(format_string("line %d: source does not have a symbol with that name", symbolNode->getFirstLine()));
+ }
+ }
+ else
+ {
+ // no symbol name was specified so use entry point
+ target = sourceFile->createDataTargetForEntryPoint();
+ if (!target)
+ {
+ throw std::runtime_error(format_string("line %d: source does not have an entry point", symbolNode->getFirstLine()));
+ }
+ }
+ }
+ else if (naturalNode = dynamic_cast<NaturalLocationASTNode*>(targetNode))
+ {
+ // the target is the source's natural location
+ target = new NaturalDataTarget();
+ }
+ else if (addressNode = dynamic_cast<AddressRangeASTNode*>(targetNode))
+ {
+ // evaluate begin address
+ ExprASTNode * beginExpr = dynamic_cast<ExprASTNode*>(addressNode->getBegin());
+ if (!beginExpr)
+ {
+ throw semantic_error("address range must always have a beginning expression");
+ }
+ IntConstExprASTNode * beginIntExpr = dynamic_cast<IntConstExprASTNode*>(beginExpr->reduce(m_context));
+ if (!beginIntExpr)
+ {
+ throw semantic_error("address range begin did not evaluate to an integer");
+ }
+ uint32_t beginAddress = static_cast<uint32_t>(beginIntExpr->getValue());
+
+ // evaluate end address
+ ExprASTNode * endExpr = dynamic_cast<ExprASTNode*>(addressNode->getEnd());
+ uint32_t endAddress = 0;
+ bool hasEndAddress = false;
+ if (endExpr)
+ {
+ IntConstExprASTNode * endIntExpr = dynamic_cast<IntConstExprASTNode*>(endExpr->reduce(m_context));
+ if (!endIntExpr)
+ {
+ throw semantic_error("address range end did not evaluate to an integer");
+ }
+ endAddress = static_cast<uint32_t>(endIntExpr->getValue());
+ hasEndAddress = true;
+ }
+
+ // create target
+ if (hasEndAddress)
+ {
+ target = new ConstantDataTarget(beginAddress, endAddress);
+ }
+ else
+ {
+ target = new ConstantDataTarget(beginAddress);
+ }
+ }
+ else
+ {
+ throw semantic_error("unexpected load target node type");
+ }
+
+ return target;
+}
+
+//! \param sourceName Pointer to string containing the name of the source to look up.
+//! May be NULL, in which case the default source is used.
+//! \param line The line number on which the source name was located.
+//!
+//! \result A source file object that was previously created in the processSources()
+//! stage.
+//!
+//! \exception std::runtime_error Thrown if the source name is invalid, or if it
+//! was NULL and there is no default source (i.e., we're not inside a from
+//! statement).
+SourceFile * ConversionController::getSourceFromName(std::string * sourceName, int line)
+{
+ SourceFile * sourceFile = NULL;
+ if (sourceName)
+ {
+ // look up source in map
+ source_map_t::iterator it = m_sources.find(*sourceName);
+ if (it == m_sources.end())
+ {
+ source_name_vector_t::const_iterator findIt = std::find<source_name_vector_t::const_iterator, std::string>(m_failedSources.begin(), m_failedSources.end(), *sourceName);
+ if (findIt != m_failedSources.end())
+ {
+ throw semantic_error(format_string("line %d: error opening source '%s'", line, sourceName->c_str()));
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: invalid source name '%s'", line, sourceName->c_str()));
+ }
+ }
+ sourceFile = it->second;
+ }
+ else
+ {
+ // no name provided - use default source
+ sourceFile = m_defaultSource;
+ if (!sourceFile)
+ {
+ throw semantic_error(format_string("line %d: source required but no default source is available", line));
+ }
+ }
+
+ // open the file if it hasn't already been
+ if (!sourceFile->isOpen())
+ {
+ sourceFile->open();
+ }
+ return sourceFile;
+}
+
+//! Exercises the lexer by printing out the value of every token produced by the
+//! lexer. It is assumed that the lexer object has already be configured to read
+//! from some input file. The method will return when the lexer has exhausted all
+//! tokens, or an error occurs.
+void ConversionController::testLexer(ElftosbLexer & lexer)
+{
+ // test lexer
+ while (1)
+ {
+ YYSTYPE value;
+ int lexresult = lexer.yylex();
+ if (lexresult == 0)
+ break;
+ lexer.getSymbolValue(&value);
+ Log::log("%d -> int:%d, ast:%p", lexresult, value.m_int, value.m_str, value.m_ast);
+ if (lexresult == TOK_IDENT || lexresult == TOK_SOURCE_NAME || lexresult == TOK_STRING_LITERAL)
+ {
+ if (value.m_str)
+ {
+ Log::log(", str:%s\n", value.m_str->c_str());
+ }
+ else
+ {
+ Log::log("str:NULL\n");
+ }
+ }
+ else
+ {
+ Log::log("\n");
+ }
+ }
+}
+
+//! Prints out the value of an integer constant expression AST node. Also prints
+//! the name of the identifier associated with that node, as well as the integer
+//! size.
+void ConversionController::printIntConstExpr(const std::string & ident, IntConstExprASTNode * expr)
+{
+ // print constant value
+ char sizeChar;
+ switch (expr->getSize())
+ {
+ case kWordSize:
+ sizeChar = 'w';
+ break;
+ case kHalfWordSize:
+ sizeChar = 'h';
+ break;
+ case kByteSize:
+ sizeChar = 'b';
+ break;
+ }
+ Log::log("%s => %d:%c\n", ident.c_str(), expr->getValue(), sizeChar);
+}
+
diff --git a/elftosb2/ConversionController.h b/elftosb2/ConversionController.h
new file mode 100644
index 0000000..16ae247
--- /dev/null
+++ b/elftosb2/ConversionController.h
@@ -0,0 +1,153 @@
+/*
+ * File: ConversionController.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ConversionController_h_)
+#define _ConversionController_h_
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <stdexcept>
+#include <smart_ptr.h>
+#include <ElftosbLexer.h>
+#include <ElftosbAST.h>
+#include "EvalContext.h"
+#include "Value.h"
+#include "SourceFile.h"
+#include "Operation.h"
+#include "DataSource.h"
+#include "DataTarget.h"
+#include "OutputSection.h"
+#include "BootImage.h"
+#include "OptionDictionary.h"
+#include "BootImageGenerator.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Manages the entire elftosb file conversion process.
+ *
+ * Instances of this class are intended to be used only once. There is no
+ * way to reset an instance once it has started or completed a conversion.
+ * Thus the run() method is not reentrant. State information is stored in
+ * the object during the conversion process.
+ *
+ * Two things need to be done before the conversion can be started. The
+ * command file path has to be set with the setCommandFilePath() method,
+ * and the paths of any externally provided (i.e., from the command line)
+ * files need to be added with addExternalFilePath(). Once these tasks
+ * are completed, the run() method can be called to parse and execute the
+ * command file. After run() returns, pass an instance of
+ * BootImageGenerator to the generateOutput() method in order to get
+ * an instance of BootImage that can be written to the output file.
+ */
+class ConversionController : public OptionDictionary, public EvalContext::SourceFileManager
+{
+public:
+ //! \brief Default constructor.
+ ConversionController();
+
+ //! \brief Destructor.
+ virtual ~ConversionController();
+
+ //! \name Paths
+ //@{
+ //! \brief Specify the command file that controls the conversion process.
+ void setCommandFilePath(const std::string & path);
+
+ //! \brief Specify the path of a file provided by the user from outside the command file.
+ void addExternalFilePath(const std::string & path);
+ //@}
+
+ //! \name Conversion
+ //@{
+ //! \brief Process input files.
+ void run();
+
+ //! \brief Uses a BootImageGenerator object to create the final output boot image.
+ BootImage * generateOutput(BootImageGenerator * generator);
+ //@}
+
+ //! \name SourceFileManager interface
+ //@{
+ //! \brief Returns true if a source file with the name \a name exists.
+ virtual bool hasSourceFile(const std::string & name);
+
+ //! \brief Gets the requested source file.
+ virtual SourceFile * getSourceFile(const std::string & name);
+
+ //! \brief Returns the default source file, or NULL if none is set.
+ virtual SourceFile * getDefaultSourceFile();
+ //@}
+
+ //! \brief Returns a reference to the context used for expression evaluation.
+ inline EvalContext & getEvalContext() { return m_context; }
+
+protected:
+ //! \name AST processing
+ //@{
+ void parseCommandFile();
+ void processOptions(ListASTNode * options);
+ void processConstants(ListASTNode * constants);
+ void processSources(ListASTNode * sources);
+ void processSections(ListASTNode * sections);
+ OutputSection * convertDataSection(DataSectionContentsASTNode * dataSection, uint32_t sectionID, OptionDictionary * optionsDict);
+ //@}
+
+ //! \name Statement conversion
+ //@{
+ OperationSequence * convertStatementList(ListASTNode * statements);
+ OperationSequence * convertOneStatement(StatementASTNode * statement);
+ OperationSequence * convertLoadStatement(LoadStatementASTNode * statement);
+ OperationSequence * convertCallStatement(CallStatementASTNode * statement);
+ OperationSequence * convertFromStatement(FromStatementASTNode * statement);
+ OperationSequence * convertModeStatement(ModeStatementASTNode * statement);
+ OperationSequence * convertIfStatement(IfStatementASTNode * statement);
+ void handleMessageStatement(MessageStatementASTNode * statement);
+ //@}
+
+ //! \name Utilities
+ //@{
+ Value * convertAssignmentNodeToValue(ASTNode * node, std::string & ident);
+ SourceFile * getSourceFromName(std::string * sourceName, int line);
+ DataSource * createSourceFromNode(ASTNode * dataNode);
+ DataTarget * createTargetFromNode(ASTNode * targetNode);
+ std::string * substituteVariables(const std::string * message);
+ DataSource * createIVTDataSource(IVTConstASTNode * ivtNode);
+ //@}
+
+ //! \name Debugging
+ //@{
+ void testLexer(ElftosbLexer & lexer);
+ void printIntConstExpr(const std::string & ident, IntConstExprASTNode * expr);
+ //@}
+
+protected:
+ typedef std::map<std::string, SourceFile*> source_map_t; //!< Map from source name to object.
+ typedef std::vector<std::string> path_vector_t; //!< List of file paths.
+ typedef std::vector<OutputSection*> section_vector_t; //!< List of output sections.
+ typedef std::vector<std::string> source_name_vector_t; //!< List of source names.
+
+ smart_ptr<std::string> m_commandFilePath; //!< Path to command file.
+ smart_ptr<CommandFileASTNode> m_ast; //!< Root of the abstract syntax tree.
+ EvalContext m_context; //!< Evaluation context for expressions.
+ source_map_t m_sources; //!< Map of source names to file objects.
+ path_vector_t m_externPaths; //!< Paths provided on the command line by the user.
+ SourceFile * m_defaultSource; //!< Source to use when one isn't provided.
+ section_vector_t m_outputSections; //!< List of output sections the user wants.
+ source_name_vector_t m_failedSources; //!< List of sources that failed to open successfully.
+};
+
+//! \brief Whether to support HAB keywords during parsing.
+//!
+//! This is a standalone global solely so that the bison-generated parser code can get to it
+//! as simply as possible.
+extern bool g_enableHABSupport;
+
+}; // namespace elftosb
+
+#endif // _ConversionController_h_
diff --git a/elftosb2/Doxyfile b/elftosb2/Doxyfile
new file mode 100644
index 0000000..6e7f239
--- /dev/null
+++ b/elftosb2/Doxyfile
@@ -0,0 +1,250 @@
+# Doxyfile 1.3.9
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = elftosb
+PROJECT_NUMBER = 2.0
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = YES
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH = "/Users/creed/projects/elftosb/elftosb2" \
+ "/Users/creed/projects/sgtl/elftosb/sbtool" \
+ "/Users/creed/projects/elftosb/common" \
+ "/Users/creed/projects/sgtl/elftosb/common"
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 4
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . ../common
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/elftosb2/ElftosbAST.cpp b/elftosb2/ElftosbAST.cpp
new file mode 100644
index 0000000..ab7732b
--- /dev/null
+++ b/elftosb2/ElftosbAST.cpp
@@ -0,0 +1,1352 @@
+/*
+ * File: ElftosbAST.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "ElftosbAST.h"
+#include <stdexcept>
+#include <math.h>
+#include <assert.h>
+#include "ElftosbErrors.h"
+#include "format_string.h"
+
+using namespace elftosb;
+
+#pragma mark = ASTNode =
+
+void ASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s\n", nodeName().c_str());
+}
+
+void ASTNode::printIndent(int indent) const
+{
+ int i;
+ for (i=0; i<indent; ++i)
+ {
+ printf(" ");
+ }
+}
+
+void ASTNode::setLocation(token_loc_t & first, token_loc_t & last)
+{
+ m_location.m_firstLine = first.m_firstLine;
+ m_location.m_lastLine = last.m_lastLine;
+}
+
+void ASTNode::setLocation(ASTNode * first, ASTNode * last)
+{
+ m_location.m_firstLine = first->getLocation().m_firstLine;
+ m_location.m_lastLine = last->getLocation().m_lastLine;
+}
+
+#pragma mark = ListASTNode =
+
+ListASTNode::ListASTNode(const ListASTNode & other)
+: ASTNode(other), m_list()
+{
+ // deep copy each item of the original's list
+ const_iterator it = other.begin();
+ for (; it != other.end(); ++it)
+ {
+ m_list.push_back((*it)->clone());
+ }
+}
+
+//! Deletes child node in the list.
+//!
+ListASTNode::~ListASTNode()
+{
+ iterator it = begin();
+ for (; it != end(); it++)
+ {
+ delete *it;
+ }
+}
+
+//! If \a node is NULL then the list is left unmodified.
+//!
+//! The list node's location is automatically updated after the node is added by a call
+//! to updateLocation().
+void ListASTNode::appendNode(ASTNode * node)
+{
+ if (node)
+ {
+ m_list.push_back(node);
+ updateLocation();
+ }
+}
+
+void ListASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ int n = 0;
+ const_iterator it = begin();
+ for (; it != end(); it++, n++)
+ {
+ printIndent(indent + 1);
+ printf("%d:\n", n);
+ (*it)->printTree(indent + 2);
+ }
+}
+
+void ListASTNode::updateLocation()
+{
+ token_loc_t current = { 0 };
+ const_iterator it = begin();
+ for (; it != end(); it++)
+ {
+ const ASTNode * node = *it;
+ const token_loc_t & loc = node->getLocation();
+
+ // handle first node
+ if (current.m_firstLine == 0)
+ {
+ current = loc;
+ continue;
+ }
+
+ if (loc.m_firstLine < current.m_firstLine)
+ {
+ current.m_firstLine = loc.m_firstLine;
+ }
+
+ if (loc.m_lastLine > current.m_lastLine)
+ {
+ current.m_lastLine = loc.m_lastLine;
+ }
+ }
+
+ setLocation(current);
+}
+
+#pragma mark = CommandFileASTNode =
+
+CommandFileASTNode::CommandFileASTNode()
+: ASTNode(), m_options(), m_constants(), m_sources(), m_sections()
+{
+}
+
+CommandFileASTNode::CommandFileASTNode(const CommandFileASTNode & other)
+: ASTNode(other), m_options(), m_constants(), m_sources(), m_sections()
+{
+ m_options = dynamic_cast<ListASTNode*>(other.m_options->clone());
+ m_constants = dynamic_cast<ListASTNode*>(other.m_constants->clone());
+ m_sources = dynamic_cast<ListASTNode*>(other.m_sources->clone());
+ m_sections = dynamic_cast<ListASTNode*>(other.m_sections->clone());
+}
+
+void CommandFileASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("options:\n");
+ if (m_options) m_options->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("constants:\n");
+ if (m_constants) m_constants->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("sources:\n");
+ if (m_sources) m_sources->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("sections:\n");
+ if (m_sections) m_sections->printTree(indent + 2);
+}
+
+#pragma mark = ExprASTNode =
+
+int_size_t ExprASTNode::resultIntSize(int_size_t a, int_size_t b)
+{
+ int_size_t result;
+ switch (a)
+ {
+ case kWordSize:
+ result = kWordSize;
+ break;
+ case kHalfWordSize:
+ if (b == kWordSize)
+ {
+ result = kWordSize;
+ }
+ else
+ {
+ result = kHalfWordSize;
+ }
+ break;
+ case kByteSize:
+ if (b == kWordSize)
+ {
+ result = kWordSize;
+ }
+ else if (b == kHalfWordSize)
+ {
+ result = kHalfWordSize;
+ }
+ else
+ {
+ result = kByteSize;
+ }
+ break;
+ }
+
+ return result;
+}
+
+#pragma mark = IntConstExprASTNode =
+
+IntConstExprASTNode::IntConstExprASTNode(const IntConstExprASTNode & other)
+: ExprASTNode(other), m_value(other.m_value), m_size(other.m_size)
+{
+}
+
+void IntConstExprASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ char sizeChar='?';
+ switch (m_size)
+ {
+ case kWordSize:
+ sizeChar = 'w';
+ break;
+ case kHalfWordSize:
+ sizeChar = 'h';
+ break;
+ case kByteSize:
+ sizeChar = 'b';
+ break;
+ }
+ printf("%s(%d:%c)\n", nodeName().c_str(), m_value, sizeChar);
+}
+
+#pragma mark = VariableExprASTNode =
+
+VariableExprASTNode::VariableExprASTNode(const VariableExprASTNode & other)
+: ExprASTNode(other), m_variable()
+{
+ m_variable = new std::string(*other.m_variable);
+}
+
+void VariableExprASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s(%s)\n", nodeName().c_str(), m_variable->c_str());
+}
+
+ExprASTNode * VariableExprASTNode::reduce(EvalContext & context)
+{
+ if (!context.isVariableDefined(*m_variable))
+ {
+ throw std::runtime_error(format_string("line %d: undefined variable '%s'", getFirstLine(), m_variable->c_str()));
+ }
+
+ uint32_t value = context.getVariableValue(*m_variable);
+ int_size_t size = context.getVariableSize(*m_variable);
+ return new IntConstExprASTNode(value, size);
+}
+
+#pragma mark = SymbolRefExprASTNode =
+
+SymbolRefExprASTNode::SymbolRefExprASTNode(const SymbolRefExprASTNode & other)
+: ExprASTNode(other), m_symbol(NULL)
+{
+ if (other.m_symbol)
+ {
+ m_symbol = dynamic_cast<SymbolASTNode*>(other.m_symbol->clone());
+ }
+}
+
+void SymbolRefExprASTNode::printTree(int indent) const
+{
+}
+
+ExprASTNode * SymbolRefExprASTNode::reduce(EvalContext & context)
+{
+ EvalContext::SourceFileManager * manager = context.getSourceFileManager();
+ if (!manager)
+ {
+ throw std::runtime_error("no source manager available");
+ }
+
+ if (!m_symbol)
+ {
+ throw semantic_error("no symbol provided");
+ }
+
+ // Get the name of the symbol
+ std::string * symbolName = m_symbol->getSymbolName();
+// if (!symbolName)
+// {
+// throw semantic_error(format_string("line %d: no symbol name provided", getFirstLine()));
+// }
+
+ // Get the source file.
+ std::string * sourceName = m_symbol->getSource();
+ SourceFile * sourceFile;
+
+ if (sourceName)
+ {
+ sourceFile = manager->getSourceFile(*sourceName);
+ if (!sourceFile)
+ {
+ throw semantic_error(format_string("line %d: no source file named %s", getFirstLine(), sourceName->c_str()));
+ }
+ }
+ else
+ {
+ sourceFile = manager->getDefaultSourceFile();
+ if (!sourceFile)
+ {
+ throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
+ }
+ }
+
+ // open the file if it hasn't already been
+ if (!sourceFile->isOpen())
+ {
+ sourceFile->open();
+ }
+
+ // Make sure the source file supports symbols before going any further
+ if (symbolName && !sourceFile->supportsNamedSymbols())
+ {
+ throw semantic_error(format_string("line %d: source file %s does not support symbols", getFirstLine(), sourceFile->getPath().c_str()));
+ }
+
+ if (!symbolName && !sourceFile->hasEntryPoint())
+ {
+ throw semantic_error(format_string("line %d: source file %s does not have an entry point", getFirstLine(), sourceFile->getPath().c_str()));
+ }
+
+ // Returns a const expr node with the symbol's value.
+ uint32_t value;
+ if (symbolName)
+ {
+ value = sourceFile->getSymbolValue(*symbolName);
+ }
+ else
+ {
+ value = sourceFile->getEntryPointAddress();
+ }
+ return new IntConstExprASTNode(value);
+}
+
+#pragma mark = NegativeExprASTNode =
+
+NegativeExprASTNode::NegativeExprASTNode(const NegativeExprASTNode & other)
+: ExprASTNode(other), m_expr()
+{
+ m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
+}
+
+void NegativeExprASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+ if (m_expr) m_expr->printTree(indent + 1);
+}
+
+ExprASTNode * NegativeExprASTNode::reduce(EvalContext & context)
+{
+ if (!m_expr)
+ {
+ return this;
+ }
+
+ m_expr = m_expr->reduce(context);
+ IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(m_expr.get());
+ if (intConst)
+ {
+ int32_t value = -(int32_t)intConst->getValue();
+ return new IntConstExprASTNode((uint32_t)value, intConst->getSize());
+ }
+ else
+ {
+ return this;
+ }
+}
+
+#pragma mark = BooleanNotExprASTNode =
+
+BooleanNotExprASTNode::BooleanNotExprASTNode(const BooleanNotExprASTNode & other)
+: ExprASTNode(other), m_expr()
+{
+ m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
+}
+
+void BooleanNotExprASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+ if (m_expr) m_expr->printTree(indent + 1);
+}
+
+ExprASTNode * BooleanNotExprASTNode::reduce(EvalContext & context)
+{
+ if (!m_expr)
+ {
+ return this;
+ }
+
+ m_expr = m_expr->reduce(context);
+ IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(m_expr.get());
+ if (intConst)
+ {
+ int32_t value = !((int32_t)intConst->getValue());
+ return new IntConstExprASTNode((uint32_t)value, intConst->getSize());
+ }
+ else
+ {
+ throw semantic_error(format_string("line %d: expression did not evaluate to an integer", m_expr->getFirstLine()));
+ }
+}
+
+#pragma mark = SourceFileFunctionASTNode =
+
+SourceFileFunctionASTNode::SourceFileFunctionASTNode(const SourceFileFunctionASTNode & other)
+: ExprASTNode(other), m_functionName(), m_sourceFile()
+{
+ m_functionName = new std::string(*other.m_functionName);
+ m_sourceFile = new std::string(*other.m_sourceFile);
+}
+
+void SourceFileFunctionASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+ printIndent(indent+1);
+
+ // for some stupid reason the msft C++ compiler barfs on the following line if the ".get()" parts are remove,
+ // even though the first line of reduce() below has the same expression, just in parentheses. stupid compiler.
+ if (m_functionName.get() && m_sourceFile.get())
+ {
+ printf("%s ( %s )\n", m_functionName->c_str(), m_sourceFile->c_str());
+ }
+}
+
+ExprASTNode * SourceFileFunctionASTNode::reduce(EvalContext & context)
+{
+ if (!(m_functionName && m_sourceFile))
+ {
+ throw std::runtime_error("unset function name or source file");
+ }
+
+ // Get source file manager from evaluation context. This will be the
+ // conversion controller itself.
+ EvalContext::SourceFileManager * mgr = context.getSourceFileManager();
+ if (!mgr)
+ {
+ throw std::runtime_error("source file manager is not set");
+ }
+
+ // Perform function
+ uint32_t functionResult = 0;
+ if (*m_functionName == "exists")
+ {
+ functionResult = static_cast<uint32_t>(mgr->hasSourceFile(*m_sourceFile));
+ }
+
+ // Return function result as an expression node
+ return new IntConstExprASTNode(functionResult);
+}
+
+#pragma mark = DefinedOperatorASTNode =
+
+DefinedOperatorASTNode::DefinedOperatorASTNode(const DefinedOperatorASTNode & other)
+: ExprASTNode(other), m_constantName()
+{
+ m_constantName = new std::string(*other.m_constantName);
+}
+
+void DefinedOperatorASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+ printIndent(indent+1);
+
+ if (m_constantName)
+ {
+ printf("defined ( %s )\n", m_constantName->c_str());
+ }
+}
+
+ExprASTNode * DefinedOperatorASTNode::reduce(EvalContext & context)
+{
+ assert(m_constantName);
+
+ // Return function result as an expression node
+ return new IntConstExprASTNode(context.isVariableDefined(m_constantName) ? 1 : 0);
+}
+
+#pragma mark = SizeofOperatorASTNode =
+
+SizeofOperatorASTNode::SizeofOperatorASTNode(const SizeofOperatorASTNode & other)
+: ExprASTNode(other), m_constantName(), m_symbol()
+{
+ m_constantName = new std::string(*other.m_constantName);
+ m_symbol = dynamic_cast<SymbolASTNode*>(other.m_symbol->clone());
+}
+
+void SizeofOperatorASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+
+ printIndent(indent+1);
+
+ if (m_constantName)
+ {
+ printf("sizeof: %s\n", m_constantName->c_str());
+ }
+ else if (m_symbol)
+ {
+ printf("sizeof:\n");
+ m_symbol->printTree(indent + 2);
+ }
+}
+
+ExprASTNode * SizeofOperatorASTNode::reduce(EvalContext & context)
+{
+ // One or the other must be defined.
+ assert(m_constantName || m_symbol);
+
+ EvalContext::SourceFileManager * manager = context.getSourceFileManager();
+ assert(manager);
+
+ unsigned sizeInBytes = 0;
+ SourceFile * sourceFile;
+
+ if (m_symbol)
+ {
+ // Get the symbol name.
+ std::string * symbolName = m_symbol->getSymbolName();
+ assert(symbolName);
+
+ // Get the source file, using the default if one is not specified.
+ std::string * sourceName = m_symbol->getSource();
+ if (sourceName)
+ {
+ sourceFile = manager->getSourceFile(*sourceName);
+ if (!sourceFile)
+ {
+ throw semantic_error(format_string("line %d: invalid source file: %s", getFirstLine(), sourceName->c_str()));
+ }
+ }
+ else
+ {
+ sourceFile = manager->getDefaultSourceFile();
+ if (!sourceFile)
+ {
+ throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
+ }
+ }
+
+ // Get the size of the symbol.
+ if (sourceFile->hasSymbol(*symbolName))
+ {
+ sizeInBytes = sourceFile->getSymbolSize(*symbolName);
+ }
+ }
+ else if (m_constantName)
+ {
+ // See if the "constant" is really a constant or if it's a source name.
+ if (manager->hasSourceFile(m_constantName))
+ {
+ sourceFile = manager->getSourceFile(m_constantName);
+ if (sourceFile)
+ {
+ sizeInBytes = sourceFile->getSize();
+ }
+ }
+ else
+ {
+ // Regular constant.
+ if (!context.isVariableDefined(*m_constantName))
+ {
+ throw semantic_error(format_string("line %d: cannot get size of undefined constant %s", getFirstLine(), m_constantName->c_str()));
+ }
+
+ int_size_t intSize = context.getVariableSize(*m_constantName);
+ switch (intSize)
+ {
+ case kWordSize:
+ sizeInBytes = sizeof(uint32_t);
+ break;
+ case kHalfWordSize:
+ sizeInBytes = sizeof(uint16_t);
+ break;
+ case kByteSize:
+ sizeInBytes = sizeof(uint8_t);
+ break;
+ }
+ }
+ }
+
+ // Return function result as an expression node
+ return new IntConstExprASTNode(sizeInBytes);
+}
+
+#pragma mark = BinaryOpExprASTNode =
+
+BinaryOpExprASTNode::BinaryOpExprASTNode(const BinaryOpExprASTNode & other)
+: ExprASTNode(other), m_left(), m_op(other.m_op), m_right()
+{
+ m_left = dynamic_cast<ExprASTNode*>(other.m_left->clone());
+ m_right = dynamic_cast<ExprASTNode*>(other.m_right->clone());
+}
+
+void BinaryOpExprASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("left:\n");
+ if (m_left) m_left->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("op: %s\n", getOperatorName().c_str());
+
+ printIndent(indent + 1);
+ printf("right:\n");
+ if (m_right) m_right->printTree(indent + 2);
+}
+
+std::string BinaryOpExprASTNode::getOperatorName() const
+{
+ switch (m_op)
+ {
+ case kAdd:
+ return "+";
+ case kSubtract:
+ return "-";
+ case kMultiply:
+ return "*";
+ case kDivide:
+ return "/";
+ case kModulus:
+ return "%";
+ case kPower:
+ return "**";
+ case kBitwiseAnd:
+ return "&";
+ case kBitwiseOr:
+ return "|";
+ case kBitwiseXor:
+ return "^";
+ case kShiftLeft:
+ return "<<";
+ case kShiftRight:
+ return ">>";
+ case kLessThan:
+ return "<";
+ case kGreaterThan:
+ return ">";
+ case kLessThanEqual:
+ return "<=";
+ case kGreaterThanEqual:
+ return ">";
+ case kEqual:
+ return "==";
+ case kNotEqual:
+ return "!=";
+ case kBooleanAnd:
+ return "&&";
+ case kBooleanOr:
+ return "||";
+ }
+
+ return "???";
+}
+
+//! \todo Fix power operator under windows!!!
+//!
+ExprASTNode * BinaryOpExprASTNode::reduce(EvalContext & context)
+{
+ if (!m_left || !m_right)
+ {
+ return this;
+ }
+
+ IntConstExprASTNode * leftIntConst = NULL;
+ IntConstExprASTNode * rightIntConst = NULL;
+ uint32_t leftValue;
+ uint32_t rightValue;
+ uint32_t result = 0;
+
+ // Always reduce the left hand side.
+ m_left = m_left->reduce(context);
+ leftIntConst = dynamic_cast<IntConstExprASTNode*>(m_left.get());
+ if (!leftIntConst)
+ {
+ throw semantic_error(format_string("left hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
+ }
+ leftValue = leftIntConst->getValue();
+
+ // Boolean && and || operators are handled separately so that we can perform
+ // short-circuit evaluation.
+ if (m_op == kBooleanAnd || m_op == kBooleanOr)
+ {
+ // Reduce right hand side only if required to evaluate the boolean operator.
+ if ((m_op == kBooleanAnd && leftValue != 0) || (m_op == kBooleanOr && leftValue == 0))
+ {
+ m_right = m_right->reduce(context);
+ rightIntConst = dynamic_cast<IntConstExprASTNode*>(m_right.get());
+ if (!rightIntConst)
+ {
+ throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
+ }
+ rightValue = rightIntConst->getValue();
+
+ // Perform the boolean operation.
+ switch (m_op)
+ {
+ case kBooleanAnd:
+ result = leftValue && rightValue;
+ break;
+
+ case kBooleanOr:
+ result = leftValue && rightValue;
+ break;
+ }
+ }
+ else if (m_op == kBooleanAnd)
+ {
+ // The left hand side is false, so the && operator's result must be false
+ // without regard to the right hand side.
+ result = 0;
+ }
+ else if (m_op == kBooleanOr)
+ {
+ // The left hand value is true so the || result is automatically true.
+ result = 1;
+ }
+ }
+ else
+ {
+ // Reduce right hand side always for most operators.
+ m_right = m_right->reduce(context);
+ rightIntConst = dynamic_cast<IntConstExprASTNode*>(m_right.get());
+ if (!rightIntConst)
+ {
+ throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
+ }
+ rightValue = rightIntConst->getValue();
+
+ switch (m_op)
+ {
+ case kAdd:
+ result = leftValue + rightValue;
+ break;
+ case kSubtract:
+ result = leftValue - rightValue;
+ break;
+ case kMultiply:
+ result = leftValue * rightValue;
+ break;
+ case kDivide:
+ result = leftValue / rightValue;
+ break;
+ case kModulus:
+ result = leftValue % rightValue;
+ break;
+ case kPower:
+ #ifdef WIN32
+ result = 0;
+ #else
+ result = lroundf(powf(float(leftValue), float(rightValue)));
+ #endif
+ break;
+ case kBitwiseAnd:
+ result = leftValue & rightValue;
+ break;
+ case kBitwiseOr:
+ result = leftValue | rightValue;
+ break;
+ case kBitwiseXor:
+ result = leftValue ^ rightValue;
+ break;
+ case kShiftLeft:
+ result = leftValue << rightValue;
+ break;
+ case kShiftRight:
+ result = leftValue >> rightValue;
+ break;
+ case kLessThan:
+ result = leftValue < rightValue;
+ break;
+ case kGreaterThan:
+ result = leftValue > rightValue;
+ break;
+ case kLessThanEqual:
+ result = leftValue <= rightValue;
+ break;
+ case kGreaterThanEqual:
+ result = leftValue >= rightValue;
+ break;
+ case kEqual:
+ result = leftValue == rightValue;
+ break;
+ case kNotEqual:
+ result = leftValue != rightValue;
+ break;
+ }
+ }
+
+ // Create the result value.
+ int_size_t resultSize;
+ if (leftIntConst && rightIntConst)
+ {
+ resultSize = resultIntSize(leftIntConst->getSize(), rightIntConst->getSize());
+ }
+ else if (leftIntConst)
+ {
+ resultSize = leftIntConst->getSize();
+ }
+ else
+ {
+ // This shouldn't really be possible, but just in case.
+ resultSize = kWordSize;
+ }
+ return new IntConstExprASTNode(result, resultSize);
+}
+
+#pragma mark = IntSizeExprASTNode =
+
+IntSizeExprASTNode::IntSizeExprASTNode(const IntSizeExprASTNode & other)
+: ExprASTNode(other), m_expr(), m_size(other.m_size)
+{
+ m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
+}
+
+void IntSizeExprASTNode::printTree(int indent) const
+{
+ ExprASTNode::printTree(indent);
+
+ char sizeChar='?';
+ switch (m_size)
+ {
+ case kWordSize:
+ sizeChar = 'w';
+ break;
+ case kHalfWordSize:
+ sizeChar = 'h';
+ break;
+ case kByteSize:
+ sizeChar = 'b';
+ break;
+ }
+ printIndent(indent + 1);
+ printf("size: %c\n", sizeChar);
+
+ printIndent(indent + 1);
+ printf("expr:\n");
+ if (m_expr) m_expr->printTree(indent + 2);
+}
+
+ExprASTNode * IntSizeExprASTNode::reduce(EvalContext & context)
+{
+ if (!m_expr)
+ {
+ return this;
+ }
+
+ m_expr = m_expr->reduce(context);
+ IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(m_expr.get());
+ if (!intConst)
+ {
+ return this;
+ }
+
+ return new IntConstExprASTNode(intConst->getValue(), m_size);
+}
+
+#pragma mark = ExprConstASTNode =
+
+ExprConstASTNode::ExprConstASTNode(const ExprConstASTNode & other)
+: ConstASTNode(other), m_expr()
+{
+ m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
+}
+
+void ExprConstASTNode::printTree(int indent) const
+{
+ ConstASTNode::printTree(indent);
+ if (m_expr) m_expr->printTree(indent + 1);
+}
+
+#pragma mark = StringConstASTNode =
+
+StringConstASTNode::StringConstASTNode(const StringConstASTNode & other)
+: ConstASTNode(other), m_value()
+{
+ m_value = new std::string(other.m_value);
+}
+
+void StringConstASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s(%s)\n", nodeName().c_str(), m_value->c_str());
+}
+
+#pragma mark = BlobConstASTNode =
+
+BlobConstASTNode::BlobConstASTNode(const BlobConstASTNode & other)
+: ConstASTNode(other), m_blob()
+{
+ m_blob = new Blob(*other.m_blob);
+}
+
+void BlobConstASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+
+ const uint8_t * dataPtr = m_blob->getData();
+ unsigned dataLen = m_blob->getLength();
+ printf("%s(%p:%d)\n", nodeName().c_str(), dataPtr, dataLen);
+}
+
+#pragma mark = IVTConstASTNode =
+
+IVTConstASTNode::IVTConstASTNode(const IVTConstASTNode & other)
+: ConstASTNode(other), m_fields()
+{
+ m_fields = dynamic_cast<ListASTNode*>(other.m_fields->clone());
+}
+
+void IVTConstASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s:\n", nodeName().c_str());
+ if (m_fields)
+ {
+ m_fields->printTree(indent + 1);
+ }
+}
+
+#pragma mark = AssignmentASTNode =
+
+AssignmentASTNode::AssignmentASTNode(const AssignmentASTNode & other)
+: ASTNode(other), m_ident(), m_value()
+{
+ m_ident = new std::string(*other.m_ident);
+ m_value = dynamic_cast<ConstASTNode*>(other.m_value->clone());
+}
+
+void AssignmentASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s(%s)\n", nodeName().c_str(), m_ident->c_str());
+
+ if (m_value) m_value->printTree(indent + 1);
+}
+
+#pragma mark = SourceDefASTNode =
+
+SourceDefASTNode::SourceDefASTNode(const SourceDefASTNode & other)
+: ASTNode(other), m_name()
+{
+ m_name = new std::string(*other.m_name);
+}
+
+#pragma mark = PathSourceDefASTNode =
+
+PathSourceDefASTNode::PathSourceDefASTNode(const PathSourceDefASTNode & other)
+: SourceDefASTNode(other), m_path()
+{
+ m_path = new std::string(*other.m_path);
+}
+
+void PathSourceDefASTNode::printTree(int indent) const
+{
+ SourceDefASTNode::printTree(indent);
+
+ printIndent(indent+1);
+ printf("path: %s\n", m_path->c_str());
+
+ printIndent(indent+1);
+ printf("attributes:\n");
+ if (m_attributes)
+ {
+ m_attributes->printTree(indent+2);
+ }
+}
+
+#pragma mark = ExternSourceDefASTNode =
+
+ExternSourceDefASTNode::ExternSourceDefASTNode(const ExternSourceDefASTNode & other)
+: SourceDefASTNode(other), m_expr()
+{
+ m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
+}
+
+void ExternSourceDefASTNode::printTree(int indent) const
+{
+ SourceDefASTNode::printTree(indent);
+
+ printIndent(indent+1);
+ printf("expr:\n");
+ if (m_expr) m_expr->printTree(indent + 2);
+
+ printIndent(indent+1);
+ printf("attributes:\n");
+ if (m_attributes)
+ {
+ m_attributes->printTree(indent+2);
+ }
+}
+
+#pragma mark = SectionContentsASTNode =
+
+SectionContentsASTNode::SectionContentsASTNode(const SectionContentsASTNode & other)
+: ASTNode(other), m_sectionExpr()
+{
+ m_sectionExpr = dynamic_cast<ExprASTNode*>(other.m_sectionExpr->clone());
+}
+
+void SectionContentsASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("section#:\n");
+ if (m_sectionExpr) m_sectionExpr->printTree(indent + 2);
+}
+
+#pragma mark = DataSectionContentsASTNode =
+
+DataSectionContentsASTNode::DataSectionContentsASTNode(const DataSectionContentsASTNode & other)
+: SectionContentsASTNode(other), m_contents()
+{
+ m_contents = dynamic_cast<ASTNode*>(other.m_contents->clone());
+}
+
+void DataSectionContentsASTNode::printTree(int indent) const
+{
+ SectionContentsASTNode::printTree(indent);
+
+ if (m_contents)
+ {
+ m_contents->printTree(indent + 1);
+ }
+}
+
+#pragma mark = BootableSectionContentsASTNode =
+
+BootableSectionContentsASTNode::BootableSectionContentsASTNode(const BootableSectionContentsASTNode & other)
+: SectionContentsASTNode(other), m_statements()
+{
+ m_statements = dynamic_cast<ListASTNode*>(other.m_statements->clone());
+}
+
+void BootableSectionContentsASTNode::printTree(int indent) const
+{
+ SectionContentsASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("statements:\n");
+ if (m_statements) m_statements->printTree(indent + 2);
+}
+
+#pragma mark = IfStatementASTNode =
+
+//! \warning Be careful; this method could enter an infinite loop if m_nextIf feeds
+//! back onto itself. m_nextIf must be NULL at some point down the next if list.
+IfStatementASTNode::IfStatementASTNode(const IfStatementASTNode & other)
+: StatementASTNode(),
+ m_conditionExpr(),
+ m_ifStatements(),
+ m_nextIf(),
+ m_elseStatements()
+{
+ m_conditionExpr = dynamic_cast<ExprASTNode*>(other.m_conditionExpr->clone());
+ m_ifStatements = dynamic_cast<ListASTNode*>(other.m_ifStatements->clone());
+ m_nextIf = dynamic_cast<IfStatementASTNode*>(other.m_nextIf->clone());
+ m_elseStatements = dynamic_cast<ListASTNode*>(other.m_elseStatements->clone());
+}
+
+#pragma mark = ModeStatementASTNode =
+
+ModeStatementASTNode::ModeStatementASTNode(const ModeStatementASTNode & other)
+: StatementASTNode(other), m_modeExpr()
+{
+ m_modeExpr = dynamic_cast<ExprASTNode*>(other.m_modeExpr->clone());
+}
+
+void ModeStatementASTNode::printTree(int indent) const
+{
+ StatementASTNode::printTree(indent);
+ printIndent(indent + 1);
+ printf("mode:\n");
+ if (m_modeExpr) m_modeExpr->printTree(indent + 2);
+}
+
+#pragma mark = MessageStatementASTNode =
+
+MessageStatementASTNode::MessageStatementASTNode(const MessageStatementASTNode & other)
+: StatementASTNode(other), m_type(other.m_type), m_message()
+{
+ m_message = new std::string(*other.m_message);
+}
+
+void MessageStatementASTNode::printTree(int indent) const
+{
+ StatementASTNode::printTree(indent);
+ printIndent(indent + 1);
+ printf("%s: %s\n", getTypeName(), m_message->c_str());
+}
+
+const char * MessageStatementASTNode::getTypeName() const
+{
+ switch (m_type)
+ {
+ case kInfo:
+ return "info";
+
+ case kWarning:
+ return "warning";
+
+ case kError:
+ return "error";
+ }
+
+ return "unknown";
+}
+
+#pragma mark = LoadStatementASTNode =
+
+LoadStatementASTNode::LoadStatementASTNode(const LoadStatementASTNode & other)
+: StatementASTNode(other), m_data(), m_target(), m_isDCDLoad(other.m_isDCDLoad)
+{
+ m_data = other.m_data->clone();
+ m_target = other.m_target->clone();
+}
+
+void LoadStatementASTNode::printTree(int indent) const
+{
+ StatementASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("data:\n");
+ if (m_data) m_data->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("target:\n");
+ if (m_target) m_target->printTree(indent + 2);
+}
+
+#pragma mark = CallStatementASTNode =
+
+CallStatementASTNode::CallStatementASTNode(const CallStatementASTNode & other)
+: StatementASTNode(other), m_type(other.m_type), m_target(), m_arg()
+{
+ m_target = other.m_target->clone();
+ m_arg = other.m_arg->clone();
+}
+
+void CallStatementASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s(%s)%s\n", nodeName().c_str(), (m_type == kCallType ? "call" : "jump"), (m_isHAB ? "/HAB" : ""));
+
+ printIndent(indent + 1);
+ printf("target:\n");
+ if (m_target) m_target->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("arg:\n");
+ if (m_arg) m_arg->printTree(indent + 2);
+}
+
+#pragma mark = SourceASTNode =
+
+SourceASTNode::SourceASTNode(const SourceASTNode & other)
+: ASTNode(other), m_name()
+{
+ m_name = new std::string(*other.m_name);
+}
+
+void SourceASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+ printf("%s(%s)\n", nodeName().c_str(), m_name->c_str());
+}
+
+#pragma mark = SectionMatchListASTNode =
+
+SectionMatchListASTNode::SectionMatchListASTNode(const SectionMatchListASTNode & other)
+: ASTNode(other), m_sections(), m_source()
+{
+ if (other.m_sections)
+ {
+ m_sections = dynamic_cast<ListASTNode *>(other.m_sections->clone());
+ }
+
+ if (other.m_source)
+ {
+ m_source = new std::string(*other.m_source);
+ }
+}
+
+void SectionMatchListASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ printIndent(indent+1);
+ printf("sections:\n");
+ if (m_sections)
+ {
+ m_sections->printTree(indent+2);
+ }
+
+ printIndent(indent+1);
+ printf("source: ", m_source->c_str());
+ if (m_source)
+ {
+ printf("%s\n", m_source->c_str());
+ }
+ else
+ {
+ printf("\n");
+ }
+}
+
+#pragma mark = SectionASTNode =
+
+SectionASTNode::SectionASTNode(const SectionASTNode & other)
+: ASTNode(other), m_name(), m_source()
+{
+ m_action = other.m_action;
+
+ if (other.m_name)
+ {
+ m_name = new std::string(*other.m_name);
+ }
+
+ if (other.m_source)
+ {
+ m_source = new std::string(*other.m_source);
+ }
+}
+
+void SectionASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+
+ const char * actionName;
+ switch (m_action)
+ {
+ case kInclude:
+ actionName = "include";
+ break;
+ case kExclude:
+ actionName = "exclude";
+ break;
+ }
+
+ if (m_source)
+ {
+ printf("%s(%s:%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str(), m_source->c_str());
+ }
+ else
+ {
+ printf("%s(%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str());
+ }
+}
+
+#pragma mark = SymbolASTNode =
+
+SymbolASTNode::SymbolASTNode(const SymbolASTNode & other)
+: ASTNode(other), m_symbol(), m_source()
+{
+ m_symbol = new std::string(*other.m_symbol);
+ m_source = new std::string(*other.m_source);
+}
+
+void SymbolASTNode::printTree(int indent) const
+{
+ printIndent(indent);
+
+ const char * symbol = NULL;
+ if (m_symbol)
+ {
+ symbol = m_symbol->c_str();
+ }
+
+ const char * source = NULL;
+ if (m_source)
+ {
+ source = m_source->c_str();
+ }
+
+ printf("%s(", nodeName().c_str());
+ if (source)
+ {
+ printf(source);
+ }
+ else
+ {
+ printf(".");
+ }
+ printf(":");
+ if (symbol)
+ {
+ printf(symbol);
+ }
+ else
+ {
+ printf(".");
+ }
+ printf(")\n");
+}
+
+#pragma mark = AddressRangeASTNode =
+
+AddressRangeASTNode::AddressRangeASTNode(const AddressRangeASTNode & other)
+: ASTNode(other), m_begin(), m_end()
+{
+ m_begin = other.m_begin->clone();
+ m_end = other.m_end->clone();
+}
+
+void AddressRangeASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("begin:\n");
+ if (m_begin) m_begin->printTree(indent + 2);
+
+ printIndent(indent + 1);
+ printf("end:\n");
+ if (m_end) m_end->printTree(indent + 2);
+}
+
+#pragma mark = FromStatementASTNode =
+
+FromStatementASTNode::FromStatementASTNode(std::string * source, ListASTNode * statements)
+: StatementASTNode(), m_source(source), m_statements(statements)
+{
+}
+
+FromStatementASTNode::FromStatementASTNode(const FromStatementASTNode & other)
+: StatementASTNode(), m_source(), m_statements()
+{
+ m_source = new std::string(*other.m_source);
+ m_statements = dynamic_cast<ListASTNode*>(other.m_statements->clone());
+}
+
+void FromStatementASTNode::printTree(int indent) const
+{
+ ASTNode::printTree(indent);
+
+ printIndent(indent + 1);
+ printf("source: ");
+ if (m_source) printf("%s\n", m_source->c_str());
+
+ printIndent(indent + 1);
+ printf("statements:\n");
+ if (m_statements) m_statements->printTree(indent + 2);
+}
+
diff --git a/elftosb2/ElftosbAST.h b/elftosb2/ElftosbAST.h
new file mode 100644
index 0000000..cb70f49
--- /dev/null
+++ b/elftosb2/ElftosbAST.h
@@ -0,0 +1,1227 @@
+/*
+ * File: ElftosbAST.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ElftosbAST_h_)
+#define _ElftosbAST_h_
+
+#include "stdafx.h"
+#include <string>
+#include <list>
+#include "smart_ptr.h"
+#include "EvalContext.h"
+
+namespace elftosb
+{
+
+// forward reference
+class SymbolASTNode;
+
+/*!
+ * \brief Token location in the source file.
+ */
+struct token_loc_t
+{
+ int m_firstLine; //!< Starting line of the token.
+ int m_lastLine; //!< Ending line of the token.
+};
+
+/*!
+ * \brief The base class for all AST node classes.
+ */
+class ASTNode
+{
+public:
+ //! \brief Default constructor.
+ ASTNode() : m_parent(0) {}
+
+ //! \brief Constructor taking a parent node.
+ ASTNode(ASTNode * parent) : m_parent(parent) {}
+
+ //! \brief Copy constructor.
+ ASTNode(const ASTNode & other) : m_parent(other.m_parent) {}
+
+ //! \brief Destructor.
+ virtual ~ASTNode() {}
+
+ //! \brief Returns an exact duplicate of this object.
+ virtual ASTNode * clone() const = 0;
+
+ //! \brief Returns the name of the object's class.
+ virtual std::string nodeName() const { return "ASTNode"; }
+
+ //! \name Parents
+ //@{
+ virtual ASTNode * getParent() const { return m_parent; }
+ virtual void setParent(ASTNode * newParent) { m_parent = newParent; }
+ //@}
+
+ //! \name Tree printing
+ //@{
+ virtual void printTree() const { printTree(0); }
+ virtual void printTree(int indent) const;
+ //@}
+
+ //! \name Location
+ //@{
+ virtual void setLocation(token_loc_t & loc) { m_location = loc; }
+ virtual void setLocation(token_loc_t & first, token_loc_t & last);
+ virtual void setLocation(ASTNode * loc) { setLocation(loc->getLocation()); }
+ virtual void setLocation(ASTNode * first, ASTNode * last);
+
+ virtual token_loc_t & getLocation() { return m_location; }
+ virtual const token_loc_t & getLocation() const { return m_location; }
+
+ virtual int getFirstLine() { return m_location.m_firstLine; }
+ virtual int getLastLine() { return m_location.m_lastLine; }
+ //@}
+
+protected:
+ ASTNode * m_parent; //!< Pointer to parent node of this object. May be NULL.
+ token_loc_t m_location; //!< Location of this node in the source file.
+
+ //! \brief Prints \a indent number of spaces.
+ void printIndent(int indent) const;
+};
+
+/*!
+ * \brief AST node that contains other AST nodes.
+ *
+ * Unlike other AST nodes, the location of a ListASTNode is computed dynamically
+ * based on the nodes in its list. Or mostly dynamic at least. The updateLocation()
+ * method is used to force the list object to recalculate its beginning and ending
+ * line numbers.
+ *
+ * \todo Figure out why it crashes in the destructor when the
+ * ast_list_t type is a list of smart_ptr<ASTNode>.
+ */
+class ListASTNode : public ASTNode
+{
+public:
+ typedef std::list< /*smart_ptr<ASTNode>*/ ASTNode * > ast_list_t;
+ typedef ast_list_t::iterator iterator;
+ typedef ast_list_t::const_iterator const_iterator;
+
+public:
+ ListASTNode() {}
+
+ ListASTNode(const ListASTNode & other);
+
+ virtual ~ListASTNode();
+
+ virtual ASTNode * clone() const { return new ListASTNode(*this); }
+
+ virtual std::string nodeName() const { return "ListASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ //! \name List operations
+ //@{
+ //! \brief Adds \a node to the end of the ordered list of child nodes.
+ virtual void appendNode(ASTNode * node);
+
+ //! \brief Returns the number of nodes in this list.
+ virtual unsigned nodeCount() const { return static_cast<unsigned>(m_list.size()); }
+ //@}
+
+ //! \name Node iterators
+ //@{
+ inline iterator begin() { return m_list.begin(); }
+ inline iterator end() { return m_list.end(); }
+
+ inline const_iterator begin() const { return m_list.begin(); }
+ inline const_iterator end() const { return m_list.end(); }
+ //@}
+
+ //! \name Location
+ //@{
+ virtual void updateLocation();
+ //@}
+
+protected:
+ ast_list_t m_list; //!< Ordered list of child nodes.
+};
+
+/*!
+ *
+ */
+class OptionsBlockASTNode : public ASTNode
+{
+public:
+ OptionsBlockASTNode(ListASTNode * options) : ASTNode(), m_options(options) {}
+
+ inline ListASTNode * getOptions() { return m_options; }
+
+ virtual ASTNode * clone() const { return NULL; }
+
+protected:
+ smart_ptr<ListASTNode> m_options;
+};
+
+/*!
+ *
+ */
+class ConstantsBlockASTNode : public ASTNode
+{
+public:
+ ConstantsBlockASTNode(ListASTNode * constants) : ASTNode(), m_constants(constants) {}
+
+ inline ListASTNode * getConstants() { return m_constants; }
+
+ virtual ASTNode * clone() const { return NULL; }
+
+protected:
+ smart_ptr<ListASTNode> m_constants;
+};
+
+/*!
+ *
+ */
+class SourcesBlockASTNode : public ASTNode
+{
+public:
+ SourcesBlockASTNode(ListASTNode * sources) : ASTNode(), m_sources(sources) {}
+
+ inline ListASTNode * getSources() { return m_sources; }
+
+ virtual ASTNode * clone() const { return NULL; }
+
+protected:
+ smart_ptr<ListASTNode> m_sources;
+};
+
+/*!
+ * \brief Root node for the entire file.
+ */
+class CommandFileASTNode : public ASTNode
+{
+public:
+ CommandFileASTNode();
+ CommandFileASTNode(const CommandFileASTNode & other);
+
+ virtual std::string nodeName() const { return "CommandFileASTNode"; }
+
+ virtual ASTNode * clone() const { return new CommandFileASTNode(*this); }
+
+ virtual void printTree(int indent) const;
+
+ inline void setBlocks(ListASTNode * blocks) { m_blocks = blocks; }
+ inline void setOptions(ListASTNode * options) { m_options = options; }
+ inline void setConstants(ListASTNode * constants) { m_constants = constants; }
+ inline void setSources(ListASTNode * sources) { m_sources = sources; }
+ inline void setSections(ListASTNode * sections) { m_sections = sections; }
+
+ inline ListASTNode * getBlocks() { return m_blocks; }
+ inline ListASTNode * getOptions() { return m_options; }
+ inline ListASTNode * getConstants() { return m_constants; }
+ inline ListASTNode * getSources() { return m_sources; }
+ inline ListASTNode * getSections() { return m_sections; }
+
+protected:
+ smart_ptr<ListASTNode> m_blocks;
+ smart_ptr<ListASTNode> m_options;
+ smart_ptr<ListASTNode> m_constants;
+ smart_ptr<ListASTNode> m_sources;
+ smart_ptr<ListASTNode> m_sections;
+};
+
+/*!
+ * \brief Abstract base class for all expression AST nodes.
+ */
+class ExprASTNode : public ASTNode
+{
+public:
+ ExprASTNode() : ASTNode() {}
+ ExprASTNode(const ExprASTNode & other) : ASTNode(other) {}
+
+ virtual std::string nodeName() const { return "ExprASTNode"; }
+
+ //! \brief Evaluate the expression and produce a result node to replace this one.
+ //!
+ //! The default implementation simply return this node unmodified. This
+ //! method is responsible for deleting any nodes that are no longer needed.
+ //! (?) how to delete this?
+ virtual ExprASTNode * reduce(EvalContext & context) { return this; }
+
+ int_size_t resultIntSize(int_size_t a, int_size_t b);
+};
+
+/*!
+ *
+ */
+class IntConstExprASTNode : public ExprASTNode
+{
+public:
+ IntConstExprASTNode(uint32_t value, int_size_t size=kWordSize)
+ : ExprASTNode(), m_value(value), m_size(size)
+ {
+ }
+
+ IntConstExprASTNode(const IntConstExprASTNode & other);
+
+ virtual std::string nodeName() const { return "IntConstExprASTNode"; }
+
+ virtual ASTNode * clone() const { return new IntConstExprASTNode(*this); }
+
+ virtual void printTree(int indent) const;
+
+ uint32_t getValue() const { return m_value; }
+ int_size_t getSize() const { return m_size; }
+
+protected:
+ uint32_t m_value;
+ int_size_t m_size;
+};
+
+/*!
+ *
+ */
+class VariableExprASTNode : public ExprASTNode
+{
+public:
+ VariableExprASTNode(std::string * name) : ExprASTNode(), m_variable(name) {}
+ VariableExprASTNode(const VariableExprASTNode & other);
+
+ inline std::string * getVariableName() { return m_variable; }
+
+ virtual ASTNode * clone() const { return new VariableExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "VariableExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+protected:
+ smart_ptr<std::string> m_variable;
+};
+
+/*!
+ * \brief Expression node for a symbol reference.
+ *
+ * The symbol evaluates to its address.
+ */
+class SymbolRefExprASTNode : public ExprASTNode
+{
+public:
+ SymbolRefExprASTNode(SymbolASTNode * sym) : ExprASTNode(), m_symbol(sym) {}
+ SymbolRefExprASTNode(const SymbolRefExprASTNode & other);
+
+ virtual ASTNode * clone() const { return new SymbolRefExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SymbolRefExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+protected:
+ SymbolASTNode * m_symbol;
+};
+
+/*!
+ * \brief Negates an expression.
+ */
+class NegativeExprASTNode : public ExprASTNode
+{
+public:
+ NegativeExprASTNode(ExprASTNode * expr) : ExprASTNode(), m_expr(expr) {}
+ NegativeExprASTNode(const NegativeExprASTNode & other);
+
+ virtual ASTNode * clone() const { return new NegativeExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "NegativeExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ ExprASTNode * getExpr() { return m_expr; }
+
+protected:
+ smart_ptr<ExprASTNode> m_expr;
+};
+
+/*!
+ * \brief Performa a boolean inversion.
+ */
+class BooleanNotExprASTNode : public ExprASTNode
+{
+public:
+ BooleanNotExprASTNode(ExprASTNode * expr) : ExprASTNode(), m_expr(expr) {}
+ BooleanNotExprASTNode(const BooleanNotExprASTNode & other);
+
+ virtual ASTNode * clone() const { return new BooleanNotExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "BooleanNotExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ ExprASTNode * getExpr() { return m_expr; }
+
+protected:
+ smart_ptr<ExprASTNode> m_expr;
+};
+
+/*!
+ * \brief Calls a built-in function with a source as the parameter.
+ */
+class SourceFileFunctionASTNode : public ExprASTNode
+{
+public:
+ SourceFileFunctionASTNode(std::string * functionName, std::string * sourceFileName) : ExprASTNode(), m_functionName(functionName), m_sourceFile(sourceFileName) {}
+ SourceFileFunctionASTNode(const SourceFileFunctionASTNode & other);
+
+ virtual ASTNode * clone() const { return new SourceFileFunctionASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SourceFileFunctionASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ std::string * getFunctionName() { return m_functionName; }
+ std::string * getSourceFile() { return m_sourceFile; }
+
+protected:
+ smart_ptr<std::string> m_functionName;
+ smart_ptr<std::string> m_sourceFile;
+};
+
+/*!
+ * \brief Returns true or false depending on whether a constant is defined.
+ */
+class DefinedOperatorASTNode : public ExprASTNode
+{
+public:
+ DefinedOperatorASTNode(std::string * constantName) : ExprASTNode(), m_constantName(constantName) {}
+ DefinedOperatorASTNode(const DefinedOperatorASTNode & other);
+
+ virtual ASTNode * clone() const { return new DefinedOperatorASTNode(*this); }
+
+ virtual std::string nodeName() const { return "DefinedOperatorASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ std::string * getConstantName() { return m_constantName; }
+
+protected:
+ smart_ptr<std::string> m_constantName; //!< Name of the constant.
+};
+
+class SymbolASTNode;
+
+/*!
+ * \brief Returns an integer that is the size in bytes of the operand.
+ */
+class SizeofOperatorASTNode : public ExprASTNode
+{
+public:
+ SizeofOperatorASTNode(std::string * constantName) : ExprASTNode(), m_constantName(constantName), m_symbol() {}
+ SizeofOperatorASTNode(SymbolASTNode * symbol) : ExprASTNode(), m_constantName(), m_symbol(symbol) {}
+ SizeofOperatorASTNode(const SizeofOperatorASTNode & other);
+
+ virtual ASTNode * clone() const { return new SizeofOperatorASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SizeofOperatorASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ std::string * getConstantName() { return m_constantName; }
+ SymbolASTNode * getSymbol() { return m_symbol; }
+
+protected:
+ smart_ptr<std::string> m_constantName; //!< Name of the constant.
+ smart_ptr<SymbolASTNode> m_symbol; //!< Symbol reference. If this is non-NULL then the constant name is used instead.
+};
+
+/*!
+ *
+ */
+class BinaryOpExprASTNode : public ExprASTNode
+{
+public:
+ enum operator_t
+ {
+ kAdd,
+ kSubtract,
+ kMultiply,
+ kDivide,
+ kModulus,
+ kPower,
+ kBitwiseAnd,
+ kBitwiseOr,
+ kBitwiseXor,
+ kShiftLeft,
+ kShiftRight,
+ kLessThan,
+ kGreaterThan,
+ kLessThanEqual,
+ kGreaterThanEqual,
+ kEqual,
+ kNotEqual,
+ kBooleanAnd,
+ kBooleanOr
+ };
+
+ BinaryOpExprASTNode(ExprASTNode * left, operator_t op, ExprASTNode * right)
+ : ExprASTNode(), m_left(left), m_op(op), m_right(right)
+ {
+ }
+
+ BinaryOpExprASTNode(const BinaryOpExprASTNode & other);
+
+ virtual ASTNode * clone() const { return new BinaryOpExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "BinaryOpExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ ExprASTNode * getLeftExpr() { return m_left; }
+ ExprASTNode * getRightExpr() { return m_right; }
+ operator_t getOp() const { return m_op; }
+
+protected:
+ smart_ptr<ExprASTNode> m_left;
+ smart_ptr<ExprASTNode> m_right;
+ operator_t m_op;
+
+ std::string getOperatorName() const;
+};
+
+/*!
+ * \brief Negates an expression.
+ */
+class IntSizeExprASTNode : public ExprASTNode
+{
+public:
+ IntSizeExprASTNode(ExprASTNode * expr, int_size_t intSize) : ExprASTNode(), m_expr(expr), m_size(intSize) {}
+ IntSizeExprASTNode(const IntSizeExprASTNode & other);
+
+ virtual ASTNode * clone() const { return new IntSizeExprASTNode(*this); }
+
+ virtual std::string nodeName() const { return "IntSizeExprASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ virtual ExprASTNode * reduce(EvalContext & context);
+
+ ExprASTNode * getExpr() { return m_expr; }
+ int_size_t getIntSize() { return m_size; }
+
+protected:
+ smart_ptr<ExprASTNode> m_expr;
+ int_size_t m_size;
+};
+
+/*!
+ * Base class for const AST nodes.
+ */
+class ConstASTNode : public ASTNode
+{
+public:
+ ConstASTNode() : ASTNode() {}
+ ConstASTNode(const ConstASTNode & other) : ASTNode(other) {}
+
+protected:
+};
+
+/*!
+ *
+ */
+class ExprConstASTNode : public ConstASTNode
+{
+public:
+ ExprConstASTNode(ExprASTNode * expr) : ConstASTNode(), m_expr(expr) {}
+ ExprConstASTNode(const ExprConstASTNode & other);
+
+ virtual ASTNode * clone() const { return new ExprConstASTNode(*this); }
+
+ virtual std::string nodeName() const { return "ExprConstASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ ExprASTNode * getExpr() { return m_expr; }
+
+protected:
+ smart_ptr<ExprASTNode> m_expr;
+};
+
+/*!
+ *
+ */
+class StringConstASTNode : public ConstASTNode
+{
+public:
+ StringConstASTNode(std::string * value) : ConstASTNode(), m_value(value) {}
+ StringConstASTNode(const StringConstASTNode & other);
+
+ virtual ASTNode * clone() const { return new StringConstASTNode(*this); }
+
+ virtual std::string nodeName() const { return "StringConstASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ std::string * getString() { return m_value; }
+
+protected:
+ smart_ptr<std::string> m_value;
+};
+
+/*!
+ *
+ */
+class BlobConstASTNode : public ConstASTNode
+{
+public:
+ BlobConstASTNode(Blob * value) : ConstASTNode(), m_blob(value) {}
+ BlobConstASTNode(const BlobConstASTNode & other);
+
+ virtual ASTNode * clone() const { return new BlobConstASTNode(*this); }
+
+ virtual std::string nodeName() const { return "BlobConstASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ Blob * getBlob() { return m_blob; }
+
+protected:
+ smart_ptr<Blob> m_blob;
+};
+
+// Forward declaration.
+struct hab_ivt;
+
+/*!
+ * \brief Node for a constant IVT structure as used by HAB4.
+ */
+class IVTConstASTNode : public ConstASTNode
+{
+public:
+ IVTConstASTNode() : ConstASTNode(), m_fields() {}
+ IVTConstASTNode(const IVTConstASTNode & other);
+
+ virtual ASTNode * clone() const { return new IVTConstASTNode(*this); }
+
+ virtual std::string nodeName() const { return "IVTConstASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ void setFieldAssignments(ListASTNode * fields) { m_fields = fields; }
+ ListASTNode * getFieldAssignments() { return m_fields; }
+
+protected:
+ //! Fields of the IVT are set through assignment statements.
+ smart_ptr<ListASTNode> m_fields;
+};
+
+/*!
+ *
+ */
+class AssignmentASTNode : public ASTNode
+{
+public:
+ AssignmentASTNode(std::string * ident, ASTNode * value)
+ : ASTNode(), m_ident(ident), m_value(value)
+ {
+ }
+
+ AssignmentASTNode(const AssignmentASTNode & other);
+
+ virtual ASTNode * clone() const { return new AssignmentASTNode(*this); }
+
+ virtual std::string nodeName() const { return "AssignmentASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline std::string * getIdent() { return m_ident; }
+ inline ASTNode * getValue() { return m_value; }
+
+protected:
+ smart_ptr<std::string> m_ident;
+ smart_ptr<ASTNode> m_value;
+};
+
+/*!
+ * Base class for PathSourceDefASTNode and ExternSourceDefASTNode.
+ */
+class SourceDefASTNode : public ASTNode
+{
+public:
+ SourceDefASTNode(std::string * name) : m_name(name) {}
+ SourceDefASTNode(const SourceDefASTNode & other);
+
+ inline std::string * getName() { return m_name; }
+
+ inline void setAttributes(ListASTNode * attributes) { m_attributes = attributes; }
+ inline ListASTNode * getAttributes() { return m_attributes; }
+
+protected:
+ smart_ptr<std::string> m_name;
+ smart_ptr<ListASTNode> m_attributes;
+};
+
+/*!
+ *
+ */
+class PathSourceDefASTNode : public SourceDefASTNode
+{
+public:
+ PathSourceDefASTNode(std::string * name, std::string * path)
+ : SourceDefASTNode(name), m_path(path)
+ {
+ }
+
+ PathSourceDefASTNode(const PathSourceDefASTNode & other);
+
+ virtual PathSourceDefASTNode * clone() const { return new PathSourceDefASTNode(*this); }
+
+ virtual std::string nodeName() const { return "PathSourceDefASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ std::string * getPath() { return m_path; }
+
+protected:
+ smart_ptr<std::string> m_path;
+};
+
+/*!
+ *
+ */
+class ExternSourceDefASTNode : public SourceDefASTNode
+{
+public:
+ ExternSourceDefASTNode(std::string * name, ExprASTNode * expr)
+ : SourceDefASTNode(name), m_expr(expr)
+ {
+ }
+
+ ExternSourceDefASTNode(const ExternSourceDefASTNode & other);
+
+ virtual ASTNode * clone() const { return new ExternSourceDefASTNode(*this); }
+
+ virtual std::string nodeName() const { return "ExternSourceDefASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ ExprASTNode * getSourceNumberExpr() { return m_expr; }
+
+protected:
+ smart_ptr<ExprASTNode> m_expr;
+};
+
+/*!
+ *
+ */
+class SectionContentsASTNode : public ASTNode
+{
+public:
+ SectionContentsASTNode() : m_sectionExpr() {}
+ SectionContentsASTNode(ExprASTNode * section) : m_sectionExpr(section) {}
+ SectionContentsASTNode(const SectionContentsASTNode & other);
+
+ virtual ASTNode * clone() const { return new SectionContentsASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SectionContentsASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setSectionNumberExpr(ExprASTNode * section)
+ {
+ m_sectionExpr = section;
+ }
+
+ inline ExprASTNode * getSectionNumberExpr()
+ {
+ return m_sectionExpr;
+ }
+
+ inline void setOptions(ListASTNode * options)
+ {
+ m_options = options;
+ }
+
+ inline ListASTNode * getOptions()
+ {
+ return m_options;
+ }
+
+protected:
+ smart_ptr<ExprASTNode> m_sectionExpr;
+ smart_ptr<ListASTNode> m_options;
+};
+
+/*!
+ * @brief Node representing a raw binary section definition.
+ */
+class DataSectionContentsASTNode : public SectionContentsASTNode
+{
+public:
+ DataSectionContentsASTNode(ASTNode * contents)
+ : SectionContentsASTNode(), m_contents(contents)
+ {
+ }
+
+ DataSectionContentsASTNode(const DataSectionContentsASTNode & other);
+
+ virtual ASTNode * clone() const { return new DataSectionContentsASTNode(*this); }
+
+ virtual std::string nodeName() const { return "DataSectionContentsASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ ASTNode * getContents() { return m_contents; }
+
+protected:
+ smart_ptr<ASTNode> m_contents;
+};
+
+/*!
+ *
+ */
+class BootableSectionContentsASTNode : public SectionContentsASTNode
+{
+public:
+ BootableSectionContentsASTNode(ListASTNode * statements)
+ : SectionContentsASTNode(), m_statements(statements)
+ {
+ }
+
+ BootableSectionContentsASTNode(const BootableSectionContentsASTNode & other);
+
+ virtual ASTNode * clone() const { return new BootableSectionContentsASTNode(*this); }
+
+ virtual std::string nodeName() const { return "BootableSectionContentsASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ ListASTNode * getStatements() { return m_statements; }
+
+protected:
+ smart_ptr<ListASTNode> m_statements;
+};
+
+/*!
+ *
+ */
+class StatementASTNode : public ASTNode
+{
+public:
+ StatementASTNode() : ASTNode() {}
+ StatementASTNode(const StatementASTNode & other) : ASTNode(other) {}
+
+protected:
+};
+
+/*!
+ *
+ */
+class IfStatementASTNode : public StatementASTNode
+{
+public:
+ IfStatementASTNode() : StatementASTNode(), m_ifStatements(), m_nextIf(), m_elseStatements() {}
+ IfStatementASTNode(const IfStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new IfStatementASTNode(*this); }
+
+ void setConditionExpr(ExprASTNode * expr) { m_conditionExpr = expr; }
+ ExprASTNode * getConditionExpr() { return m_conditionExpr; }
+
+ void setIfStatements(ListASTNode * statements) { m_ifStatements = statements; }
+ ListASTNode * getIfStatements() { return m_ifStatements; }
+
+ void setNextIf(IfStatementASTNode * nextIf) { m_nextIf = nextIf; }
+ IfStatementASTNode * getNextIf() { return m_nextIf; }
+
+ void setElseStatements(ListASTNode * statements) { m_elseStatements = statements; }
+ ListASTNode * getElseStatements() { return m_elseStatements; }
+
+protected:
+ smart_ptr<ExprASTNode> m_conditionExpr; //!< Boolean expression.
+ smart_ptr<ListASTNode> m_ifStatements; //!< List of "if" section statements.
+ smart_ptr<IfStatementASTNode> m_nextIf; //!< Link to next "else if". If this is non-NULL then #m_elseStatements must be NULL and vice-versa.
+ smart_ptr<ListASTNode> m_elseStatements; //!< Statements for the "else" part of the statements.
+};
+
+/*!
+ * \brief Statement to insert a ROM_MODE_CMD command.
+ */
+class ModeStatementASTNode : public StatementASTNode
+{
+public:
+ ModeStatementASTNode() : StatementASTNode(), m_modeExpr() {}
+ ModeStatementASTNode(ExprASTNode * modeExpr) : StatementASTNode(), m_modeExpr(modeExpr) {}
+ ModeStatementASTNode(const ModeStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new ModeStatementASTNode(*this); }
+
+ virtual std::string nodeName() const { return "ModeStatementASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setModeExpr(ExprASTNode * modeExpr) { m_modeExpr = modeExpr; }
+ inline ExprASTNode * getModeExpr() { return m_modeExpr; }
+
+protected:
+ smart_ptr<ExprASTNode> m_modeExpr; //!< Expression that evaluates to the new boot mode.
+};
+
+/*!
+ * \brief Statement to print a message to the elftosb user.
+ */
+class MessageStatementASTNode : public StatementASTNode
+{
+public:
+ enum _message_type
+ {
+ kInfo, //!< Prints an informational messag to the user.
+ kWarning, //!< Prints a warning to the user.
+ kError //!< Throws an error exception.
+ };
+
+ typedef enum _message_type message_type_t;
+
+public:
+ MessageStatementASTNode(message_type_t messageType, std::string * message) : StatementASTNode(), m_type(messageType), m_message(message) {}
+ MessageStatementASTNode(const MessageStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new MessageStatementASTNode(*this); }
+
+ virtual std::string nodeName() const { return "MessageStatementASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline message_type_t getType() { return m_type; }
+ inline std::string * getMessage() { return m_message; }
+
+ const char * getTypeName() const;
+
+protected:
+ message_type_t m_type;
+ smart_ptr<std::string> m_message; //!< Message to report.
+};
+
+/*!
+ * \brief AST node for a load statement.
+ */
+class LoadStatementASTNode : public StatementASTNode
+{
+public:
+ LoadStatementASTNode()
+ : StatementASTNode(), m_data(), m_target(), m_isDCDLoad(false)
+ {
+ }
+
+ LoadStatementASTNode(ASTNode * data, ASTNode * target)
+ : StatementASTNode(), m_data(data), m_target(), m_isDCDLoad(false)
+ {
+ }
+
+ LoadStatementASTNode(const LoadStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new LoadStatementASTNode(*this); }
+
+ virtual std::string nodeName() const { return "LoadStatementASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setData(ASTNode * data) { m_data = data; }
+ inline ASTNode * getData() { return m_data; }
+
+ inline void setTarget(ASTNode * target) { m_target = target; }
+ inline ASTNode * getTarget() { return m_target; }
+
+ inline void setDCDLoad(bool isDCD) { m_isDCDLoad = isDCD; }
+ inline bool isDCDLoad() const { return m_isDCDLoad; }
+
+protected:
+ smart_ptr<ASTNode> m_data;
+ smart_ptr<ASTNode> m_target;
+ bool m_isDCDLoad;
+};
+
+/*!
+ * \brief AST node for a call statement.
+ */
+class CallStatementASTNode : public StatementASTNode
+{
+public:
+ //! Possible sub-types of call statements.
+ typedef enum {
+ kCallType,
+ kJumpType
+ } call_type_t;
+
+public:
+ CallStatementASTNode(call_type_t callType=kCallType)
+ : StatementASTNode(), m_type(callType), m_target(), m_arg(), m_isHAB(false)
+ {
+ }
+
+ CallStatementASTNode(call_type_t callType, ASTNode * target, ASTNode * arg)
+ : StatementASTNode(), m_type(callType), m_target(target), m_arg(arg), m_isHAB(false)
+ {
+ }
+
+ CallStatementASTNode(const CallStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new CallStatementASTNode(*this); }
+
+ virtual std::string nodeName() const { return "CallStatementASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setCallType(call_type_t callType) { m_type = callType; }
+ inline call_type_t getCallType() { return m_type; }
+
+ inline void setTarget(ASTNode * target) { m_target = target; }
+ inline ASTNode * getTarget() { return m_target; }
+
+ inline void setArgument(ASTNode * arg) { m_arg = arg; }
+ inline ASTNode * getArgument() { return m_arg; }
+
+ inline void setIsHAB(bool isHAB) { m_isHAB = isHAB; }
+ inline bool isHAB() const { return m_isHAB; }
+
+protected:
+ call_type_t m_type;
+ smart_ptr<ASTNode> m_target; //!< This becomes the IVT address in HAB mode.
+ smart_ptr<ASTNode> m_arg;
+ bool m_isHAB;
+};
+
+/*!
+ *
+ */
+class SourceASTNode : public ASTNode
+{
+public:
+ SourceASTNode(std::string * name) : ASTNode(), m_name(name) {}
+ SourceASTNode(const SourceASTNode & other);
+
+ virtual ASTNode * clone() const { return new SourceASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SourceASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline std::string * getSourceName() { return m_name; }
+
+protected:
+ smart_ptr<std::string> m_name;
+};
+
+/*!
+ * \brief List of section matches for a particular source name.
+ */
+class SectionMatchListASTNode : public ASTNode
+{
+public:
+ SectionMatchListASTNode(ListASTNode * sections)
+ : ASTNode(), m_sections(sections), m_source()
+ {
+ }
+
+ SectionMatchListASTNode(ListASTNode * sections, std::string * source)
+ : ASTNode(), m_sections(sections), m_source(source)
+ {
+ }
+
+ SectionMatchListASTNode(const SectionMatchListASTNode & other);
+
+ virtual ASTNode * clone() const { return new SectionMatchListASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SectionMatchListASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline ListASTNode * getSections() { return m_sections; }
+ inline std::string * getSourceName() { return m_source; }
+
+protected:
+ smart_ptr<ListASTNode> m_sections;
+ smart_ptr<std::string> m_source;
+};
+
+/*!
+ * \brief AST node for a section glob.
+ *
+ * Can be assigned an include or exclude action for when this node is part of a
+ * SectionMatchListASTNode.
+ */
+class SectionASTNode : public ASTNode
+{
+public:
+ //! Possible actions for a section match list.
+ typedef enum
+ {
+ kInclude, //!< Include sections matched by this node.
+ kExclude //!< Exclude sections matched by this node.
+ } match_action_t;
+
+public:
+ SectionASTNode(std::string * name)
+ : ASTNode(), m_action(kInclude), m_name(name), m_source()
+ {
+ }
+
+ SectionASTNode(std::string * name, match_action_t action)
+ : ASTNode(), m_action(action), m_name(name), m_source()
+ {
+ }
+
+ SectionASTNode(std::string * name, std::string * source)
+ : ASTNode(), m_action(kInclude), m_name(name), m_source(source)
+ {
+ }
+
+ SectionASTNode(const SectionASTNode & other);
+
+ virtual ASTNode * clone() const { return new SectionASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SectionASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline match_action_t getAction() { return m_action; }
+ inline std::string * getSectionName() { return m_name; }
+ inline std::string * getSourceName() { return m_source; }
+
+protected:
+ match_action_t m_action;
+ smart_ptr<std::string> m_name;
+ smart_ptr<std::string> m_source;
+};
+
+/*!
+ *
+ */
+class SymbolASTNode : public ASTNode
+{
+public:
+ SymbolASTNode()
+ : ASTNode(), m_symbol(), m_source()
+ {
+ }
+
+ SymbolASTNode(std::string * symbol, std::string * source=0)
+ : ASTNode(), m_symbol(symbol), m_source(source)
+ {
+ }
+
+ SymbolASTNode(const SymbolASTNode & other);
+
+ virtual ASTNode * clone() const { return new SymbolASTNode(*this); }
+
+ virtual std::string nodeName() const { return "SymbolASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setSymbolName(std::string * symbol) { m_symbol = symbol; }
+ inline std::string * getSymbolName() { return m_symbol; }
+
+ inline void setSource(std::string * source) { m_source = source; }
+ inline std::string * getSource() { return m_source; }
+
+protected:
+ smart_ptr<std::string> m_symbol; //!< Required.
+ smart_ptr<std::string> m_source; //!< Optional, may be NULL;
+};
+
+/*!
+ * If the end of the range is NULL, then only a single address was specified.
+ */
+class AddressRangeASTNode : public ASTNode
+{
+public:
+ AddressRangeASTNode()
+ : ASTNode(), m_begin(), m_end()
+ {
+ }
+
+ AddressRangeASTNode(ASTNode * begin, ASTNode * end)
+ : ASTNode(), m_begin(begin), m_end(end)
+ {
+ }
+
+ AddressRangeASTNode(const AddressRangeASTNode & other);
+
+ virtual ASTNode * clone() const { return new AddressRangeASTNode(*this); }
+
+ virtual std::string nodeName() const { return "AddressRangeASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setBegin(ASTNode * begin) { m_begin = begin; }
+ inline ASTNode * getBegin() { return m_begin; }
+
+ inline void setEnd(ASTNode * end) { m_end = end; }
+ inline ASTNode * getEnd() { return m_end; }
+
+protected:
+ smart_ptr<ASTNode> m_begin;
+ smart_ptr<ASTNode> m_end;
+};
+
+/*!
+ *
+ */
+class NaturalLocationASTNode : public ASTNode
+{
+public:
+ NaturalLocationASTNode()
+ : ASTNode()
+ {
+ }
+
+ NaturalLocationASTNode(const NaturalLocationASTNode & other)
+ : ASTNode(other)
+ {
+ }
+
+ virtual ASTNode * clone() const { return new NaturalLocationASTNode(*this); }
+
+ virtual std::string nodeName() const { return "NaturalLocationASTNode"; }
+};
+
+/*!
+ *
+ */
+class FromStatementASTNode : public StatementASTNode
+{
+public:
+ FromStatementASTNode() : StatementASTNode() {}
+ FromStatementASTNode(std::string * source, ListASTNode * statements);
+ FromStatementASTNode(const FromStatementASTNode & other);
+
+ virtual ASTNode * clone() const { return new FromStatementASTNode(*this); }
+
+ virtual std::string nodeName() const { return "FromStatementASTNode"; }
+
+ virtual void printTree(int indent) const;
+
+ inline void setSourceName(std::string * source) { m_source = source; }
+ inline std::string * getSourceName() { return m_source; }
+
+ inline void setStatements(ListASTNode * statements) { m_statements = statements; }
+ inline ListASTNode * getStatements() { return m_statements; }
+
+protected:
+ smart_ptr<std::string> m_source;
+ smart_ptr<ListASTNode> m_statements;
+};
+
+}; // namespace elftosb
+
+#endif // _ElftosbAST_h_
diff --git a/elftosb2/ElftosbErrors.h b/elftosb2/ElftosbErrors.h
new file mode 100644
index 0000000..abb546a
--- /dev/null
+++ b/elftosb2/ElftosbErrors.h
@@ -0,0 +1,29 @@
+/*
+ * File: ConversionController.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_ElftosbErrors_h_)
+#define _ElftosbErrors_h_
+
+#include <string>
+#include <stdexcept>
+
+namespace elftosb
+{
+
+/*!
+ * \brief A semantic error discovered while processing the command file AST.
+ */
+class semantic_error : public std::runtime_error
+{
+public:
+ explicit semantic_error(const std::string & msg)
+ : std::runtime_error(msg)
+ {}
+};
+
+}; // namespace elftosb
+
+#endif // _ElftosbErrors_h_
diff --git a/elftosb2/ElftosbLexer.cpp b/elftosb2/ElftosbLexer.cpp
new file mode 100644
index 0000000..b1ba327
--- /dev/null
+++ b/elftosb2/ElftosbLexer.cpp
@@ -0,0 +1,149 @@
+/*
+ * File: ElftosbLexer.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#include "ElftosbLexer.h"
+#include <algorithm>
+#include "HexValues.h"
+
+using namespace elftosb;
+
+ElftosbLexer::ElftosbLexer(istream & inputStream)
+: yyFlexLexer(&inputStream), m_line(1), m_blob(0), m_blobFirstLine(0)
+{
+}
+
+void ElftosbLexer::getSymbolValue(YYSTYPE * value)
+{
+ if (!value)
+ {
+ return;
+ }
+ *value = m_symbolValue;
+}
+
+void ElftosbLexer::addSourceName(std::string * ident)
+{
+ m_sources.push_back(*ident);
+}
+
+bool ElftosbLexer::isSourceName(std::string * ident)
+{
+ string_vector_t::iterator it = find(m_sources.begin(), m_sources.end(), *ident);
+ return it != m_sources.end();
+}
+
+void ElftosbLexer::LexerError(const char * msg)
+{
+ throw elftosb::lexical_error(msg);
+}
+
+//! Reads the \a in string and writes to the \a out string. These strings can be the same
+//! string since the read head is always in front of the write head.
+//!
+//! \param[in] in Input string containing C-style escape sequences.
+//! \param[out] out Output string. All escape sequences in the input string have been converted
+//! to the actual characters. May point to the same string as \a in.
+//! \return The length of the resulting \a out string. This length is necessary because
+//! the string may have contained escape sequences that inserted null characters.
+int ElftosbLexer::processStringEscapes(const char * in, char * out)
+{
+ int count = 0;
+ while (*in)
+ {
+ switch (*in)
+ {
+ case '\\':
+ {
+ // start of an escape sequence
+ char c = *++in;
+ switch (c)
+ {
+ case 0: // end of the string, bail
+ break;
+ case 'x':
+ {
+ // start of a hex char escape sequence
+
+ // read high and low nibbles, checking for end of string
+ char hi = *++in;
+ if (hi == 0) break;
+ char lo = *++in;
+ if (lo == 0) break;
+
+ if (isHexDigit(hi) && isHexDigit(lo))
+ {
+ if (hi >= '0' && hi <= '9')
+ c = (hi - '0') << 4;
+ else if (hi >= 'A' && hi <= 'F')
+ c = (hi - 'A' + 10) << 4;
+ else if (hi >= 'a' && hi <= 'f')
+ c = (hi - 'a' + 10) << 4;
+
+ if (lo >= '0' && lo <= '9')
+ c |= lo - '0';
+ else if (lo >= 'A' && lo <= 'F')
+ c |= lo - 'A' + 10;
+ else if (lo >= 'a' && lo <= 'f')
+ c |= lo - 'a' + 10;
+
+ *out++ = c;
+ count++;
+ }
+ else
+ {
+ // not hex digits, the \x must have wanted an 'x' char
+ *out++ = 'x';
+ *out++ = hi;
+ *out++ = lo;
+ count += 3;
+ }
+ break;
+ }
+ case 'n':
+ *out++ = '\n';
+ count++;
+ break;
+ case 't':
+ *out++ = '\t';
+ count++;
+ break;
+ case 'r':
+ *out++ = '\r';
+ count++;
+ break;
+ case 'b':
+ *out++ = '\b';
+ count++;
+ break;
+ case 'f':
+ *out++ = '\f';
+ count++;
+ break;
+ case '0':
+ *out++ = '\0';
+ count++;
+ break;
+ default:
+ *out++ = c;
+ count++;
+ break;
+ }
+ break;
+ }
+
+ default:
+ // copy all other chars directly
+ *out++ = *in++;
+ count++;
+ }
+ }
+
+ // place terminating null char on output
+ *out = 0;
+ return count;
+}
+
+
diff --git a/elftosb2/ElftosbLexer.h b/elftosb2/ElftosbLexer.h
new file mode 100644
index 0000000..04a16f9
--- /dev/null
+++ b/elftosb2/ElftosbLexer.h
@@ -0,0 +1,97 @@
+/*
+ * File: ElftosbLexer.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+// This header just wraps the standard flex C++ header to make it easier to include
+// without having to worry about redefinitions of the class name every time.
+
+#if !defined(_ElftosbLexer_h_)
+#define _ElftosbLexer_h_
+
+#include "ElftosbAST.h"
+#include "FlexLexer.h"
+#include "elftosb_parser.tab.hpp"
+#include <vector>
+#include <string>
+#include <stdexcept>
+#include "Blob.h"
+
+using namespace std;
+
+namespace elftosb
+{
+
+/*!
+ * \brief Exception class for syntax errors.
+ */
+class syntax_error : public std::runtime_error
+{
+public:
+ explicit syntax_error(const std::string & __arg) : std::runtime_error(__arg) {}
+};
+
+/*!
+ * \brief Exception class for lexical errors.
+ */
+class lexical_error : public std::runtime_error
+{
+public:
+ explicit lexical_error(const std::string & __arg) : std::runtime_error(__arg) {}
+};
+
+/*!
+ * \brief Lexical scanner class for elftosb command files.
+ *
+ * This class is a subclass of the standard C++ lexer class produced by
+ * Flex. It's primary purpose is to provide a clean way to report values
+ * for symbols, without using the yylval global. This is necessary because
+ * the parser produced by Bison is a "pure" parser.
+ *
+ * In addition, this class manages a list of source names generated by
+ * parsing. The lexer uses this list to determine if an identifier is
+ * a source name or a constant identifier.
+ */
+class ElftosbLexer : public yyFlexLexer
+{
+public:
+ //! \brief Constructor.
+ ElftosbLexer(istream & inputStream);
+
+ //! \brief Lexer interface. Returns one token.
+ virtual int yylex();
+
+ //! \brief Returns the value for the most recently produced token in \a value.
+ virtual void getSymbolValue(YYSTYPE * value);
+
+ //! \brief Returns the current token's location in \a loc.
+ inline token_loc_t & getLocation() { return m_location; }
+
+ //! \name Source names
+ //@{
+ void addSourceName(std::string * ident);
+ bool isSourceName(std::string * ident);
+ //@}
+
+protected:
+ YYSTYPE m_symbolValue; //!< Value for the current token.
+ int m_line; //!< Current line number.
+ token_loc_t m_location; //!< Location for the current token.
+ Blob * m_blob; //!< The binary object value as its being constructed.
+ int m_blobFirstLine; //!< Line number for the first character of a blob.
+
+ typedef std::vector<std::string> string_vector_t;
+ string_vector_t m_sources; //!< Vector of source identifiers;
+
+ //! \brief Throw an elftosb::lexical_error exception.
+ virtual void LexerError(const char * msg);
+
+ //! \brief Process a string containing escape sequences.
+ int processStringEscapes(const char * in, char * out);
+};
+
+}; // namespace elftosb
+
+#endif // _ElftosbLexer_h_
diff --git a/elftosb2/EncoreBootImageGenerator.cpp b/elftosb2/EncoreBootImageGenerator.cpp
new file mode 100644
index 0000000..9bb65c2
--- /dev/null
+++ b/elftosb2/EncoreBootImageGenerator.cpp
@@ -0,0 +1,297 @@
+/*
+ * File: EncoreBootImageGenerator.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "EncoreBootImageGenerator.h"
+#include "Logging.h"
+
+#define kFlagsOption "flags"
+#define kSectionFlagsOption "sectionFlags"
+#define kProductVersionOption "productVersion"
+#define kComponentVersionOption "componentVersion"
+#define kAlignmentOption "alignment"
+#define kCleartextOption "cleartext"
+
+using namespace elftosb;
+
+BootImage * EncoreBootImageGenerator::generate()
+{
+ EncoreBootImage * image = new EncoreBootImage();
+
+ // process each output section
+ section_vector_t::iterator it = m_sections.begin();
+ for (; it != m_sections.end(); ++it)
+ {
+ OutputSection * section = *it;
+
+ OperationSequenceSection * opSection = dynamic_cast<OperationSequenceSection*>(section);
+ if (opSection)
+ {
+ processOperationSection(opSection, image);
+ continue;
+ }
+
+ BinaryDataSection * dataSection = dynamic_cast<BinaryDataSection*>(section);
+ if (dataSection)
+ {
+ processDataSection(dataSection, image);
+ continue;
+ }
+
+ Log::log(Logger::WARNING, "warning: unexpected output section type\n");
+ }
+
+ // handle global options that affect the image
+ processOptions(image);
+
+ return image;
+}
+
+void EncoreBootImageGenerator::processOptions(EncoreBootImage * image)
+{
+ // bail if no option context was set
+ if (!m_options)
+ {
+ return;
+ }
+
+ if (m_options->hasOption(kFlagsOption))
+ {
+ const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(m_options->getOption(kFlagsOption));
+ if (intValue)
+ {
+ image->setFlags(intValue->getValue());
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: flags option is an unexpected type\n");
+ }
+ }
+
+ // handle common options
+ processVersionOptions(image);
+ processDriveTagOption(image);
+}
+
+void EncoreBootImageGenerator::processSectionOptions(EncoreBootImage::Section * imageSection, OutputSection * modelSection)
+{
+ // Get options context for this output section.
+ const OptionContext * context = modelSection->getOptions();
+ if (!context)
+ {
+ return;
+ }
+
+ // Check for and handle "sectionFlags" option.
+ if (context->hasOption(kSectionFlagsOption))
+ {
+ const Value * value = context->getOption(kSectionFlagsOption);
+ const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value);
+ if (intValue)
+ {
+ // set explicit flags for this section
+ imageSection->setFlags(intValue->getValue());
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: sectionFlags option is an unexpected type\n");
+ }
+ }
+
+ // Check for and handle "alignment" option.
+ if (context->hasOption(kAlignmentOption))
+ {
+ const Value * value = context->getOption(kAlignmentOption);
+ const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value);
+ if (intValue)
+ {
+ // verify alignment value
+ if (intValue->getValue() < EncoreBootImage::BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT)
+ {
+ Log::log(Logger::WARNING, "warning: alignment option value must be 16 or greater\n");
+ }
+
+ imageSection->setAlignment(intValue->getValue());
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: alignment option is an unexpected type\n");
+ }
+ }
+
+ // Check for and handle "cleartext" option.
+ if (context->hasOption(kCleartextOption))
+ {
+ const Value * value = context->getOption(kCleartextOption);
+ const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value);
+ if (intValue)
+ {
+ bool leaveUnencrypted = intValue->getValue() != 0;
+ imageSection->setLeaveUnencrypted(leaveUnencrypted);
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: cleartext option is an unexpected type\n");
+ }
+ }
+}
+
+void EncoreBootImageGenerator::processOperationSection(OperationSequenceSection * section, EncoreBootImage * image)
+{
+ EncoreBootImage::BootSection * newSection = new EncoreBootImage::BootSection(section->getIdentifier());
+
+ OperationSequence & sequence = section->getSequence();
+ OperationSequence::iterator_t it = sequence.begin();
+ for (; it != sequence.end(); ++it)
+ {
+ Operation * op = *it;
+
+ LoadOperation * loadOp = dynamic_cast<LoadOperation*>(op);
+ if (loadOp)
+ {
+ processLoadOperation(loadOp, newSection);
+ continue;
+ }
+
+ ExecuteOperation * execOp = dynamic_cast<ExecuteOperation*>(op);
+ if (execOp)
+ {
+ processExecuteOperation(execOp, newSection);
+ continue;
+ }
+
+ BootModeOperation * modeOp = dynamic_cast<BootModeOperation*>(op);
+ if (modeOp)
+ {
+ processBootModeOperation(modeOp, newSection);
+ continue;
+ }
+
+ Log::log(Logger::WARNING, "warning: unexpected operation type\n");
+ }
+
+ // Deal with options that apply to sections.
+ processSectionOptions(newSection, section);
+
+ // add the boot section to the image
+ image->addSection(newSection);
+}
+
+void EncoreBootImageGenerator::processLoadOperation(LoadOperation * op, EncoreBootImage::BootSection * section)
+{
+ DataSource * source = op->getSource();
+ DataTarget * target = op->getTarget();
+
+ // other sources get handled the same way
+ unsigned segmentCount = source->getSegmentCount();
+ unsigned index = 0;
+ for (; index < segmentCount; ++index)
+ {
+ DataSource::Segment * segment = source->getSegmentAt(index);
+ DataTarget::AddressRange range = target->getRangeForSegment(*source, *segment);
+ unsigned rangeLength = range.m_end - range.m_begin;
+
+ // handle a pattern segment as a special case to create a fill command
+ DataSource::PatternSegment * patternSegment = dynamic_cast<DataSource::PatternSegment*>(segment);
+ if (patternSegment)
+ {
+ SizedIntegerValue & pattern = patternSegment->getPattern();
+
+ EncoreBootImage::FillCommand * command = new EncoreBootImage::FillCommand();
+ command->setAddress(range.m_begin);
+ command->setFillCount(rangeLength);
+ setFillPatternFromValue(*command, pattern);
+
+ section->addCommand(command);
+ continue;
+ }
+
+ // get the data from the segment
+ uint8_t * data = new uint8_t[rangeLength];
+ segment->getData(0, rangeLength, data);
+
+ // create the boot command
+ EncoreBootImage::LoadCommand * command = new EncoreBootImage::LoadCommand();
+ command->setData(data, rangeLength); // Makes a copy of the data buffer.
+ command->setLoadAddress(range.m_begin);
+ command->setDCD(op->isDCDLoad());
+
+ section->addCommand(command);
+
+ // Free the segment buffer.
+ delete [] data;
+ }
+}
+
+void EncoreBootImageGenerator::setFillPatternFromValue(EncoreBootImage::FillCommand & command, SizedIntegerValue & pattern)
+{
+ uint32_t u32PatternValue = pattern.getValue() & pattern.getWordSizeMask();
+ switch (pattern.getWordSize())
+ {
+ case kWordSize:
+ {
+ command.setPattern(u32PatternValue);
+ break;
+ }
+
+ case kHalfWordSize:
+ {
+ uint16_t u16PatternValue = static_cast<uint16_t>(u32PatternValue);
+ command.setPattern(u16PatternValue);
+ break;
+ }
+
+ case kByteSize:
+ {
+ uint8_t u8PatternValue = static_cast<uint8_t>(u32PatternValue);
+ command.setPattern(u8PatternValue);
+ }
+ }
+}
+
+void EncoreBootImageGenerator::processExecuteOperation(ExecuteOperation * op, EncoreBootImage::BootSection * section)
+{
+ DataTarget * target = op->getTarget();
+ uint32_t arg = static_cast<uint32_t>(op->getArgument());
+
+ EncoreBootImage::JumpCommand * command;
+ switch (op->getExecuteType())
+ {
+ case ExecuteOperation::kJump:
+ command = new EncoreBootImage::JumpCommand();
+ break;
+
+ case ExecuteOperation::kCall:
+ command = new EncoreBootImage::CallCommand();
+ break;
+ }
+
+ command->setAddress(target->getBeginAddress());
+ command->setArgument(arg);
+ command->setIsHAB(op->isHAB());
+
+ section->addCommand(command);
+}
+
+void EncoreBootImageGenerator::processBootModeOperation(BootModeOperation * op, EncoreBootImage::BootSection * section)
+{
+ EncoreBootImage::ModeCommand * command = new EncoreBootImage::ModeCommand();
+ command->setBootMode(op->getBootMode());
+
+ section->addCommand(command);
+}
+
+void EncoreBootImageGenerator::processDataSection(BinaryDataSection * section, EncoreBootImage * image)
+{
+ EncoreBootImage::DataSection * dataSection = new EncoreBootImage::DataSection(section->getIdentifier());
+ dataSection->setData(section->getData(), section->getLength());
+
+ // Handle alignment option.
+ processSectionOptions(dataSection, section);
+
+ image->addSection(dataSection);
+}
+
diff --git a/elftosb2/EncoreBootImageGenerator.h b/elftosb2/EncoreBootImageGenerator.h
new file mode 100644
index 0000000..f0466bb
--- /dev/null
+++ b/elftosb2/EncoreBootImageGenerator.h
@@ -0,0 +1,57 @@
+/*
+ * File: EncoreBootImageGenerator.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_EncoreBootImageGenerator_h_)
+#define _EncoreBootImageGenerator_h_
+
+#include "BootImageGenerator.h"
+#include "EncoreBootImage.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Generator for Encore boot images.
+ *
+ * Takes the abstract model of the output file and processes it into a
+ * concrete boot image for the STMP37xx.
+ *
+ * In order to enable full i.mx28 support, you must call the setSupportHAB() method and
+ * pass true.
+ */
+class EncoreBootImageGenerator : public BootImageGenerator
+{
+public:
+ //! \brief Default constructor.
+ EncoreBootImageGenerator() : BootImageGenerator() {}
+
+ //! \brief Builds the resulting boot image from previously added output sections.
+ virtual BootImage * generate();
+
+ //! \brief Enable or disable HAB support.
+ void setSupportHAB(bool supportHAB) { m_supportHAB = supportHAB; }
+
+protected:
+
+ bool m_supportHAB; //!< True if HAB features are enabled.
+
+ void processOptions(EncoreBootImage * image);
+ void processSectionOptions(EncoreBootImage::Section * imageSection, OutputSection * modelSection);
+
+ void processOperationSection(OperationSequenceSection * section, EncoreBootImage * image);
+ void processDataSection(BinaryDataSection * section, EncoreBootImage * image);
+
+ void processLoadOperation(LoadOperation * op, EncoreBootImage::BootSection * section);
+ void processExecuteOperation(ExecuteOperation * op, EncoreBootImage::BootSection * section);
+ void processBootModeOperation(BootModeOperation * op, EncoreBootImage::BootSection * section);
+
+ void setFillPatternFromValue(EncoreBootImage::FillCommand & command, SizedIntegerValue & pattern);
+};
+
+}; // namespace elftosb
+
+#endif // _EncoreBootImageGenerator_h_
+
diff --git a/elftosb2/FlexLexer.h b/elftosb2/FlexLexer.h
new file mode 100644
index 0000000..8b26ef2
--- /dev/null
+++ b/elftosb2/FlexLexer.h
@@ -0,0 +1,208 @@
+// -*-C++-*-
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+// by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+
+// Neither the name of the University nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer. You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer xxFlexLexer
+// #include <FlexLexer.h>
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer zzFlexLexer
+// #include <FlexLexer.h>
+// ...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+
+#include <iostream>
+# ifndef FLEX_STD
+# define FLEX_STD std::
+# endif
+
+extern "C++" {
+
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+ virtual ~FlexLexer() { }
+
+ const char* YYText() const { return yytext; }
+ int YYLeng() const { return yyleng; }
+
+ virtual void
+ yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+ virtual struct yy_buffer_state*
+ yy_create_buffer( FLEX_STD istream* s, int size ) = 0;
+ virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+ virtual void yyrestart( FLEX_STD istream* s ) = 0;
+
+ virtual int yylex() = 0;
+
+ // Call yylex with new input/output sources.
+ int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
+ {
+ switch_streams( new_in, new_out );
+ return yylex();
+ }
+
+ // Switch to new input/output streams. A nil stream pointer
+ // indicates "keep the current one".
+ virtual void switch_streams( FLEX_STD istream* new_in = 0,
+ FLEX_STD ostream* new_out = 0 ) = 0;
+
+ int lineno() const { return yylineno; }
+
+ int debug() const { return yy_flex_debug; }
+ void set_debug( int flag ) { yy_flex_debug = flag; }
+
+protected:
+ char* yytext;
+ int yyleng;
+ int yylineno; // only maintained if you use %option yylineno
+ int yy_flex_debug; // only has effect with -d or "%option debug"
+};
+
+}
+#endif // FLEXLEXER_H
+
+//#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// had to disable the 'defined(yyFlexLexer)' part because it was causing duplicate class defs
+#if ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex manual.
+#define yyFlexLexerOnce
+
+extern "C++" {
+
+class yyFlexLexer : public FlexLexer {
+public:
+ // arg_yyin and arg_yyout default to the cin and cout, but we
+ // only make that assignment when initializing in yylex().
+ yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 );
+
+ virtual ~yyFlexLexer();
+
+ void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+ struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size );
+ void yy_delete_buffer( struct yy_buffer_state* b );
+ void yyrestart( FLEX_STD istream* s );
+
+ void yypush_buffer_state( struct yy_buffer_state* new_buffer );
+ void yypop_buffer_state();
+
+ virtual int yylex();
+ virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 );
+ virtual int yywrap();
+
+protected:
+ virtual int LexerInput( char* buf, int max_size );
+ virtual void LexerOutput( const char* buf, int size );
+ virtual void LexerError( const char* msg );
+
+ void yyunput( int c, char* buf_ptr );
+ int yyinput();
+
+ void yy_load_buffer_state();
+ void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s );
+ void yy_flush_buffer( struct yy_buffer_state* b );
+
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int* yy_start_stack;
+
+ void yy_push_state( int new_state );
+ void yy_pop_state();
+ int yy_top_state();
+
+ yy_state_type yy_get_previous_state();
+ yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+ int yy_get_next_buffer();
+
+ FLEX_STD istream* yyin; // input source for default LexerInput
+ FLEX_STD ostream* yyout; // output sink for default LexerOutput
+
+ // yy_hold_char holds the character lost when yytext is formed.
+ char yy_hold_char;
+
+ // Number of characters read into yy_ch_buf.
+ int yy_n_chars;
+
+ // Points to current character in buffer.
+ char* yy_c_buf_p;
+
+ int yy_init; // whether we need to initialize
+ int yy_start; // start state number
+
+ // Flag which is used to allow yywrap()'s to do buffer switches
+ // instead of setting up a fresh yyin. A bit of a hack ...
+ int yy_did_buffer_switch_on_eof;
+
+
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */
+ void yyensure_buffer_stack(void);
+
+ // The following are not always needed, but may be depending
+ // on use of certain flex features (like REJECT or yymore()).
+
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ yy_state_type* yy_state_buf;
+ yy_state_type* yy_state_ptr;
+
+ char* yy_full_match;
+ int* yy_full_state;
+ int yy_full_lp;
+
+ int yy_lp;
+ int yy_looking_for_trail_begin;
+
+ int yy_more_flag;
+ int yy_more_len;
+ int yy_more_offset;
+ int yy_prev_more_offset;
+};
+
+}
+
+#endif // yyFlexLexer || ! yyFlexLexerOnce
+
diff --git a/elftosb2/elftosb.cpp b/elftosb2/elftosb.cpp
new file mode 100644
index 0000000..f358bd9
--- /dev/null
+++ b/elftosb2/elftosb.cpp
@@ -0,0 +1,700 @@
+/*
+ * File: elftosb.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdlib.h>
+#include <stdexcept>
+#include "ConversionController.h"
+#include "options.h"
+#include "Version.h"
+#include "EncoreBootImage.h"
+#include "smart_ptr.h"
+#include "Logging.h"
+#include "EncoreBootImageGenerator.h"
+#include "SearchPath.h"
+#include "format_string.h"
+
+//! An array of strings.
+typedef std::vector<std::string> string_vector_t;
+
+//! The tool's name.
+const char k_toolName[] = "elftosb";
+
+//! Current version number for the tool.
+const char k_version[] = "2.6.1";
+
+//! Copyright string.
+const char k_copyright[] = "Copyright (c) 2004-2010 Freescale Semiconductor, Inc.\nAll rights reserved.";
+
+static const char * k_optionsDefinition[] = {
+ "?|help",
+ "v|version",
+ "f:chip-family <family>",
+ "c:command <file>",
+ "o:output <file>",
+ "P:product <version>",
+ "C:component <version>",
+ "k:key <file>",
+ "z|zero-key",
+ "D:define <const>",
+ "O:option <option>",
+ "d|debug",
+ "q|quiet",
+ "V|verbose",
+ "p:search-path <path>",
+ NULL
+};
+
+//! Help string.
+const char k_usageText[] = "\nOptions:\n\
+ -?/--help Show this help\n\
+ -v/--version Display tool version\n\
+ -f/--chip-family <family> Select the chip family (default is 37xx)\n\
+ -c/--command <file> Use this command file\n\
+ -o/--output <file> Write output to this file\n\
+ -p/--search-path <path> Add a search path used to find input files\n\
+ -P/--product <version Set product version\n\
+ -C/--component <version> Set component version\n\
+ -k/--key <file> Add OTP key, enable encryption\n\
+ -z/--zero-key Add default key of all zeroes\n\
+ -D/--define <const>=<int> Define or override a constant value\n\
+ -O/--option <name>=<value> Set or override a processing option\n\
+ -d/--debug Enable debug output\n\
+ -q/--quiet Output only warnings and errors\n\
+ -V/--verbose Print extra detailed log information\n\n";
+
+// prototypes
+int main(int argc, char* argv[], char* envp[]);
+
+/*!
+ * \brief Class that encapsulates the elftosb tool.
+ *
+ * A single global logger instance is created during object construction. It is
+ * never freed because we need it up to the last possible minute, when an
+ * exception could be thrown.
+ */
+class elftosbTool
+{
+protected:
+ //! Supported chip families.
+ enum chip_family_t
+ {
+ k37xxFamily, //!< 37xx series.
+ kMX28Family, //!< Catskills series.
+ };
+
+ /*!
+ * \brief A structure describing an entry in the table of chip family names.
+ */
+ struct FamilyNameTableEntry
+ {
+ const char * const name;
+ chip_family_t family;
+ };
+
+ //! \brief Table that maps from family name strings to chip family constants.
+ static const FamilyNameTableEntry kFamilyNameTable[];
+
+ int m_argc; //!< Number of command line arguments.
+ char ** m_argv; //!< String value for each command line argument.
+ StdoutLogger * m_logger; //!< Singleton logger instance.
+ string_vector_t m_keyFilePaths; //!< Paths to OTP key files.
+ string_vector_t m_positionalArgs; //!< Arguments coming after explicit options.
+ bool m_isVerbose; //!< Whether the verbose flag was turned on.
+ bool m_useDefaultKey; //!< Include a default (zero) crypto key.
+ const char * m_commandFilePath; //!< Path to the elftosb command file.
+ const char * m_outputFilePath; //!< Path to the output .sb file.
+ const char * m_searchPath; //!< Optional search path for input files.
+ elftosb::version_t m_productVersion; //!< Product version specified on command line.
+ elftosb::version_t m_componentVersion; //!< Component version specified on command line.
+ bool m_productVersionSpecified; //!< True if the product version was specified on the command line.
+ bool m_componentVersionSpecified; //!< True if the component version was specified on the command line.
+ chip_family_t m_family; //!< Chip family that the output file is formatted for.
+ elftosb::ConversionController m_controller; //!< Our conversion controller instance.
+
+public:
+ /*!
+ * Constructor.
+ *
+ * Creates the singleton logger instance.
+ */
+ elftosbTool(int argc, char * argv[])
+ : m_argc(argc),
+ m_argv(argv),
+ m_logger(0),
+ m_keyFilePaths(),
+ m_positionalArgs(),
+ m_isVerbose(false),
+ m_useDefaultKey(false),
+ m_commandFilePath(NULL),
+ m_outputFilePath(NULL),
+ m_searchPath(NULL),
+ m_productVersion(),
+ m_componentVersion(),
+ m_productVersionSpecified(false),
+ m_componentVersionSpecified(false),
+ m_family(k37xxFamily),
+ m_controller()
+ {
+ // create logger instance
+ m_logger = new StdoutLogger();
+ m_logger->setFilterLevel(Logger::INFO);
+ Log::setLogger(m_logger);
+ }
+
+ /*!
+ * Destructor.
+ */
+ ~elftosbTool()
+ {
+ }
+
+ /*!
+ * \brief Searches the family name table.
+ *
+ * \retval true The \a name was found in the table, and \a family is valid.
+ * \retval false No matching family name was found. The \a family argument is not modified.
+ */
+ bool lookupFamilyName(const char * name, chip_family_t * family)
+ {
+ // Create a local read-write copy of the argument string.
+ std::string familyName(name);
+
+ // Convert the argument string to lower case for case-insensitive comparison.
+ for (int n=0; n < familyName.length(); n++)
+ {
+ familyName[n] = tolower(familyName[n]);
+ }
+
+ // Exit the loop if we hit the NULL terminator entry.
+ const FamilyNameTableEntry * entry = &kFamilyNameTable[0];
+ for (; entry->name; entry++)
+ {
+ // Compare lowercased name with the table entry.
+ if (familyName == entry->name)
+ {
+ *family = entry->family;
+ return true;
+ }
+ }
+
+ // Failed to find a matching name.
+ return false;
+ }
+
+ /*!
+ * Reads the command line options passed into the constructor.
+ *
+ * This method can return a return code to its caller, which will cause the
+ * tool to exit immediately with that return code value. Normally, though, it
+ * will return -1 to signal that the tool should continue to execute and
+ * all options were processed successfully.
+ *
+ * The Options class is used to parse command line options. See
+ * #k_optionsDefinition for the list of options and #k_usageText for the
+ * descriptive help for each option.
+ *
+ * \retval -1 The options were processed successfully. Let the tool run normally.
+ * \return A zero or positive result is a return code value that should be
+ * returned from the tool as it exits immediately.
+ */
+ int processOptions()
+ {
+ Options options(*m_argv, k_optionsDefinition);
+ OptArgvIter iter(--m_argc, ++m_argv);
+
+ // process command line options
+ int optchar;
+ const char * optarg;
+ while (optchar = options(iter, optarg))
+ {
+ switch (optchar)
+ {
+ case '?':
+ printUsage(options);
+ return 0;
+
+ case 'v':
+ printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
+ return 0;
+
+ case 'f':
+ if (!lookupFamilyName(optarg, &m_family))
+ {
+ Log::log(Logger::ERROR, "error: unknown chip family '%s'\n", optarg);
+ printUsage(options);
+ return 0;
+ }
+ break;
+
+ case 'c':
+ m_commandFilePath = optarg;
+ break;
+
+ case 'o':
+ m_outputFilePath = optarg;
+ break;
+
+ case 'P':
+ m_productVersion.set(optarg);
+ m_productVersionSpecified = true;
+ break;
+
+ case 'C':
+ m_componentVersion.set(optarg);
+ m_componentVersionSpecified = true;
+ break;
+
+ case 'k':
+ m_keyFilePaths.push_back(optarg);
+ break;
+
+ case 'z':
+ m_useDefaultKey = true;
+ break;
+
+ case 'D':
+ overrideVariable(optarg);
+ break;
+
+ case 'O':
+ overrideOption(optarg);
+ break;
+
+ case 'd':
+ Log::getLogger()->setFilterLevel(Logger::DEBUG);
+ break;
+
+ case 'q':
+ Log::getLogger()->setFilterLevel(Logger::WARNING);
+ break;
+
+ case 'V':
+ m_isVerbose = true;
+ break;
+
+ case 'p':
+ {
+ std::string newSearchPath(optarg);
+ PathSearcher::getGlobalSearcher().addSearchPath(newSearchPath);
+ break;
+ }
+
+ default:
+ Log::log(Logger::ERROR, "error: unrecognized option\n\n");
+ printUsage(options);
+ return 0;
+ }
+ }
+
+ // handle positional args
+ if (iter.index() < m_argc)
+ {
+ Log::SetOutputLevel leveler(Logger::DEBUG);
+ Log::log("positional args:\n");
+ int i;
+ for (i = iter.index(); i < m_argc; ++i)
+ {
+ Log::log("%d: %s\n", i - iter.index(), m_argv[i]);
+ m_positionalArgs.push_back(m_argv[i]);
+ }
+ }
+
+ // all is well
+ return -1;
+ }
+
+ /*!
+ * Prints help for the tool.
+ */
+ void printUsage(Options & options)
+ {
+ options.usage(std::cout, "files...");
+ printf(k_usageText, k_toolName);
+ }
+
+ /*!
+ * \brief Core of the tool.
+ *
+ * Calls processOptions() to handle command line options before performing the
+ * real work the tool does.
+ */
+ int run()
+ {
+ try
+ {
+ // read command line options
+ int result;
+ if ((result = processOptions()) != -1)
+ {
+ return result;
+ }
+
+ // set verbose logging
+ setVerboseLogging();
+
+ // check argument values
+ checkArguments();
+
+ // set up the controller
+ m_controller.setCommandFilePath(m_commandFilePath);
+
+ // add external paths to controller
+ string_vector_t::iterator it = m_positionalArgs.begin();
+ for (; it != m_positionalArgs.end(); ++it)
+ {
+ m_controller.addExternalFilePath(*it);
+ }
+
+ // run conversion
+ convert();
+ }
+ catch (std::exception & e)
+ {
+ Log::log(Logger::ERROR, "error: %s\n", e.what());
+ return 1;
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /*!
+ * \brief Validate arguments that can be checked.
+ * \exception std::runtime_error Thrown if an argument value fails to pass validation.
+ */
+ void checkArguments()
+ {
+ if (m_commandFilePath == NULL)
+ {
+ throw std::runtime_error("no command file was specified");
+ }
+ if (m_outputFilePath == NULL)
+ {
+ throw std::runtime_error("no output file was specified");
+ }
+ }
+
+ /*!
+ * \brief Turns on verbose logging.
+ */
+ void setVerboseLogging()
+ {
+ if (m_isVerbose)
+ {
+ // verbose only affects the INFO and DEBUG filter levels
+ // if the user has selected quiet mode, it overrides verbose
+ switch (Log::getLogger()->getFilterLevel())
+ {
+ case Logger::INFO:
+ Log::getLogger()->setFilterLevel(Logger::INFO2);
+ break;
+ case Logger::DEBUG:
+ Log::getLogger()->setFilterLevel(Logger::DEBUG2);
+ break;
+ }
+ }
+ }
+
+ /*!
+ * \brief Returns the integer value for a string.
+ *
+ * Metric multiplier prefixes are supported.
+ */
+ uint32_t parseIntValue(const char * value)
+ {
+ // Accept 'true'/'yes' and 'false'/'no' as integer values.
+ if ((strcmp(value, "true") == 0) || (strcmp(value, "yes") == 0))
+ {
+ return 1;
+ }
+ else if ((strcmp(value, "false") == 0) || (strcmp(value, "no") == 0))
+ {
+ return 0;
+ }
+
+ uint32_t intValue = strtoul(value, NULL, 0);
+ unsigned multiplier;
+ switch (value[strlen(value) - 1])
+ {
+ case 'G':
+ multiplier = 1024 * 1024 * 1024;
+ break;
+ case 'M':
+ multiplier = 1024 * 1024;
+ break;
+ case 'K':
+ multiplier = 1024;
+ break;
+ default:
+ multiplier = 1;
+ }
+ intValue *= multiplier;
+ return intValue;
+ }
+
+ /*!
+ * \brief Parses the -D option to override a constant value.
+ */
+ void overrideVariable(const char * optarg)
+ {
+ // split optarg into two strings
+ std::string constName(optarg);
+ int i;
+ for (i=0; i < strlen(optarg); ++i)
+ {
+ if (optarg[i] == '=')
+ {
+ constName.resize(i++);
+ break;
+ }
+ }
+
+ uint32_t constValue = parseIntValue(&optarg[i]);
+
+ elftosb::EvalContext & context = m_controller.getEvalContext();
+ context.setVariable(constName, constValue);
+ context.lockVariable(constName);
+ }
+
+ /*!
+ * \brief
+ */
+ void overrideOption(const char * optarg)
+ {
+ // split optarg into two strings
+ std::string optionName(optarg);
+ int i;
+ for (i=0; i < strlen(optarg); ++i)
+ {
+ if (optarg[i] == '=')
+ {
+ optionName.resize(i++);
+ break;
+ }
+ }
+
+ // handle quotes for option value
+ const char * valuePtr = &optarg[i];
+ bool isString = false;
+ int len;
+ if (valuePtr[0] == '"')
+ {
+ // remember that the value is a string and get rid of the opening quote
+ isString = true;
+ valuePtr++;
+
+ // remove trailing quote if present
+ len = strlen(valuePtr);
+ if (valuePtr[len] == '"')
+ {
+ len--;
+ }
+ }
+
+ elftosb::Value * value;
+ if (isString)
+ {
+ std::string stringValue(valuePtr);
+ stringValue.resize(len); // remove trailing quote
+ value = new elftosb::StringValue(stringValue);
+ }
+ else
+ {
+ value = new elftosb::IntegerValue(parseIntValue(valuePtr));
+ }
+
+ // Set and lock the option in the controller
+ m_controller.setOption(optionName, value);
+ m_controller.lockOption(optionName);
+ }
+
+ /*!
+ * \brief Do the conversion.
+ * \exception std::runtime_error This exception is thrown if the conversion controller does
+ * not produce a boot image, or if the output file cannot be opened. Other errors
+ * internal to the conversion controller may also produce this exception.
+ */
+ void convert()
+ {
+ // create a generator for the chosen chip family
+ smart_ptr<elftosb::BootImageGenerator> generator;
+ switch (m_family)
+ {
+ case k37xxFamily:
+ generator = new elftosb::EncoreBootImageGenerator;
+ elftosb::g_enableHABSupport = false;
+ break;
+
+ case kMX28Family:
+ generator = new elftosb::EncoreBootImageGenerator;
+ elftosb::g_enableHABSupport = true;
+ break;
+ }
+
+ // process input and get a boot image
+ m_controller.run();
+ smart_ptr<elftosb::BootImage> image = m_controller.generateOutput(generator);
+ if (!image)
+ {
+ throw std::runtime_error("failed to produce output!");
+ }
+
+ // set version numbers if they were provided on the command line
+ if (m_productVersionSpecified)
+ {
+ image->setProductVersion(m_productVersion);
+ }
+ if (m_componentVersionSpecified)
+ {
+ image->setComponentVersion(m_componentVersion);
+ }
+
+ // special handling for each family
+ switch (m_family)
+ {
+ case k37xxFamily:
+ case kMX28Family:
+ {
+ // add OTP keys
+ elftosb::EncoreBootImage * encoreImage = dynamic_cast<elftosb::EncoreBootImage*>(image.get());
+ if (encoreImage)
+ {
+ // add keys
+ addCryptoKeys(encoreImage);
+
+ // print debug image
+ encoreImage->debugPrint();
+ }
+ break;
+ }
+ }
+
+ // write output
+ std::ofstream outputStream(m_outputFilePath, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
+ if (outputStream.is_open())
+ {
+ image->writeToStream(outputStream);
+ }
+ else
+ {
+ throw std::runtime_error(format_string("could not open output file %s", m_outputFilePath));
+ }
+ }
+
+ /*!
+ * \brief
+ */
+ void addCryptoKeys(elftosb::EncoreBootImage * encoreImage)
+ {
+ string_vector_t::iterator it = m_keyFilePaths.begin();
+ for (; it != m_keyFilePaths.end(); ++it)
+ {
+ std::string & keyPath = *it;
+
+ std::string actualPath;
+ bool found = PathSearcher::getGlobalSearcher().search(keyPath, PathSearcher::kFindFile, true, actualPath);
+ if (!found)
+ {
+ throw std::runtime_error(format_string("unable to find key file %s\n", keyPath.c_str()));
+ }
+
+ std::ifstream keyStream(actualPath.c_str(), std::ios_base::in);
+ if (!keyStream.is_open())
+ {
+ throw std::runtime_error(format_string("unable to read key file %s\n", keyPath.c_str()));
+ }
+ keyStream.seekg(0);
+
+ try
+ {
+ // read as many keys as possible from the stream
+ while (true)
+ {
+ AESKey<128> key(keyStream);
+ encoreImage->addKey(key);
+
+ // dump key bytes
+ dumpKey(key);
+ }
+ }
+ catch (...)
+ {
+ // ignore the exception -- there are just no more keys in the stream
+ }
+ }
+
+ // add the default key of all zero bytes if requested
+ if (m_useDefaultKey)
+ {
+ AESKey<128> defaultKey;
+ encoreImage->addKey(defaultKey);
+ }
+ }
+
+ /*!
+ * \brief Write the value of each byte of the \a key to the log.
+ */
+ void dumpKey(const AESKey<128> & key)
+ {
+ // dump key bytes
+ Log::log(Logger::DEBUG, "key bytes: ");
+ AESKey<128>::key_t the_key;
+ key.getKey(&the_key);
+ int q;
+ for (q=0; q<16; q++)
+ {
+ Log::log(Logger::DEBUG, "%02x ", the_key[q]);
+ }
+ Log::log(Logger::DEBUG, "\n");
+ }
+
+};
+
+const elftosbTool::FamilyNameTableEntry elftosbTool::kFamilyNameTable[] =
+ {
+ { "37xx", k37xxFamily },
+ { "377x", k37xxFamily },
+ { "378x", k37xxFamily },
+ { "mx23", k37xxFamily },
+ { "imx23", k37xxFamily },
+ { "i.mx23", k37xxFamily },
+ { "mx28", kMX28Family },
+ { "imx28", kMX28Family },
+ { "i.mx28", kMX28Family },
+
+ // Null terminator entry.
+ { NULL, k37xxFamily }
+ };
+
+/*!
+ * Main application entry point. Creates an sbtool instance and lets it take over.
+ */
+int main(int argc, char* argv[], char* envp[])
+{
+ try
+ {
+ return elftosbTool(argc, argv).run();
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/elftosb2/elftosb_lexer.cpp b/elftosb2/elftosb_lexer.cpp
new file mode 100644
index 0000000..3b87842
--- /dev/null
+++ b/elftosb2/elftosb_lexer.cpp
@@ -0,0 +1,2241 @@
+#line 2 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_lexer.cpp"
+
+#line 4 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_lexer.cpp"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+ /* The c++ scanner is a mess. The FlexLexer.h header file relies on the
+ * following macro. This is required in order to pass the c++-multiple-scanners
+ * test in the regression suite. We get reports that it breaks inheritance.
+ * We will address this in a future release of flex, or omit the C++ scanner
+ * altogether.
+ */
+ #define yyFlexLexer yyFlexLexer
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+#include <iostream>
+#include <errno.h>
+#include <cstdlib>
+#include <cstring>
+/* end standard C++ headers. */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+
+ std::istream* yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+#define yytext_ptr yytext
+
+#include <FlexLexer.h>
+
+int yyFlexLexer::yywrap() { return 1; }
+int yyFlexLexer::yylex()
+ {
+ LexerError( "yyFlexLexer::yylex invoked but %option yyclass used" );
+ return 0;
+ }
+
+#define YY_DECL int ElftosbLexer::yylex()
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 74
+#define YY_END_OF_BUFFER 75
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[218] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 75, 73, 70, 71,
+ 71, 64, 73, 73, 73, 49, 54, 73, 34, 35,
+ 47, 45, 39, 46, 42, 48, 27, 27, 40, 41,
+ 57, 38, 43, 26, 36, 37, 51, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 32, 55, 33, 50, 73, 73,
+ 72, 70, 71, 72, 71, 61, 0, 65, 0, 0,
+ 69, 29, 62, 0, 0, 56, 44, 30, 0, 0,
+ 27, 27, 0, 0, 52, 59, 60, 58, 53, 26,
+ 23, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+
+ 26, 26, 13, 26, 26, 26, 26, 26, 25, 26,
+ 26, 26, 26, 26, 26, 26, 26, 31, 63, 66,
+ 67, 68, 0, 0, 28, 0, 0, 27, 27, 26,
+ 26, 20, 26, 26, 26, 26, 26, 26, 26, 21,
+ 26, 22, 26, 26, 26, 26, 8, 26, 26, 26,
+ 26, 26, 24, 0, 0, 28, 0, 0, 0, 11,
+ 26, 26, 14, 26, 26, 26, 26, 7, 16, 10,
+ 9, 12, 26, 26, 26, 26, 26, 0, 0, 0,
+ 0, 28, 0, 26, 26, 18, 26, 26, 26, 26,
+ 26, 26, 26, 28, 0, 28, 0, 26, 26, 6,
+
+ 26, 26, 26, 19, 26, 26, 0, 26, 15, 4,
+ 1, 5, 3, 17, 26, 2, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 22, 22, 22, 22, 22, 22, 22, 23, 24, 25,
+ 26, 27, 28, 1, 29, 29, 30, 29, 31, 29,
+ 32, 33, 33, 33, 32, 33, 32, 33, 33, 33,
+ 33, 33, 34, 33, 33, 33, 33, 33, 33, 33,
+ 35, 1, 36, 37, 33, 1, 38, 39, 40, 41,
+
+ 42, 43, 44, 45, 46, 47, 33, 48, 49, 50,
+ 51, 52, 33, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[66] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 1, 1, 3, 3, 1, 4,
+ 4, 4, 1, 1, 1, 1, 1, 3, 4, 4,
+ 4, 5, 5, 5, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[231] =
+ { 0,
+ 0, 0, 64, 127, 67, 73, 384, 385, 385, 385,
+ 380, 356, 66, 378, 0, 385, 370, 348, 385, 385,
+ 364, 385, 385, 385, 359, 59, 78, 94, 385, 385,
+ 57, 350, 62, 0, 385, 385, 385, 191, 41, 69,
+ 60, 74, 337, 75, 318, 322, 321, 320, 318, 331,
+ 92, 315, 329, 324, 303, 301, 385, 385, 0, 299,
+ 385, 385, 359, 342, 385, 385, 115, 385, 129, 357,
+ 385, 0, 385, 111, 128, 385, 385, 385, 356, 121,
+ 152, 385, 70, 0, 385, 385, 385, 385, 385, 0,
+ 385, 310, 307, 315, 312, 300, 300, 297, 303, 302,
+
+ 298, 309, 0, 304, 291, 296, 306, 302, 0, 287,
+ 283, 300, 278, 282, 281, 283, 281, 385, 385, 385,
+ 385, 385, 145, 113, 130, 200, 202, 218, 148, 286,
+ 279, 0, 286, 289, 279, 287, 274, 272, 277, 0,
+ 274, 0, 272, 282, 280, 275, 0, 265, 277, 265,
+ 275, 266, 0, 146, 284, 283, 102, 148, 210, 0,
+ 258, 262, 0, 258, 257, 267, 266, 0, 0, 0,
+ 0, 0, 256, 257, 247, 253, 242, 270, 153, 160,
+ 211, 212, 213, 214, 209, 0, 199, 195, 196, 189,
+ 194, 194, 185, 385, 200, 198, 151, 162, 148, 0,
+
+ 134, 132, 135, 0, 129, 111, 214, 90, 0, 0,
+ 0, 0, 0, 0, 86, 0, 385, 256, 261, 266,
+ 271, 274, 279, 281, 97, 286, 70, 291, 296, 301
+ } ;
+
+static yyconst flex_int16_t yy_def[231] =
+ { 0,
+ 217, 1, 218, 218, 219, 219, 217, 217, 217, 217,
+ 217, 217, 220, 221, 222, 217, 217, 223, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 224, 217, 217, 217, 224, 224, 224,
+ 224, 224, 38, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 38, 224, 217, 217, 217, 217, 225, 217,
+ 217, 217, 217, 217, 217, 217, 220, 217, 220, 221,
+ 217, 222, 217, 226, 226, 217, 217, 217, 221, 217,
+ 217, 217, 217, 227, 217, 217, 217, 217, 217, 224,
+ 217, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 217, 217, 217,
+ 217, 217, 220, 228, 228, 228, 228, 217, 227, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 220, 229, 229, 229, 229, 230, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 217, 217, 217,
+ 228, 228, 228, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 217, 217, 229, 229, 224, 224, 224,
+
+ 224, 224, 224, 224, 224, 224, 228, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 0, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217
+ } ;
+
+static yyconst flex_int16_t yy_nxt[451] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 28, 29, 30, 31, 32, 33, 8, 34, 34,
+ 34, 34, 34, 34, 35, 36, 37, 34, 38, 39,
+ 40, 41, 42, 34, 43, 44, 45, 46, 47, 48,
+ 49, 34, 50, 51, 52, 34, 34, 53, 34, 54,
+ 34, 55, 56, 57, 58, 9, 10, 11, 62, 10,
+ 63, 68, 78, 129, 62, 10, 63, 79, 92, 80,
+ 64, 85, 86, 59, 59, 59, 64, 88, 89, 128,
+ 128, 93, 59, 59, 59, 80, 69, 81, 81, 81,
+
+ 120, 59, 59, 59, 59, 59, 59, 96, 94, 82,
+ 95, 99, 97, 81, 81, 81, 83, 103, 98, 100,
+ 68, 125, 80, 156, 104, 82, 101, 60, 9, 10,
+ 11, 105, 179, 112, 68, 180, 84, 113, 125, 216,
+ 156, 126, 114, 157, 215, 69, 59, 59, 59, 80,
+ 68, 68, 82, 80, 214, 59, 59, 59, 126, 69,
+ 157, 127, 123, 194, 59, 59, 59, 59, 59, 59,
+ 194, 81, 81, 81, 154, 69, 69, 181, 179, 82,
+ 207, 179, 213, 82, 212, 211, 195, 210, 209, 155,
+ 60, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 156, 208, 156, 91, 91, 91, 91, 91, 91, 80,
+ 182, 196, 196, 196, 196, 91, 91, 91, 179, 178,
+ 157, 159, 157, 158, 206, 205, 204, 128, 128, 203,
+ 183, 157, 157, 157, 157, 202, 197, 201, 200, 82,
+ 199, 198, 91, 91, 91, 91, 8, 8, 8, 8,
+ 8, 61, 61, 61, 61, 61, 67, 67, 67, 67,
+ 67, 70, 70, 70, 70, 70, 72, 72, 72, 74,
+ 194, 74, 74, 74, 90, 90, 124, 193, 124, 124,
+ 124, 155, 192, 155, 155, 155, 178, 191, 178, 178,
+
+ 178, 181, 190, 181, 181, 181, 189, 188, 109, 187,
+ 186, 185, 184, 179, 179, 177, 153, 176, 175, 174,
+ 173, 172, 171, 170, 169, 168, 167, 166, 165, 164,
+ 163, 162, 161, 160, 153, 152, 151, 150, 149, 148,
+ 147, 146, 145, 144, 143, 142, 141, 140, 139, 138,
+ 137, 136, 135, 134, 133, 132, 131, 130, 71, 71,
+ 122, 65, 121, 119, 118, 117, 116, 115, 111, 110,
+ 109, 108, 107, 106, 102, 87, 77, 76, 75, 73,
+ 71, 66, 65, 217, 7, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217
+ } ;
+
+static yyconst flex_int16_t yy_chk[451] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 3, 3, 5, 5,
+ 5, 13, 26, 227, 6, 6, 6, 26, 39, 27,
+ 5, 31, 31, 3, 3, 3, 6, 33, 33, 83,
+ 83, 39, 3, 3, 3, 28, 13, 27, 27, 27,
+
+ 225, 3, 3, 3, 3, 3, 3, 41, 40, 27,
+ 40, 42, 41, 28, 28, 28, 27, 44, 41, 42,
+ 67, 74, 80, 124, 44, 28, 42, 3, 4, 4,
+ 4, 44, 157, 51, 69, 157, 27, 51, 75, 215,
+ 125, 74, 51, 124, 208, 67, 4, 4, 4, 129,
+ 123, 154, 80, 81, 206, 4, 4, 4, 75, 69,
+ 125, 75, 69, 179, 4, 4, 4, 4, 4, 4,
+ 180, 81, 81, 81, 123, 123, 154, 158, 158, 129,
+ 197, 197, 205, 81, 203, 202, 179, 201, 199, 180,
+ 4, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+
+ 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+ 126, 198, 127, 38, 38, 38, 38, 38, 38, 128,
+ 159, 181, 182, 183, 207, 38, 38, 38, 196, 195,
+ 126, 127, 127, 126, 193, 192, 191, 128, 128, 190,
+ 159, 181, 182, 183, 207, 189, 183, 188, 187, 128,
+ 185, 184, 38, 38, 38, 38, 218, 218, 218, 218,
+ 218, 219, 219, 219, 219, 219, 220, 220, 220, 220,
+ 220, 221, 221, 221, 221, 221, 222, 222, 222, 223,
+ 178, 223, 223, 223, 224, 224, 226, 177, 226, 226,
+ 226, 228, 176, 228, 228, 228, 229, 175, 229, 229,
+
+ 229, 230, 174, 230, 230, 230, 173, 167, 166, 165,
+ 164, 162, 161, 156, 155, 152, 151, 150, 149, 148,
+ 146, 145, 144, 143, 141, 139, 138, 137, 136, 135,
+ 134, 133, 131, 130, 117, 116, 115, 114, 113, 112,
+ 111, 110, 108, 107, 106, 105, 104, 102, 101, 100,
+ 99, 98, 97, 96, 95, 94, 93, 92, 79, 70,
+ 64, 63, 60, 56, 55, 54, 53, 52, 50, 49,
+ 48, 47, 46, 45, 43, 32, 25, 21, 18, 17,
+ 14, 12, 11, 7, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217,
+ 217, 217, 217, 217, 217, 217, 217, 217, 217, 217
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[75] =
+ { 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+/* %option prefix="Elftosb" */
+#line 10 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+#include "ElftosbLexer.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <string>
+#include "HexValues.h"
+#include "Value.h"
+
+using namespace elftosb;
+
+//! Always executed before all other actions when a token is matched.
+//! This action just assign the first and last lines of the token to
+//! the current line. In most cases this is correct.
+#define YY_USER_ACTION do { \
+ m_location.m_firstLine = m_line; \
+ m_location.m_lastLine = m_line; \
+ } while (0);
+
+/* start conditions */
+
+#line 628 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_lexer.cpp"
+
+#define INITIAL 0
+#define blob 1
+#define mlcmt 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+#define ECHO LexerOutput( yytext, yyleng )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+\
+ if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+#define YY_DECL int yyFlexLexer::yylex()
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 38 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+
+
+#line 733 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_lexer.cpp"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = & std::cin;
+
+ if ( ! yyout )
+ yyout = & std::cout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 218 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 217 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ yylineno++;
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 40 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_OPTIONS; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 41 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_CONSTANTS; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 42 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_SOURCES; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 43 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_FILTERS; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 44 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_SECTION; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 45 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_EXTERN; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 46 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_FROM; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 47 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_RAW; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 48 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_LOAD; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 49 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_JUMP; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 50 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_CALL; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 51 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_MODE; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 52 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_IF; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 53 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_ELSE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 54 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_DEFINED; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 55 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_INFO; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 56 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_WARNING; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 57 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_ERROR; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 58 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_SIZEOF; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 59 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_DCD; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 60 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_HAB; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 61 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_IVT; }
+ YY_BREAK
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 63 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ // must be followed by any non-ident char
+ int_size_t theSize;
+ switch (yytext[0])
+ {
+ case 'w':
+ theSize = kWordSize;
+ break;
+ case 'h':
+ theSize = kHalfWordSize;
+ break;
+ case 'b':
+ theSize = kByteSize;
+ break;
+ }
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, theSize);
+ return TOK_INT_SIZE;
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 81 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(1, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 86 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 91 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ m_symbolValue.m_str = new std::string(yytext);
+ if (isSourceName(m_symbolValue.m_str))
+ {
+ return TOK_SOURCE_NAME;
+ }
+ else
+ {
+ return TOK_IDENT;
+ }
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 103 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ int base = 0;
+ uint32_t value;
+ int mult;
+
+ // check for binary number
+ if (yytext[0] == '0' && yytext[1] == 'b')
+ {
+ base = 2; // this is a binary number
+ yytext += 2; // skip over the "0b"
+ }
+
+ // convert value
+ value = (uint32_t)strtoul(yytext, NULL, base);
+
+ // find multiplier
+ switch (yytext[strlen(yytext) - 1])
+ {
+ case 'G':
+ mult = 1024 * 1024 * 1024;
+ break;
+ case 'M':
+ mult = 1024 * 1024;
+ break;
+ case 'K':
+ mult = 1024;
+ break;
+ default:
+ mult = 1;
+ break;
+ }
+
+ // set resulting symbol value
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(value * mult, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 140 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ uint32_t value = 0;
+ int_size_t theSize;
+ int len = strlen(yytext);
+ if (len >= 3)
+ {
+ value = yytext[1];
+ theSize = kByteSize;
+ }
+ if (len >= 4)
+ {
+ value = (value << 8) | yytext[2];
+ theSize = kHalfWordSize;
+ }
+ if (len >= 6)
+ {
+ value = (value << 8) | yytext[3];
+ value = (value << 8) | yytext[4];
+ theSize = kWordSize;
+ }
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(value, theSize);
+ return TOK_INT_LITERAL;
+ }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 164 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ // remove $ from string
+ m_symbolValue.m_str = new std::string(&yytext[1]);
+ return TOK_SECTION_NAME;
+ }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 171 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ BEGIN(mlcmt); }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 173 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ m_blob = new Blob();
+ m_blobFirstLine = yylineno;
+ BEGIN(blob);
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 179 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '{'; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 181 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '}'; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 183 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '('; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 185 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return ')'; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 187 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '['; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 189 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return ']'; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 191 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '='; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 193 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return ','; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 195 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return ':'; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 197 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return ';'; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 199 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '.'; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 201 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '>'; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 203 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_DOT_DOT; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 205 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '+'; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 207 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '-'; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 209 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '*'; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 211 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '/'; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 213 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '%'; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 215 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '~'; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 217 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '^'; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 219 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_LSHIFT; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 221 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_RSHIFT; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 223 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '&'; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 225 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '|'; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 227 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_POWER; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 229 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '<'; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 231 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_GEQ; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 233 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_LEQ; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 235 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_EQ; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 237 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_NEQ; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 239 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_AND; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 241 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return TOK_OR; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 243 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{ return '!'; }
+ YY_BREAK
+case 65:
+/* rule 65 can match eol */
+YY_RULE_SETUP
+#line 245 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ // get rid of quotes
+ yytext++;
+ yytext[strlen(yytext) - 1] = 0;
+// processStringEscapes(yytext, yytext);
+ m_symbolValue.m_str = new std::string(yytext);
+ return TOK_STRING_LITERAL;
+ }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 254 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ uint8_t x = (hexCharToInt(yytext[0]) << 4) | hexCharToInt(yytext[1]);
+ m_blob->append(&x, 1);
+ }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 259 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ BEGIN(INITIAL);
+ m_symbolValue.m_blob = m_blob;
+ m_blob = NULL;
+ m_location.m_firstLine = m_blobFirstLine;
+ return TOK_BLOB;
+ }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 267 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ // end of multi-line comment, return to initial state
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+case 69:
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 273 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+/* absorb single-line comment */
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 275 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+/* eat up whitespace in all states */
+ YY_BREAK
+case 71:
+/* rule 71 can match eol */
+YY_RULE_SETUP
+#line 277 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ /* eat up whitespace and count lines in all states */
+ m_line++;
+ }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 282 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+/* ignore all other chars in a multi-line comment */
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 284 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+{
+ /* all other chars produce errors */
+ char msg[50];
+ sprintf(msg, "unexpected character '%c' on line %d", yytext[0], m_line);
+ LexerError(msg);
+ }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 291 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+ECHO;
+ YY_BREAK
+#line 1325 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_lexer.cpp"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(blob):
+case YY_STATE_EOF(mlcmt):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* The contents of this function are C++ specific, so the () macro is not used.
+ */
+yyFlexLexer::yyFlexLexer( std::istream* arg_yyin, std::ostream* arg_yyout )
+{
+ yyin = arg_yyin;
+ yyout = arg_yyout;
+ yy_c_buf_p = 0;
+ yy_init = 0;
+ yy_start = 0;
+ yy_flex_debug = 0;
+ yylineno = 1; // this will only get updated if %option yylineno
+
+ yy_did_buffer_switch_on_eof = 0;
+
+ yy_looking_for_trail_begin = 0;
+ yy_more_flag = 0;
+ yy_more_len = 0;
+ yy_more_offset = yy_prev_more_offset = 0;
+
+ yy_start_stack_ptr = yy_start_stack_depth = 0;
+ yy_start_stack = NULL;
+
+ yy_buffer_stack = 0;
+ yy_buffer_stack_top = 0;
+ yy_buffer_stack_max = 0;
+
+ yy_state_buf = 0;
+
+}
+
+/* The contents of this function are C++ specific, so the () macro is not used.
+ */
+yyFlexLexer::~yyFlexLexer()
+{
+ delete [] yy_state_buf;
+ yyfree(yy_start_stack );
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yyfree(yy_buffer_stack );
+}
+
+/* The contents of this function are C++ specific, so the () macro is not used.
+ */
+void yyFlexLexer::switch_streams( std::istream* new_in, std::ostream* new_out )
+{
+ if ( new_in )
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+ }
+
+ if ( new_out )
+ yyout = new_out;
+}
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+{
+ if ( yyin->eof() || yyin->fail() )
+ return 0;
+
+#ifdef YY_INTERACTIVE
+ yyin->get( buf[0] );
+
+ if ( yyin->eof() )
+ return 0;
+
+ if ( yyin->bad() )
+ return -1;
+
+ return 1;
+
+#else
+ (void) yyin->read( buf, max_size );
+
+ if ( yyin->bad() )
+ return -1;
+ else
+ return yyin->gcount();
+#endif
+}
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+{
+ (void) yyout->write( buf, size );
+}
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+int yyFlexLexer::yy_get_next_buffer()
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ yy_state_type yyFlexLexer::yy_get_previous_state()
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 218 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 218 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 217);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ void yyFlexLexer::yyunput( int c, register char* yy_bp)
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register yy_size_t number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' ){
+ --yylineno;
+ }
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+ int yyFlexLexer::yyinput()
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return 0;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ if ( c == '\n' )
+
+ yylineno++;
+;
+
+ return c;
+}
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyFlexLexer::yyrestart( std::istream* input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+ void yyFlexLexer::yy_load_buffer_state()
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( std::istream* file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, std::istream* file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yyFlexLexer::yypush_buffer_state (YY_BUFFER_STATE new_buffer)
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yyFlexLexer::yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+void yyFlexLexer::yyensure_buffer_stack(void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+ void yyFlexLexer::yy_push_state( int new_state )
+{
+ if ( (yy_start_stack_ptr) >= (yy_start_stack_depth) )
+ {
+ yy_size_t new_size;
+
+ (yy_start_stack_depth) += YY_START_STACK_INCR;
+ new_size = (yy_start_stack_depth) * sizeof( int );
+
+ if ( ! (yy_start_stack) )
+ (yy_start_stack) = (int *) yyalloc(new_size );
+
+ else
+ (yy_start_stack) = (int *) yyrealloc((void *) (yy_start_stack),new_size );
+
+ if ( ! (yy_start_stack) )
+ YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+ }
+
+ (yy_start_stack)[(yy_start_stack_ptr)++] = YY_START;
+
+ BEGIN(new_state);
+}
+
+ void yyFlexLexer::yy_pop_state()
+{
+ if ( --(yy_start_stack_ptr) < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN((yy_start_stack)[(yy_start_stack_ptr)]);
+}
+
+ int yyFlexLexer::yy_top_state()
+{
+ return (yy_start_stack)[(yy_start_stack_ptr) - 1];
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+{
+ std::cerr << msg << std::endl;
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 291 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_lexer.l"
+
+
+
+// verbatim code copied to the bottom of the output
+
+
+
diff --git a/elftosb2/elftosb_lexer.l b/elftosb2/elftosb_lexer.l
new file mode 100644
index 0000000..23272b7
--- /dev/null
+++ b/elftosb2/elftosb_lexer.l
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+%option c++
+/* %option prefix="Elftosb" */
+%option yylineno
+%option never-interactive
+%option yyclass="ElftosbLexer"
+%option noyywrap
+
+%{
+#include "ElftosbLexer.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <string>
+#include "HexValues.h"
+#include "Value.h"
+
+using namespace elftosb;
+
+//! Always executed before all other actions when a token is matched.
+//! This action just assign the first and last lines of the token to
+//! the current line. In most cases this is correct.
+#define YY_USER_ACTION do { \
+ m_location.m_firstLine = m_line; \
+ m_location.m_lastLine = m_line; \
+ } while (0);
+
+%}
+
+DIGIT [0-9]
+HEXDIGIT [0-9a-fA-F]
+BINDIGIT [0-1]
+IDENT [a-zA-Z_][a-zA-Z0-9_]*
+ESC \\(x{HEXDIGIT}{2}|.)
+
+/* start conditions */
+%x blob mlcmt
+
+%%
+
+options { return TOK_OPTIONS; }
+constants { return TOK_CONSTANTS; }
+sources { return TOK_SOURCES; }
+filters { return TOK_FILTERS; }
+section { return TOK_SECTION; }
+extern { return TOK_EXTERN; }
+from { return TOK_FROM; }
+raw { return TOK_RAW; }
+load { return TOK_LOAD; }
+jump { return TOK_JUMP; }
+call { return TOK_CALL; }
+mode { return TOK_MODE; }
+if { return TOK_IF; }
+else { return TOK_ELSE; }
+defined { return TOK_DEFINED; }
+info { return TOK_INFO; }
+warning { return TOK_WARNING; }
+error { return TOK_ERROR; }
+sizeof { return TOK_SIZEOF; }
+dcd { return TOK_DCD; }
+hab { return TOK_HAB; }
+ivt { return TOK_IVT; }
+
+[whb]/[^a-zA-Z_0-9] { // must be followed by any non-ident char
+ int_size_t theSize;
+ switch (yytext[0])
+ {
+ case 'w':
+ theSize = kWordSize;
+ break;
+ case 'h':
+ theSize = kHalfWordSize;
+ break;
+ case 'b':
+ theSize = kByteSize;
+ break;
+ }
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, theSize);
+ return TOK_INT_SIZE;
+ }
+
+true|yes {
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(1, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+
+false|no {
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+
+{IDENT} {
+ m_symbolValue.m_str = new std::string(yytext);
+ if (isSourceName(m_symbolValue.m_str))
+ {
+ return TOK_SOURCE_NAME;
+ }
+ else
+ {
+ return TOK_IDENT;
+ }
+ }
+
+({DIGIT}+|0x{HEXDIGIT}+|0b{BINDIGIT}+)([ \t]*[GMK])? {
+ int base = 0;
+ uint32_t value;
+ int mult;
+
+ // check for binary number
+ if (yytext[0] == '0' && yytext[1] == 'b')
+ {
+ base = 2; // this is a binary number
+ yytext += 2; // skip over the "0b"
+ }
+
+ // convert value
+ value = (uint32_t)strtoul(yytext, NULL, base);
+
+ // find multiplier
+ switch (yytext[strlen(yytext) - 1])
+ {
+ case 'G':
+ mult = 1024 * 1024 * 1024;
+ break;
+ case 'M':
+ mult = 1024 * 1024;
+ break;
+ case 'K':
+ mult = 1024;
+ break;
+ default:
+ mult = 1;
+ break;
+ }
+
+ // set resulting symbol value
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(value * mult, kWordSize);
+ return TOK_INT_LITERAL;
+ }
+
+\'(.|ESC)\'|\'(.|ESC){2}\'|\'(.|ESC){4}\' {
+ uint32_t value = 0;
+ int_size_t theSize;
+ int len = strlen(yytext);
+ if (len >= 3)
+ {
+ value = yytext[1];
+ theSize = kByteSize;
+ }
+ if (len >= 4)
+ {
+ value = (value << 8) | yytext[2];
+ theSize = kHalfWordSize;
+ }
+ if (len >= 6)
+ {
+ value = (value << 8) | yytext[3];
+ value = (value << 8) | yytext[4];
+ theSize = kWordSize;
+ }
+ m_symbolValue.m_int = new elftosb::SizedIntegerValue(value, theSize);
+ return TOK_INT_LITERAL;
+ }
+
+\$[\.\*a-zA-Z0-9_\[\]\^\?\-]+ {
+ // remove $ from string
+ m_symbolValue.m_str = new std::string(&yytext[1]);
+ return TOK_SECTION_NAME;
+ }
+
+
+"/*" { BEGIN(mlcmt); }
+
+"{{" {
+ m_blob = new Blob();
+ m_blobFirstLine = yylineno;
+ BEGIN(blob);
+ }
+
+"{" { return '{'; }
+
+"}" { return '}'; }
+
+"(" { return '('; }
+
+")" { return ')'; }
+
+"[" { return '['; }
+
+"]" { return ']'; }
+
+"=" { return '='; }
+
+"," { return ','; }
+
+":" { return ':'; }
+
+";" { return ';'; }
+
+"." { return '.'; }
+
+">" { return '>'; }
+
+".." { return TOK_DOT_DOT; }
+
+"+" { return '+'; }
+
+"-" { return '-'; }
+
+"*" { return '*'; }
+
+"/" { return '/'; }
+
+"%" { return '%'; }
+
+"~" { return '~'; }
+
+"^" { return '^'; }
+
+"<<" { return TOK_LSHIFT; }
+
+">>" { return TOK_RSHIFT; }
+
+"&" { return '&'; }
+
+"|" { return '|'; }
+
+"**" { return TOK_POWER; }
+
+"<" { return '<'; }
+
+">=" { return TOK_GEQ; }
+
+"<=" { return TOK_LEQ; }
+
+"==" { return TOK_EQ; }
+
+"!=" { return TOK_NEQ; }
+
+"&&" { return TOK_AND; }
+
+"||" { return TOK_OR; }
+
+"!" { return '!'; }
+
+\"(ESC|[^\"])*\" {
+ // get rid of quotes
+ yytext++;
+ yytext[strlen(yytext) - 1] = 0;
+// processStringEscapes(yytext, yytext);
+ m_symbolValue.m_str = new std::string(yytext);
+ return TOK_STRING_LITERAL;
+ }
+
+<blob>{HEXDIGIT}{2} {
+ uint8_t x = (hexCharToInt(yytext[0]) << 4) | hexCharToInt(yytext[1]);
+ m_blob->append(&x, 1);
+ }
+
+<blob>"}}" {
+ BEGIN(INITIAL);
+ m_symbolValue.m_blob = m_blob;
+ m_blob = NULL;
+ m_location.m_firstLine = m_blobFirstLine;
+ return TOK_BLOB;
+ }
+
+<mlcmt>\*\/ {
+ // end of multi-line comment, return to initial state
+ BEGIN(INITIAL);
+ }
+
+
+(#|\/\/).*$ /* absorb single-line comment */
+
+<*>[ \t] /* eat up whitespace in all states */
+
+<*>(\r\n|\r|\n) {
+ /* eat up whitespace and count lines in all states */
+ m_line++;
+ }
+
+<mlcmt>. /* ignore all other chars in a multi-line comment */
+
+<*>. {
+ /* all other chars produce errors */
+ char msg[50];
+ sprintf(msg, "unexpected character '%c' on line %d", yytext[0], m_line);
+ LexerError(msg);
+ }
+
+%%
+
+// verbatim code copied to the bottom of the output
+
+
diff --git a/elftosb2/elftosb_parser.tab.cpp b/elftosb2/elftosb_parser.tab.cpp
new file mode 100644
index 0000000..731ca45
--- /dev/null
+++ b/elftosb2/elftosb_parser.tab.cpp
@@ -0,0 +1,2955 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 1
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_IDENT = 258,
+ TOK_STRING_LITERAL = 259,
+ TOK_INT_LITERAL = 260,
+ TOK_SECTION_NAME = 261,
+ TOK_SOURCE_NAME = 262,
+ TOK_BLOB = 263,
+ TOK_DOT_DOT = 264,
+ TOK_AND = 265,
+ TOK_OR = 266,
+ TOK_GEQ = 267,
+ TOK_LEQ = 268,
+ TOK_EQ = 269,
+ TOK_NEQ = 270,
+ TOK_POWER = 271,
+ TOK_LSHIFT = 272,
+ TOK_RSHIFT = 273,
+ TOK_INT_SIZE = 274,
+ TOK_OPTIONS = 275,
+ TOK_CONSTANTS = 276,
+ TOK_SOURCES = 277,
+ TOK_FILTERS = 278,
+ TOK_SECTION = 279,
+ TOK_EXTERN = 280,
+ TOK_FROM = 281,
+ TOK_RAW = 282,
+ TOK_LOAD = 283,
+ TOK_JUMP = 284,
+ TOK_CALL = 285,
+ TOK_MODE = 286,
+ TOK_IF = 287,
+ TOK_ELSE = 288,
+ TOK_DEFINED = 289,
+ TOK_INFO = 290,
+ TOK_WARNING = 291,
+ TOK_ERROR = 292,
+ TOK_SIZEOF = 293,
+ TOK_DCD = 294,
+ TOK_HAB = 295,
+ TOK_IVT = 296,
+ UNARY_OP = 297
+ };
+#endif
+/* Tokens. */
+#define TOK_IDENT 258
+#define TOK_STRING_LITERAL 259
+#define TOK_INT_LITERAL 260
+#define TOK_SECTION_NAME 261
+#define TOK_SOURCE_NAME 262
+#define TOK_BLOB 263
+#define TOK_DOT_DOT 264
+#define TOK_AND 265
+#define TOK_OR 266
+#define TOK_GEQ 267
+#define TOK_LEQ 268
+#define TOK_EQ 269
+#define TOK_NEQ 270
+#define TOK_POWER 271
+#define TOK_LSHIFT 272
+#define TOK_RSHIFT 273
+#define TOK_INT_SIZE 274
+#define TOK_OPTIONS 275
+#define TOK_CONSTANTS 276
+#define TOK_SOURCES 277
+#define TOK_FILTERS 278
+#define TOK_SECTION 279
+#define TOK_EXTERN 280
+#define TOK_FROM 281
+#define TOK_RAW 282
+#define TOK_LOAD 283
+#define TOK_JUMP 284
+#define TOK_CALL 285
+#define TOK_MODE 286
+#define TOK_IF 287
+#define TOK_ELSE 288
+#define TOK_DEFINED 289
+#define TOK_INFO 290
+#define TOK_WARNING 291
+#define TOK_ERROR 292
+#define TOK_SIZEOF 293
+#define TOK_DCD 294
+#define TOK_HAB 295
+#define TOK_IVT 296
+#define UNARY_OP 297
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 14 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+
+#include "ElftosbLexer.h"
+#include "ElftosbAST.h"
+#include "Logging.h"
+#include "Blob.h"
+#include "format_string.h"
+#include "Value.h"
+#include "ConversionController.h"
+
+using namespace elftosb;
+
+//! Our special location type.
+#define YYLTYPE token_loc_t
+
+// this indicates that we're using our own type. it should be unset automatically
+// but that's not working for some reason with the .hpp file.
+#if defined(YYLTYPE_IS_TRIVIAL)
+ #undef YYLTYPE_IS_TRIVIAL
+ #define YYLTYPE_IS_TRIVIAL 0
+#endif
+
+//! Default location action
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) \
+ { \
+ (Current).m_firstLine = YYRHSLOC(Rhs, 1).m_firstLine; \
+ (Current).m_lastLine = YYRHSLOC(Rhs, N).m_lastLine; \
+ } \
+ else \
+ { \
+ (Current).m_firstLine = (Current).m_lastLine = YYRHSLOC(Rhs, 0).m_lastLine; \
+ } \
+ } while (0)
+
+//! Forward declaration of yylex().
+static int yylex(YYSTYPE * lvalp, YYLTYPE * yylloc, ElftosbLexer * lexer);
+
+// Forward declaration of error handling function.
+static void yyerror(YYLTYPE * yylloc, ElftosbLexer * lexer, CommandFileASTNode ** resultAST, const char * error);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 58 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+typedef union YYSTYPE {
+ int m_num;
+ elftosb::SizedIntegerValue * m_int;
+ Blob * m_blob;
+ std::string * m_str;
+ elftosb::ASTNode * m_ast; // must use full name here because this is put into *.tab.hpp
+} YYSTYPE;
+/* Line 196 of yacc.c. */
+#line 220 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined (YYLTYPE) && ! defined (YYLTYPE_IS_DECLARED)
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 219 of yacc.c. */
+#line 244 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYINCLUDED_STDLIB_H
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifdef __cplusplus
+}
+# endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYLTYPE_IS_TRIVIAL) && YYLTYPE_IS_TRIVIAL \
+ && defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 13
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 418
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 66
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 52
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 133
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 238
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 297
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 26, 2, 2, 2, 64, 23, 2,
+ 9, 10, 62, 60, 16, 61, 20, 63, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 18, 17,
+ 25, 15, 19, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 13, 2, 14, 59, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 11, 24, 12, 22, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 21, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 65
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short int yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 11, 13, 15, 17, 22,
+ 27, 29, 32, 35, 36, 40, 45, 47, 50, 54,
+ 55, 59, 66, 70, 71, 73, 77, 81, 83, 86,
+ 93, 96, 97, 99, 100, 104, 108, 110, 113, 116,
+ 118, 120, 121, 123, 126, 129, 131, 132, 134, 136,
+ 138, 140, 145, 147, 148, 150, 152, 154, 156, 160,
+ 165, 167, 169, 171, 175, 177, 180, 183, 184, 186,
+ 188, 193, 195, 196, 200, 205, 207, 209, 211, 213,
+ 217, 220, 221, 227, 230, 233, 236, 239, 246, 251,
+ 254, 255, 257, 261, 263, 265, 267, 271, 275, 279,
+ 283, 287, 291, 295, 299, 302, 307, 311, 316, 318,
+ 322, 325, 327, 329, 331, 335, 339, 343, 347, 351,
+ 355, 359, 363, 367, 371, 375, 377, 381, 385, 390,
+ 395, 400, 403, 406
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 67, 0, -1, 68, 82, -1, 69, -1, 68, 69,
+ -1, 70, -1, 71, -1, 75, -1, 37, 11, 72,
+ 12, -1, 38, 11, 72, 12, -1, 73, -1, 72,
+ 73, -1, 74, 17, -1, -1, 3, 15, 111, -1,
+ 39, 11, 76, 12, -1, 77, -1, 76, 77, -1,
+ 78, 79, 17, -1, -1, 3, 15, 4, -1, 3,
+ 15, 42, 9, 113, 10, -1, 9, 80, 10, -1,
+ -1, 81, -1, 80, 16, 81, -1, 3, 15, 111,
+ -1, 83, -1, 82, 83, -1, 41, 9, 113, 84,
+ 10, 86, -1, 17, 85, -1, -1, 80, -1, -1,
+ 30, 94, 17, -1, 11, 87, 12, -1, 88, -1,
+ 87, 88, -1, 91, 17, -1, 105, -1, 108, -1,
+ -1, 90, -1, 89, 90, -1, 91, 17, -1, 108,
+ -1, -1, 92, -1, 101, -1, 106, -1, 107, -1,
+ 45, 93, 94, 97, -1, 56, -1, -1, 113, -1,
+ 4, -1, 7, -1, 95, -1, 95, 43, 7, -1,
+ 7, 13, 95, 14, -1, 8, -1, 99, -1, 96,
+ -1, 95, 16, 96, -1, 6, -1, 22, 6, -1,
+ 19, 98, -1, -1, 20, -1, 110, -1, 58, 9,
+ 100, 10, -1, 80, -1, -1, 102, 103, 104, -1,
+ 57, 102, 110, 104, -1, 47, -1, 46, -1, 7,
+ -1, 113, -1, 9, 113, 10, -1, 9, 10, -1,
+ -1, 43, 7, 11, 89, 12, -1, 48, 113, -1,
+ 52, 4, -1, 53, 4, -1, 54, 4, -1, 49,
+ 112, 11, 87, 12, 109, -1, 50, 11, 87, 12,
+ -1, 50, 108, -1, -1, 113, -1, 113, 21, 113,
+ -1, 112, -1, 4, -1, 113, -1, 112, 25, 112,
+ -1, 112, 19, 112, -1, 112, 29, 112, -1, 112,
+ 30, 112, -1, 112, 31, 112, -1, 112, 32, 112,
+ -1, 112, 27, 112, -1, 112, 28, 112, -1, 26,
+ 112, -1, 3, 9, 7, 10, -1, 9, 112, 10,
+ -1, 51, 9, 3, 10, -1, 115, -1, 7, 18,
+ 3, -1, 18, 3, -1, 117, -1, 3, -1, 114,
+ -1, 115, 60, 115, -1, 115, 61, 115, -1, 115,
+ 62, 115, -1, 115, 63, 115, -1, 115, 64, 115,
+ -1, 115, 33, 115, -1, 115, 23, 115, -1, 115,
+ 24, 115, -1, 115, 59, 115, -1, 115, 34, 115,
+ -1, 115, 35, 115, -1, 116, -1, 115, 20, 36,
+ -1, 9, 115, 10, -1, 55, 9, 114, 10, -1,
+ 55, 9, 3, 10, -1, 55, 9, 7, 10, -1,
+ 60, 115, -1, 61, 115, -1, 5, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short int yyrline[] =
+{
+ 0, 162, 162, 172, 178, 186, 187, 188, 191, 197,
+ 203, 209, 216, 217, 220, 227, 233, 239, 247, 259,
+ 262, 267, 275, 276, 280, 286, 294, 301, 307, 314,
+ 329, 334, 340, 345, 351, 357, 365, 371, 379, 380,
+ 381, 382, 385, 391, 399, 400, 401, 404, 405, 406,
+ 407, 410, 433, 443, 445, 449, 454, 459, 464, 469,
+ 474, 479, 484, 490, 498, 503, 510, 515, 521, 526,
+ 532, 544, 545, 548, 577, 614, 615, 618, 623, 630,
+ 631, 632, 635, 642, 649, 654, 659, 666, 677, 681,
+ 688, 691, 696, 703, 707, 714, 718, 725, 732, 739,
+ 746, 753, 760, 767, 774, 779, 784, 789, 796, 799,
+ 804, 812, 816, 821, 832, 839, 846, 853, 860, 867,
+ 874, 881, 888, 895, 902, 909, 913, 918, 923, 928,
+ 933, 940, 944, 951
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "\"identifier\"", "\"string\"",
+ "\"integer\"", "\"section name\"", "\"source name\"",
+ "\"binary object\"", "'('", "')'", "'{'", "'}'", "'['", "']'", "'='",
+ "','", "';'", "':'", "'>'", "'.'", "\"..\"", "'~'", "'&'", "'|'", "'<'",
+ "'!'", "\"&&\"", "\"||\"", "\">=\"", "\"<=\"", "\"==\"", "\"!=\"",
+ "\"**\"", "\"<<\"", "\">>\"", "\"integer size\"", "\"options\"",
+ "\"constants\"", "\"sources\"", "\"filters\"", "\"section\"",
+ "\"extern\"", "\"from\"", "\"raw\"", "\"load\"", "\"jump\"", "\"call\"",
+ "\"mode\"", "\"if\"", "\"else\"", "\"defined\"", "\"info\"",
+ "\"warning\"", "\"error\"", "\"sizeof\"", "\"dcd\"", "\"hab\"",
+ "\"ivt\"", "'^'", "'+'", "'-'", "'*'", "'/'", "'%'", "UNARY_OP",
+ "$accept", "command_file", "blocks_list", "pre_section_block",
+ "options_block", "constants_block", "const_def_list",
+ "const_def_list_elem", "const_def", "sources_block", "source_def_list",
+ "source_def_list_elem", "source_def", "source_attrs_opt",
+ "source_attr_list", "source_attr_list_elem", "section_defs",
+ "section_def", "section_options_opt", "source_attr_list_opt",
+ "section_contents", "full_stmt_list", "full_stmt_list_elem",
+ "basic_stmt_list", "basic_stmt_list_elem", "basic_stmt", "load_stmt",
+ "dcd_opt", "load_data", "section_list", "section_list_elem",
+ "load_target_opt", "load_target", "ivt_def", "assignment_list_opt",
+ "call_stmt", "call_or_jump", "call_target", "call_arg_opt", "from_stmt",
+ "mode_stmt", "message_stmt", "if_stmt", "else_opt", "address_or_range",
+ "const_expr", "bool_expr", "int_const_expr", "symbol_ref", "expr",
+ "unary_expr", "int_value", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 40,
+ 41, 123, 125, 91, 93, 61, 44, 59, 58, 62,
+ 46, 264, 126, 38, 124, 60, 33, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, 94,
+ 43, 45, 42, 47, 37, 297
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 66, 67, 68, 68, 69, 69, 69, 70, 71,
+ 72, 72, 73, 73, 74, 75, 76, 76, 77, 77,
+ 78, 78, 79, 79, 80, 80, 81, 82, 82, 83,
+ 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
+ 88, 88, 89, 89, 90, 90, 90, 91, 91, 91,
+ 91, 92, 93, 93, 94, 94, 94, 94, 94, 94,
+ 94, 94, 95, 95, 96, 96, 97, 97, 98, 98,
+ 99, 100, 100, 101, 101, 102, 102, 103, 103, 104,
+ 104, 104, 105, 106, 107, 107, 107, 108, 109, 109,
+ 109, 110, 110, 111, 111, 112, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 112, 112, 113, 114,
+ 114, 115, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115, 116, 116, 117
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 2, 1, 2, 1, 1, 1, 4, 4,
+ 1, 2, 2, 0, 3, 4, 1, 2, 3, 0,
+ 3, 6, 3, 0, 1, 3, 3, 1, 2, 6,
+ 2, 0, 1, 0, 3, 3, 1, 2, 2, 1,
+ 1, 0, 1, 2, 2, 1, 0, 1, 1, 1,
+ 1, 4, 1, 0, 1, 1, 1, 1, 3, 4,
+ 1, 1, 1, 3, 1, 2, 2, 0, 1, 1,
+ 4, 1, 0, 3, 4, 1, 1, 1, 1, 3,
+ 2, 0, 5, 2, 2, 2, 2, 6, 4, 2,
+ 0, 1, 3, 1, 1, 1, 3, 3, 3, 3,
+ 3, 3, 3, 3, 2, 4, 3, 4, 1, 3,
+ 2, 1, 1, 1, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 1, 3, 3, 4, 4,
+ 4, 2, 2, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 0, 0, 0, 0, 0, 0, 3, 5, 6, 7,
+ 13, 13, 19, 1, 0, 4, 2, 27, 0, 0,
+ 10, 0, 0, 0, 0, 16, 23, 0, 28, 0,
+ 8, 11, 12, 9, 0, 15, 17, 0, 0, 112,
+ 133, 0, 0, 0, 0, 0, 0, 31, 113, 108,
+ 125, 111, 112, 94, 0, 0, 0, 14, 93, 95,
+ 20, 0, 0, 0, 24, 18, 0, 0, 110, 0,
+ 131, 132, 33, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 108, 104,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 22, 0, 109, 127, 0, 0, 0, 32, 30,
+ 0, 126, 120, 121, 119, 123, 124, 122, 114, 115,
+ 116, 117, 118, 0, 106, 0, 97, 96, 102, 103,
+ 98, 99, 100, 101, 0, 26, 25, 129, 130, 128,
+ 41, 0, 29, 105, 107, 21, 0, 53, 76, 75,
+ 0, 0, 0, 0, 0, 0, 0, 36, 0, 47,
+ 48, 0, 39, 49, 50, 40, 55, 64, 56, 60,
+ 0, 0, 0, 57, 62, 61, 54, 0, 52, 0,
+ 83, 0, 84, 85, 86, 0, 35, 37, 38, 77,
+ 81, 78, 0, 65, 72, 34, 0, 0, 46, 67,
+ 41, 81, 91, 0, 73, 0, 71, 0, 63, 58,
+ 0, 42, 0, 45, 0, 51, 0, 74, 0, 80,
+ 0, 59, 70, 82, 43, 44, 68, 66, 69, 90,
+ 92, 79, 0, 87, 41, 89, 0, 88
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+ -1, 4, 5, 6, 7, 8, 19, 20, 21, 9,
+ 24, 25, 26, 38, 63, 64, 16, 17, 73, 109,
+ 142, 156, 157, 210, 211, 158, 159, 179, 172, 173,
+ 174, 215, 227, 175, 207, 160, 161, 190, 204, 162,
+ 163, 164, 165, 233, 201, 57, 58, 59, 48, 49,
+ 50, 51
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -181
+static const short int yypact[] =
+{
+ 128, 17, 25, 48, 69, 123, -181, -181, -181, -181,
+ 96, 96, 101, -181, 80, -181, 68, -181, 112, 85,
+ -181, 115, 89, 114, 91, -181, 124, 30, -181, 47,
+ -181, -181, -181, -181, 11, -181, -181, 134, 125, -181,
+ -181, 133, 30, 140, 144, 30, 30, 153, -181, 225,
+ -181, -181, 148, -181, 61, 61, 162, -181, 359, -181,
+ -181, 164, 159, 22, -181, -181, 172, 121, -181, 9,
+ -181, -181, 134, 168, 143, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 179, 303, 121, -181,
+ 194, 61, 61, 61, 61, 61, 61, 61, 61, 30,
+ 47, -181, 134, -181, -181, 188, 4, 200, 199, -181,
+ 56, -181, 241, 231, 236, 86, 86, 247, 76, 76,
+ 196, 196, 196, 208, -181, 210, -181, -181, 373, 373,
+ -181, -181, -181, -181, 216, -181, -181, -181, -181, -181,
+ 314, 2, -181, -181, -181, -181, 220, 175, -181, -181,
+ 30, 61, 228, 230, 237, 28, 147, -181, 223, -181,
+ -181, 108, -181, -181, -181, -181, -181, -181, 92, -181,
+ 240, 243, 233, 15, -181, -181, -181, 242, -181, 2,
+ -181, 345, -181, -181, -181, 30, -181, -181, -181, 133,
+ 246, -181, 7, -181, 134, -181, 7, 250, 361, 244,
+ 314, 246, 248, 16, -181, 104, 199, 252, -181, -181,
+ 190, -181, 251, -181, 75, -181, 160, -181, 30, -181,
+ 261, -181, -181, -181, -181, -181, -181, -181, -181, 222,
+ -181, -181, 6, -181, 314, -181, 176, -181
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short int yypgoto[] =
+{
+ -181, -181, -181, 268, -181, -181, 266, 106, -181, -181,
+ -181, 254, -181, -181, -70, 177, -181, 267, -181, -181,
+ -181, -151, -155, -181, 107, -180, -181, -181, 127, 122,
+ 129, -181, -181, -181, -181, -181, 163, -181, 118, -181,
+ -181, -181, -21, -181, 109, 221, -51, -27, 257, 270,
+ -181, -181
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 47, 187, 108, 87, 89, 39, 166, 40, 167, 168,
+ 169, 42, 105, 167, 138, 60, 106, 234, 212, 39,
+ 43, 40, 66, 41, 170, 42, 219, 43, 10, 170,
+ 212, 196, 101, 39, 43, 40, 11, 41, 102, 42,
+ 126, 127, 128, 129, 130, 131, 132, 133, 43, 216,
+ 52, 53, 40, 61, 41, 151, 54, 44, 197, 12,
+ 171, 187, 45, 46, 52, 43, 40, 140, 41, 13,
+ 54, 44, 134, 55, 148, 149, 45, 46, 39, 43,
+ 40, 187, 41, 236, 42, 44, 141, 55, 18, 27,
+ 45, 46, 18, 43, 23, 226, 74, 30, 56, 18,
+ 181, 33, 44, 35, 23, 192, 74, 45, 46, 14,
+ 66, 39, 56, 40, 176, 189, 44, 42, 221, 77,
+ 196, 45, 46, 180, 206, 31, 43, 29, 31, 34,
+ 44, 104, 32, 37, 191, 45, 46, 62, 83, 84,
+ 85, 74, 65, 68, 75, 76, 81, 82, 83, 84,
+ 85, 66, 176, 69, 77, 78, 79, 86, 202, 186,
+ 1, 2, 3, 44, 14, 1, 2, 3, 45, 46,
+ 72, 90, 229, 99, 100, 103, 220, 213, 110, 111,
+ 80, 81, 82, 83, 84, 85, 123, 202, 237, 213,
+ 146, 230, 147, 148, 149, 150, 151, 125, 137, 152,
+ 153, 154, 223, 146, 155, 147, 148, 149, 150, 151,
+ 139, 235, 152, 153, 154, 102, 74, 155, 143, 146,
+ 144, 147, 148, 149, 150, 151, 145, 177, 152, 153,
+ 154, 178, 182, 155, 183, 147, 148, 149, 150, 151,
+ 188, 184, 152, 153, 154, 74, 193, 155, 75, 76,
+ 195, 74, 194, 198, 75, 203, 74, 209, 77, 78,
+ 79, 74, 222, 214, 77, 78, 79, 74, 225, 218,
+ 75, 231, 232, 15, 77, 78, 79, 22, 36, 136,
+ 77, 78, 79, 28, 80, 81, 82, 83, 84, 85,
+ 80, 81, 82, 83, 84, 85, 81, 82, 83, 84,
+ 85, 81, 82, 83, 84, 85, 199, 81, 82, 83,
+ 84, 85, 67, 124, 205, 70, 71, 224, 185, 217,
+ 0, 135, 91, 228, 88, 208, 107, 0, 92, 0,
+ 93, 94, 95, 96, 97, 98, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 200, 146, 0, 147,
+ 148, 149, 150, 151, 91, 0, 152, 153, 154, 0,
+ 92, 155, 93, 94, 95, 96, 97, 98, 91, 0,
+ 0, 0, 0, 0, 92, 0, 93, 94, 95, 96,
+ 97, 98, 91, 0, 0, 0, 0, 0, 92, 0,
+ 0, 0, 95, 96, 97, 98, 147, 148, 149, 150,
+ 151, 0, 0, 152, 153, 154, 0, 0, 155
+};
+
+static const short int yycheck[] =
+{
+ 27, 156, 72, 54, 55, 3, 4, 5, 6, 7,
+ 8, 9, 3, 6, 10, 4, 7, 11, 198, 3,
+ 18, 5, 18, 7, 22, 9, 10, 18, 11, 22,
+ 210, 16, 10, 3, 18, 5, 11, 7, 16, 9,
+ 91, 92, 93, 94, 95, 96, 97, 98, 18, 200,
+ 3, 4, 5, 42, 7, 49, 9, 55, 43, 11,
+ 58, 216, 60, 61, 3, 18, 5, 11, 7, 0,
+ 9, 55, 99, 26, 46, 47, 60, 61, 3, 18,
+ 5, 236, 7, 234, 9, 55, 30, 26, 3, 9,
+ 60, 61, 3, 18, 3, 20, 20, 12, 51, 3,
+ 151, 12, 55, 12, 3, 13, 20, 60, 61, 41,
+ 18, 3, 51, 5, 141, 7, 55, 9, 14, 33,
+ 16, 60, 61, 150, 194, 19, 18, 15, 22, 15,
+ 55, 10, 17, 9, 161, 60, 61, 3, 62, 63,
+ 64, 20, 17, 3, 23, 24, 60, 61, 62, 63,
+ 64, 18, 179, 9, 33, 34, 35, 9, 185, 12,
+ 37, 38, 39, 55, 41, 37, 38, 39, 60, 61,
+ 17, 9, 12, 9, 15, 3, 203, 198, 10, 36,
+ 59, 60, 61, 62, 63, 64, 7, 214, 12, 210,
+ 43, 218, 45, 46, 47, 48, 49, 3, 10, 52,
+ 53, 54, 12, 43, 57, 45, 46, 47, 48, 49,
+ 10, 232, 52, 53, 54, 16, 20, 57, 10, 43,
+ 10, 45, 46, 47, 48, 49, 10, 7, 52, 53,
+ 54, 56, 4, 57, 4, 45, 46, 47, 48, 49,
+ 17, 4, 52, 53, 54, 20, 6, 57, 23, 24,
+ 17, 20, 9, 11, 23, 9, 20, 7, 33, 34,
+ 35, 20, 10, 19, 33, 34, 35, 20, 17, 21,
+ 23, 10, 50, 5, 33, 34, 35, 11, 24, 102,
+ 33, 34, 35, 16, 59, 60, 61, 62, 63, 64,
+ 59, 60, 61, 62, 63, 64, 60, 61, 62, 63,
+ 64, 60, 61, 62, 63, 64, 179, 60, 61, 62,
+ 63, 64, 42, 10, 192, 45, 46, 210, 155, 201,
+ -1, 100, 19, 214, 54, 196, 69, -1, 25, -1,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 11, 43, -1, 45,
+ 46, 47, 48, 49, 19, -1, 52, 53, 54, -1,
+ 25, 57, 27, 28, 29, 30, 31, 32, 19, -1,
+ -1, -1, -1, -1, 25, -1, 27, 28, 29, 30,
+ 31, 32, 19, -1, -1, -1, -1, -1, 25, -1,
+ -1, -1, 29, 30, 31, 32, 45, 46, 47, 48,
+ 49, -1, -1, 52, 53, 54, -1, -1, 57
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 37, 38, 39, 67, 68, 69, 70, 71, 75,
+ 11, 11, 11, 0, 41, 69, 82, 83, 3, 72,
+ 73, 74, 72, 3, 76, 77, 78, 9, 83, 15,
+ 12, 73, 17, 12, 15, 12, 77, 9, 79, 3,
+ 5, 7, 9, 18, 55, 60, 61, 113, 114, 115,
+ 116, 117, 3, 4, 9, 26, 51, 111, 112, 113,
+ 4, 42, 3, 80, 81, 17, 18, 115, 3, 9,
+ 115, 115, 17, 84, 20, 23, 24, 33, 34, 35,
+ 59, 60, 61, 62, 63, 64, 9, 112, 115, 112,
+ 9, 19, 25, 27, 28, 29, 30, 31, 32, 9,
+ 15, 10, 16, 3, 10, 3, 7, 114, 80, 85,
+ 10, 36, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115, 115, 115, 7, 10, 3, 112, 112, 112, 112,
+ 112, 112, 112, 112, 113, 111, 81, 10, 10, 10,
+ 11, 30, 86, 10, 10, 10, 43, 45, 46, 47,
+ 48, 49, 52, 53, 54, 57, 87, 88, 91, 92,
+ 101, 102, 105, 106, 107, 108, 4, 6, 7, 8,
+ 22, 58, 94, 95, 96, 99, 113, 7, 56, 93,
+ 113, 112, 4, 4, 4, 102, 12, 88, 17, 7,
+ 103, 113, 13, 6, 9, 17, 16, 43, 11, 94,
+ 11, 110, 113, 9, 104, 95, 80, 100, 96, 7,
+ 89, 90, 91, 108, 19, 97, 87, 104, 21, 10,
+ 113, 14, 10, 12, 90, 17, 20, 98, 110, 12,
+ 113, 10, 50, 109, 11, 108, 87, 12
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, lexer, resultAST, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, lexer)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value, Location); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ size_t yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep, yylocationp)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+ (void) yylocationp;
+
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+ (void) yylocationp;
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+ case 3: /* "\"identifier\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_str); };
+#line 1209 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 4: /* "\"string\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_str); };
+#line 1214 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 5: /* "\"integer\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_int); };
+#line 1219 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 6: /* "\"section name\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_str); };
+#line 1224 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 7: /* "\"source name\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_str); };
+#line 1229 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 8: /* "\"binary object\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_blob); };
+#line 1234 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+ case 36: /* "\"integer size\"" */
+#line 158 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { delete (yyvaluep->m_int); };
+#line 1239 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (ElftosbLexer * lexer, CommandFileASTNode ** resultAST);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (ElftosbLexer * lexer, CommandFileASTNode ** resultAST)
+#else
+int
+yyparse (lexer, resultAST)
+ ElftosbLexer * lexer;
+ CommandFileASTNode ** resultAST;
+#endif
+#endif
+{
+ /* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+/* Location data for the look-ahead symbol. */
+YYLTYPE yylloc;
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+ yylsp = yyls;
+#if YYLTYPE_IS_TRIVIAL
+ /* Initialize the default location before parsing starts. */
+ yylloc.first_line = yylloc.last_line = 1;
+ yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+ YYSTACK_RELOCATE (yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a look-ahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+ *++yylsp = yylloc;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, yylsp - yylen, yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 163 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ CommandFileASTNode * commandFile = new CommandFileASTNode();
+ commandFile->setBlocks(dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast)));
+ commandFile->setSections(dynamic_cast<ListASTNode*>((yyvsp[0].m_ast)));
+ commandFile->setLocation((yylsp[-1]), (yylsp[0]));
+ *resultAST = commandFile;
+ ;}
+ break;
+
+ case 3:
+#line 173 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 4:
+#line 179 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 5:
+#line 186 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 6:
+#line 187 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 7:
+#line 188 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 8:
+#line 192 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new OptionsBlockASTNode(dynamic_cast<ListASTNode *>((yyvsp[-1].m_ast)));
+ ;}
+ break;
+
+ case 9:
+#line 198 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new ConstantsBlockASTNode(dynamic_cast<ListASTNode *>((yyvsp[-1].m_ast)));
+ ;}
+ break;
+
+ case 10:
+#line 204 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 11:
+#line 210 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 12:
+#line 216 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[-1].m_ast); ;}
+ break;
+
+ case 13:
+#line 217 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 14:
+#line 221 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new AssignmentASTNode((yyvsp[-2].m_str), (yyvsp[0].m_ast));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 15:
+#line 228 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SourcesBlockASTNode(dynamic_cast<ListASTNode *>((yyvsp[-1].m_ast)));
+ ;}
+ break;
+
+ case 16:
+#line 234 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 17:
+#line 240 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 18:
+#line 248 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ // tell the lexer that this is the name of a source file
+ SourceDefASTNode * node = dynamic_cast<SourceDefASTNode*>((yyvsp[-2].m_ast));
+ if ((yyvsp[-1].m_ast))
+ {
+ node->setAttributes(dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast)));
+ }
+ node->setLocation(node->getLocation(), (yylsp[0]));
+ lexer->addSourceName(node->getName());
+ (yyval.m_ast) = (yyvsp[-2].m_ast);
+ ;}
+ break;
+
+ case 19:
+#line 259 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 20:
+#line 263 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new PathSourceDefASTNode((yyvsp[-2].m_str), (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 21:
+#line 268 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new ExternSourceDefASTNode((yyvsp[-5].m_str), dynamic_cast<ExprASTNode*>((yyvsp[-1].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-5]), (yylsp[0]));
+ ;}
+ break;
+
+ case 22:
+#line 275 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[-1].m_ast); ;}
+ break;
+
+ case 23:
+#line 276 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 24:
+#line 281 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 25:
+#line 287 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-2].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-2].m_ast);
+ ;}
+ break;
+
+ case 26:
+#line 295 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new AssignmentASTNode((yyvsp[-2].m_str), (yyvsp[0].m_ast));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 27:
+#line 302 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 28:
+#line 308 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 29:
+#line 315 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ SectionContentsASTNode * sectionNode = dynamic_cast<SectionContentsASTNode*>((yyvsp[0].m_ast));
+ if (sectionNode)
+ {
+ ExprASTNode * exprNode = dynamic_cast<ExprASTNode*>((yyvsp[-3].m_ast));
+ sectionNode->setSectionNumberExpr(exprNode);
+ sectionNode->setOptions(dynamic_cast<ListASTNode*>((yyvsp[-2].m_ast)));
+ sectionNode->setLocation((yylsp[-5]), sectionNode->getLocation());
+ }
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 30:
+#line 330 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 31:
+#line 334 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = NULL;
+ ;}
+ break;
+
+ case 32:
+#line 341 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 33:
+#line 345 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = NULL;
+ ;}
+ break;
+
+ case 34:
+#line 352 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ DataSectionContentsASTNode * dataSection = new DataSectionContentsASTNode((yyvsp[-1].m_ast));
+ dataSection->setLocation((yylsp[-2]), (yylsp[0]));
+ (yyval.m_ast) = dataSection;
+ ;}
+ break;
+
+ case 35:
+#line 358 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * listNode = dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast));
+ (yyval.m_ast) = new BootableSectionContentsASTNode(listNode);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 36:
+#line 366 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 37:
+#line 372 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 38:
+#line 379 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[-1].m_ast); ;}
+ break;
+
+ case 39:
+#line 380 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 40:
+#line 381 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 41:
+#line 382 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 42:
+#line 386 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 43:
+#line 392 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 44:
+#line 399 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[-1].m_ast); ;}
+ break;
+
+ case 45:
+#line 400 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 46:
+#line 401 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 47:
+#line 404 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 48:
+#line 405 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 49:
+#line 406 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 50:
+#line 407 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 51:
+#line 411 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ LoadStatementASTNode * stmt = new LoadStatementASTNode();
+ stmt->setData((yyvsp[-1].m_ast));
+ stmt->setTarget((yyvsp[0].m_ast));
+ // set dcd load flag if the "dcd" keyword was present.
+ if ((yyvsp[-2].m_num))
+ {
+ stmt->setDCDLoad(true);
+ }
+ // set char locations for the statement
+ if ((yyvsp[0].m_ast))
+ {
+ stmt->setLocation((yylsp[-3]), (yylsp[0]));
+ }
+ else
+ {
+ stmt->setLocation((yylsp[-3]), (yylsp[-1]));
+ }
+ (yyval.m_ast) = stmt;
+ ;}
+ break;
+
+ case 52:
+#line 434 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ if (!elftosb::g_enableHABSupport)
+ {
+ yyerror(&yylloc, lexer, resultAST, "HAB features not supported with the selected family");
+ YYABORT;
+ }
+
+ (yyval.m_num) = 1;
+ ;}
+ break;
+
+ case 53:
+#line 443 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_num) = 0; ;}
+ break;
+
+ case 54:
+#line 446 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 55:
+#line 450 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new StringConstASTNode((yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 56:
+#line 455 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SourceASTNode((yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 57:
+#line 460 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>((yyvsp[0].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 58:
+#line 465 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>((yyvsp[-2].m_ast)), (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 59:
+#line 470 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast)), (yyvsp[-3].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 60:
+#line 475 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new BlobConstASTNode((yyvsp[0].m_blob));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 61:
+#line 480 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ;}
+ break;
+
+ case 62:
+#line 485 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ ;}
+ break;
+
+ case 63:
+#line 491 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ dynamic_cast<ListASTNode*>((yyvsp[-2].m_ast))->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = (yyvsp[-2].m_ast);
+ ;}
+ break;
+
+ case 64:
+#line 499 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SectionASTNode((yyvsp[0].m_str), SectionASTNode::kInclude);
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 65:
+#line 504 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SectionASTNode((yyvsp[0].m_str), SectionASTNode::kExclude);
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 66:
+#line 511 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 67:
+#line 515 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new NaturalLocationASTNode();
+// $$->setLocation();
+ ;}
+ break;
+
+ case 68:
+#line 522 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new NaturalLocationASTNode();
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 69:
+#line 527 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 70:
+#line 533 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ IVTConstASTNode * ivt = new IVTConstASTNode();
+ if ((yyvsp[-1].m_ast))
+ {
+ ivt->setFieldAssignments(dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast)));
+ }
+ ivt->setLocation((yylsp[-3]), (yylsp[0]));
+ (yyval.m_ast) = ivt;
+ ;}
+ break;
+
+ case 71:
+#line 544 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 72:
+#line 545 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 73:
+#line 549 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ CallStatementASTNode * stmt = new CallStatementASTNode();
+ switch ((yyvsp[-2].m_num))
+ {
+ case 1:
+ stmt->setCallType(CallStatementASTNode::kCallType);
+ break;
+ case 2:
+ stmt->setCallType(CallStatementASTNode::kJumpType);
+ break;
+ default:
+ yyerror(&yylloc, lexer, resultAST, "invalid call_or_jump value");
+ YYABORT;
+ break;
+ }
+ stmt->setTarget((yyvsp[-1].m_ast));
+ stmt->setArgument((yyvsp[0].m_ast));
+ stmt->setIsHAB(false);
+ if ((yyvsp[0].m_ast))
+ {
+ stmt->setLocation((yylsp[-2]), (yylsp[0]));
+ }
+ else
+ {
+ stmt->setLocation((yylsp[-2]), (yylsp[-1]));
+ }
+ (yyval.m_ast) = stmt;
+ ;}
+ break;
+
+ case 74:
+#line 578 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ if (!elftosb::g_enableHABSupport)
+ {
+ yyerror(&yylloc, lexer, resultAST, "HAB features not supported with the selected family");
+ YYABORT;
+ }
+
+ CallStatementASTNode * stmt = new CallStatementASTNode();
+ switch ((yyvsp[-2].m_num))
+ {
+ case 1:
+ stmt->setCallType(CallStatementASTNode::kCallType);
+ break;
+ case 2:
+ stmt->setCallType(CallStatementASTNode::kJumpType);
+ break;
+ default:
+ yyerror(&yylloc, lexer, resultAST, "invalid call_or_jump value");
+ YYABORT;
+ break;
+ }
+ stmt->setTarget((yyvsp[-1].m_ast));
+ stmt->setArgument((yyvsp[0].m_ast));
+ stmt->setIsHAB(true);
+ if ((yyvsp[0].m_ast))
+ {
+ stmt->setLocation((yylsp[-3]), (yylsp[0]));
+ }
+ else
+ {
+ stmt->setLocation((yylsp[-3]), (yylsp[-1]));
+ }
+ (yyval.m_ast) = stmt;
+ ;}
+ break;
+
+ case 75:
+#line 614 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_num) = 1; ;}
+ break;
+
+ case 76:
+#line 615 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_num) = 2; ;}
+ break;
+
+ case 77:
+#line 619 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SymbolASTNode(NULL, (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 78:
+#line 624 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new AddressRangeASTNode((yyvsp[0].m_ast), NULL);
+ (yyval.m_ast)->setLocation((yyvsp[0].m_ast));
+ ;}
+ break;
+
+ case 79:
+#line 630 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[-1].m_ast); ;}
+ break;
+
+ case 80:
+#line 631 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 81:
+#line 632 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 82:
+#line 636 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new FromStatementASTNode((yyvsp[-3].m_str), dynamic_cast<ListASTNode*>((yyvsp[-1].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-4]), (yylsp[0]));
+ ;}
+ break;
+
+ case 83:
+#line 643 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new ModeStatementASTNode(dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 84:
+#line 650 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new MessageStatementASTNode(MessageStatementASTNode::kInfo, (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 85:
+#line 655 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new MessageStatementASTNode(MessageStatementASTNode::kWarning, (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 86:
+#line 660 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new MessageStatementASTNode(MessageStatementASTNode::kError, (yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 87:
+#line 667 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ IfStatementASTNode * ifStmt = new IfStatementASTNode();
+ ifStmt->setConditionExpr(dynamic_cast<ExprASTNode*>((yyvsp[-4].m_ast)));
+ ifStmt->setIfStatements(dynamic_cast<ListASTNode*>((yyvsp[-2].m_ast)));
+ ifStmt->setElseStatements(dynamic_cast<ListASTNode*>((yyvsp[0].m_ast)));
+ ifStmt->setLocation((yylsp[-5]), (yylsp[0]));
+ (yyval.m_ast) = ifStmt;
+ ;}
+ break;
+
+ case 88:
+#line 678 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ ;}
+ break;
+
+ case 89:
+#line 682 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode((yyvsp[0].m_ast));
+ (yyval.m_ast) = list;
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 90:
+#line 688 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = NULL; ;}
+ break;
+
+ case 91:
+#line 692 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new AddressRangeASTNode((yyvsp[0].m_ast), NULL);
+ (yyval.m_ast)->setLocation((yyvsp[0].m_ast));
+ ;}
+ break;
+
+ case 92:
+#line 697 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new AddressRangeASTNode((yyvsp[-2].m_ast), (yyvsp[0].m_ast));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 93:
+#line 704 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 94:
+#line 708 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new StringConstASTNode((yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 95:
+#line 715 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 96:
+#line 719 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kLessThan, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 97:
+#line 726 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kGreaterThan, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 98:
+#line 733 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kGreaterThanEqual, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 99:
+#line 740 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kLessThanEqual, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 100:
+#line 747 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kEqual, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 101:
+#line 754 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kNotEqual, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 102:
+#line 761 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBooleanAnd, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 103:
+#line 768 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBooleanOr, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 104:
+#line 775 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new BooleanNotExprASTNode(dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 105:
+#line 780 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SourceFileFunctionASTNode((yyvsp[-3].m_str), (yyvsp[-1].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 106:
+#line 785 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 107:
+#line 790 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new DefinedOperatorASTNode((yyvsp[-1].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 108:
+#line 796 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ { (yyval.m_ast) = (yyvsp[0].m_ast); ;}
+ break;
+
+ case 109:
+#line 800 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SymbolASTNode((yyvsp[0].m_str), (yyvsp[-2].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 110:
+#line 805 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SymbolASTNode((yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 111:
+#line 813 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 112:
+#line 817 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new VariableExprASTNode((yyvsp[0].m_str));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 113:
+#line 822 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SymbolRefExprASTNode(dynamic_cast<SymbolASTNode*>((yyvsp[0].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+ case 114:
+#line 833 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kAdd, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 115:
+#line 840 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kSubtract, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 116:
+#line 847 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kMultiply, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 117:
+#line 854 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kDivide, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 118:
+#line 861 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kModulus, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 119:
+#line 868 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kPower, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 120:
+#line 875 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseAnd, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 121:
+#line 882 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseOr, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 122:
+#line 889 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseXor, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 123:
+#line 896 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kShiftLeft, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 124:
+#line 903 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast));
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast));
+ (yyval.m_ast) = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kShiftRight, right);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 125:
+#line 910 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 126:
+#line 914 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new IntSizeExprASTNode(dynamic_cast<ExprASTNode*>((yyvsp[-2].m_ast)), (yyvsp[0].m_int)->getWordSize());
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 127:
+#line 919 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[-1].m_ast);
+ (yyval.m_ast)->setLocation((yylsp[-2]), (yylsp[0]));
+ ;}
+ break;
+
+ case 128:
+#line 924 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SizeofOperatorASTNode(dynamic_cast<SymbolASTNode*>((yyvsp[-1].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 129:
+#line 929 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SizeofOperatorASTNode((yyvsp[-1].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 130:
+#line 934 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new SizeofOperatorASTNode((yyvsp[-1].m_str));
+ (yyval.m_ast)->setLocation((yylsp[-3]), (yylsp[0]));
+ ;}
+ break;
+
+ case 131:
+#line 941 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = (yyvsp[0].m_ast);
+ ;}
+ break;
+
+ case 132:
+#line 945 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new NegativeExprASTNode(dynamic_cast<ExprASTNode*>((yyvsp[0].m_ast)));
+ (yyval.m_ast)->setLocation((yylsp[-1]), (yylsp[0]));
+ ;}
+ break;
+
+ case 133:
+#line 952 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+ {
+ (yyval.m_ast) = new IntConstExprASTNode((yyvsp[0].m_int)->getValue(), (yyvsp[0].m_int)->getWordSize());
+ (yyval.m_ast)->setLocation((yylsp[0]));
+ ;}
+ break;
+
+
+ default: break;
+ }
+
+/* Line 1126 of yacc.c. */
+#line 2663 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.cpp"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ yylsp -= yylen;
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ char *yymsg = 0;
+# define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+#if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+
+ if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyf))
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ yyerror (&yylloc, lexer, resultAST, yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ {
+ yyerror (&yylloc, lexer, resultAST, YY_("syntax error"));
+ goto yyexhaustedlab;
+ }
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror (&yylloc, lexer, resultAST, YY_("syntax error"));
+ }
+
+ yyerror_range[0] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding", yytoken, &yylval, &yylloc);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (0)
+ goto yyerrorlab;
+
+ yyerror_range[0] = yylsp[1-yylen];
+ yylsp -= yylen;
+ yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[0] = *yylsp;
+ yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+ yyerror_range[1] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the look-ahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, yyerror_range - 1, 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, lexer, resultAST, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp);
+ YYPOPSTACK;
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 958 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+
+
+/* code goes here */
+
+static int yylex(YYSTYPE * lvalp, YYLTYPE * yylloc, ElftosbLexer * lexer)
+{
+ int token = lexer->yylex();
+ *yylloc = lexer->getLocation();
+ lexer->getSymbolValue(lvalp);
+ return token;
+}
+
+static void yyerror(YYLTYPE * yylloc, ElftosbLexer * lexer, CommandFileASTNode ** resultAST, const char * error)
+{
+ throw syntax_error(format_string("line %d: %s\n", yylloc->m_firstLine, error));
+}
+
+
diff --git a/elftosb2/elftosb_parser.tab.hpp b/elftosb2/elftosb_parser.tab.hpp
new file mode 100644
index 0000000..4ee45c4
--- /dev/null
+++ b/elftosb2/elftosb_parser.tab.hpp
@@ -0,0 +1,152 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_IDENT = 258,
+ TOK_STRING_LITERAL = 259,
+ TOK_INT_LITERAL = 260,
+ TOK_SECTION_NAME = 261,
+ TOK_SOURCE_NAME = 262,
+ TOK_BLOB = 263,
+ TOK_DOT_DOT = 264,
+ TOK_AND = 265,
+ TOK_OR = 266,
+ TOK_GEQ = 267,
+ TOK_LEQ = 268,
+ TOK_EQ = 269,
+ TOK_NEQ = 270,
+ TOK_POWER = 271,
+ TOK_LSHIFT = 272,
+ TOK_RSHIFT = 273,
+ TOK_INT_SIZE = 274,
+ TOK_OPTIONS = 275,
+ TOK_CONSTANTS = 276,
+ TOK_SOURCES = 277,
+ TOK_FILTERS = 278,
+ TOK_SECTION = 279,
+ TOK_EXTERN = 280,
+ TOK_FROM = 281,
+ TOK_RAW = 282,
+ TOK_LOAD = 283,
+ TOK_JUMP = 284,
+ TOK_CALL = 285,
+ TOK_MODE = 286,
+ TOK_IF = 287,
+ TOK_ELSE = 288,
+ TOK_DEFINED = 289,
+ TOK_INFO = 290,
+ TOK_WARNING = 291,
+ TOK_ERROR = 292,
+ TOK_SIZEOF = 293,
+ TOK_DCD = 294,
+ TOK_HAB = 295,
+ TOK_IVT = 296,
+ UNARY_OP = 297
+ };
+#endif
+/* Tokens. */
+#define TOK_IDENT 258
+#define TOK_STRING_LITERAL 259
+#define TOK_INT_LITERAL 260
+#define TOK_SECTION_NAME 261
+#define TOK_SOURCE_NAME 262
+#define TOK_BLOB 263
+#define TOK_DOT_DOT 264
+#define TOK_AND 265
+#define TOK_OR 266
+#define TOK_GEQ 267
+#define TOK_LEQ 268
+#define TOK_EQ 269
+#define TOK_NEQ 270
+#define TOK_POWER 271
+#define TOK_LSHIFT 272
+#define TOK_RSHIFT 273
+#define TOK_INT_SIZE 274
+#define TOK_OPTIONS 275
+#define TOK_CONSTANTS 276
+#define TOK_SOURCES 277
+#define TOK_FILTERS 278
+#define TOK_SECTION 279
+#define TOK_EXTERN 280
+#define TOK_FROM 281
+#define TOK_RAW 282
+#define TOK_LOAD 283
+#define TOK_JUMP 284
+#define TOK_CALL 285
+#define TOK_MODE 286
+#define TOK_IF 287
+#define TOK_ELSE 288
+#define TOK_DEFINED 289
+#define TOK_INFO 290
+#define TOK_WARNING 291
+#define TOK_ERROR 292
+#define TOK_SIZEOF 293
+#define TOK_DCD 294
+#define TOK_HAB 295
+#define TOK_IVT 296
+#define UNARY_OP 297
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 58 "/Users/creed/projects/fsl/fromsvr/elftosb/elftosb2/elftosb_parser.y"
+typedef union YYSTYPE {
+ int m_num;
+ elftosb::SizedIntegerValue * m_int;
+ Blob * m_blob;
+ std::string * m_str;
+ elftosb::ASTNode * m_ast; // must use full name here because this is put into *.tab.hpp
+} YYSTYPE;
+/* Line 1447 of yacc.c. */
+#line 130 "/Users/creed/projects/fsl/fromsvr/elftosb/build/elftosb.build/Debug/elftosb.build/DerivedSources/elftosb_parser.tab.hpp"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined (YYLTYPE) && ! defined (YYLTYPE_IS_DECLARED)
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
diff --git a/elftosb2/elftosb_parser.y b/elftosb2/elftosb_parser.y
new file mode 100644
index 0000000..7c33652
--- /dev/null
+++ b/elftosb2/elftosb_parser.y
@@ -0,0 +1,978 @@
+/*
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+/* write header with token defines */
+%defines
+
+/* make it reentrant */
+%pure-parser
+
+/* put more info in error messages */
+%error-verbose
+
+/* enable location processing */
+%locations
+
+%{
+#include "ElftosbLexer.h"
+#include "ElftosbAST.h"
+#include "Logging.h"
+#include "Blob.h"
+#include "format_string.h"
+#include "Value.h"
+#include "ConversionController.h"
+
+using namespace elftosb;
+
+//! Our special location type.
+#define YYLTYPE token_loc_t
+
+// this indicates that we're using our own type. it should be unset automatically
+// but that's not working for some reason with the .hpp file.
+#if defined(YYLTYPE_IS_TRIVIAL)
+ #undef YYLTYPE_IS_TRIVIAL
+ #define YYLTYPE_IS_TRIVIAL 0
+#endif
+
+//! Default location action
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) \
+ { \
+ (Current).m_firstLine = YYRHSLOC(Rhs, 1).m_firstLine; \
+ (Current).m_lastLine = YYRHSLOC(Rhs, N).m_lastLine; \
+ } \
+ else \
+ { \
+ (Current).m_firstLine = (Current).m_lastLine = YYRHSLOC(Rhs, 0).m_lastLine; \
+ } \
+ } while (0)
+
+//! Forward declaration of yylex().
+static int yylex(YYSTYPE * lvalp, YYLTYPE * yylloc, ElftosbLexer * lexer);
+
+// Forward declaration of error handling function.
+static void yyerror(YYLTYPE * yylloc, ElftosbLexer * lexer, CommandFileASTNode ** resultAST, const char * error);
+
+%}
+
+/* symbol types */
+%union {
+ int m_num;
+ elftosb::SizedIntegerValue * m_int;
+ Blob * m_blob;
+ std::string * m_str;
+ elftosb::ASTNode * m_ast; // must use full name here because this is put into *.tab.hpp
+}
+
+/* extra parameters for the parser and lexer */
+%parse-param {ElftosbLexer * lexer}
+%parse-param {CommandFileASTNode ** resultAST}
+%lex-param {ElftosbLexer * lexer}
+
+/* token definitions */
+%token <m_str> TOK_IDENT "identifier"
+%token <m_str> TOK_STRING_LITERAL "string"
+%token <m_int> TOK_INT_LITERAL "integer"
+%token <m_str> TOK_SECTION_NAME "section name"
+%token <m_str> TOK_SOURCE_NAME "source name"
+%token <m_blob> TOK_BLOB "binary object"
+%token '('
+%token ')'
+%token '{'
+%token '}'
+%token '['
+%token ']'
+%token '='
+%token ','
+%token ';'
+%token ':'
+%token '>'
+%token '.'
+%token TOK_DOT_DOT ".."
+%token '~'
+%token '&'
+%token '|'
+%token '<'
+%token '>'
+%token '!'
+%token TOK_AND "&&"
+%token TOK_OR "||"
+%token TOK_GEQ ">="
+%token TOK_LEQ "<="
+%token TOK_EQ "=="
+%token TOK_NEQ "!="
+%token TOK_POWER "**"
+%token TOK_LSHIFT "<<"
+%token TOK_RSHIFT ">>"
+%token <m_int> TOK_INT_SIZE "integer size"
+%token TOK_OPTIONS "options"
+%token TOK_CONSTANTS "constants"
+%token TOK_SOURCES "sources"
+%token TOK_FILTERS "filters"
+%token TOK_SECTION "section"
+%token TOK_EXTERN "extern"
+%token TOK_FROM "from"
+%token TOK_RAW "raw"
+%token TOK_LOAD "load"
+%token TOK_JUMP "jump"
+%token TOK_CALL "call"
+%token TOK_MODE "mode"
+%token TOK_IF "if"
+%token TOK_ELSE "else"
+%token TOK_DEFINED "defined"
+%token TOK_INFO "info"
+%token TOK_WARNING "warning"
+%token TOK_ERROR "error"
+%token TOK_SIZEOF "sizeof"
+%token TOK_DCD "dcd"
+%token TOK_HAB "hab"
+%token TOK_IVT "ivt"
+
+/* operator precedence */
+%left "&&" "||"
+%left '>' '<' ">=" "<=" "==" "!="
+%left '|'
+%left '^'
+%left '&'
+%left "<<" ">>"
+%left "**"
+%left '+' '-'
+%left '*' '/' '%'
+%left '.'
+%right UNARY_OP
+
+/* nonterminal types - most nonterminal symbols are subclasses of ASTNode */
+%type <m_ast> command_file blocks_list pre_section_block options_block const_def_list const_def_list_elem
+%type <m_ast> const_def const_expr expr int_const_expr unary_expr int_value constants_block
+%type <m_ast> sources_block source_def_list source_def_list_elem source_def
+%type <m_ast> section_defs section_def section_contents full_stmt_list full_stmt_list_elem
+%type <m_ast> basic_stmt load_stmt call_stmt from_stmt load_data load_target call_target
+%type <m_ast> address_or_range load_target_opt call_arg_opt basic_stmt_list basic_stmt_list_elem
+%type <m_ast> source_attr_list source_attr_list_elem source_attrs_opt
+%type <m_ast> section_list section_list_elem symbol_ref mode_stmt
+%type <m_ast> section_options_opt source_attr_list_opt
+%type <m_ast> if_stmt else_opt message_stmt
+%type <m_ast> bool_expr ivt_def assignment_list_opt
+
+%type <m_num> call_or_jump dcd_opt
+
+%destructor { delete $$; } TOK_IDENT TOK_STRING_LITERAL TOK_SECTION_NAME TOK_SOURCE_NAME TOK_BLOB TOK_INT_SIZE TOK_INT_LITERAL
+
+%%
+
+command_file : blocks_list section_defs
+ {
+ CommandFileASTNode * commandFile = new CommandFileASTNode();
+ commandFile->setBlocks(dynamic_cast<ListASTNode*>($1));
+ commandFile->setSections(dynamic_cast<ListASTNode*>($2));
+ commandFile->setLocation(@1, @2);
+ *resultAST = commandFile;
+ }
+ ;
+
+blocks_list : pre_section_block
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | blocks_list pre_section_block
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+pre_section_block
+ : options_block { $$ = $1; }
+ | constants_block { $$ = $1; }
+ | sources_block { $$ = $1; }
+ ;
+
+options_block : "options" '{' const_def_list '}'
+ {
+ $$ = new OptionsBlockASTNode(dynamic_cast<ListASTNode *>($3));
+ }
+ ;
+
+constants_block : "constants" '{' const_def_list '}'
+ {
+ $$ = new ConstantsBlockASTNode(dynamic_cast<ListASTNode *>($3));
+ }
+ ;
+
+const_def_list : const_def_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | const_def_list const_def_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+const_def_list_elem : const_def ';' { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+const_def : TOK_IDENT '=' const_expr
+ {
+ $$ = new AssignmentASTNode($1, $3);
+ $$->setLocation(@1, @3);
+ }
+ ;
+
+sources_block : "sources" '{' source_def_list '}'
+ {
+ $$ = new SourcesBlockASTNode(dynamic_cast<ListASTNode *>($3));
+ }
+ ;
+
+source_def_list : source_def_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | source_def_list source_def_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+source_def_list_elem
+ : source_def source_attrs_opt ';'
+ {
+ // tell the lexer that this is the name of a source file
+ SourceDefASTNode * node = dynamic_cast<SourceDefASTNode*>($1);
+ if ($2)
+ {
+ node->setAttributes(dynamic_cast<ListASTNode*>($2));
+ }
+ node->setLocation(node->getLocation(), @3);
+ lexer->addSourceName(node->getName());
+ $$ = $1;
+ }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+source_def : TOK_IDENT '=' TOK_STRING_LITERAL
+ {
+ $$ = new PathSourceDefASTNode($1, $3);
+ $$->setLocation(@1, @3);
+ }
+ | TOK_IDENT '=' "extern" '(' int_const_expr ')'
+ {
+ $$ = new ExternSourceDefASTNode($1, dynamic_cast<ExprASTNode*>($5));
+ $$->setLocation(@1, @6);
+ }
+ ;
+
+source_attrs_opt
+ : '(' source_attr_list ')' { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+source_attr_list
+ : source_attr_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | source_attr_list ',' source_attr_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($3);
+ $$ = $1;
+ }
+ ;
+
+source_attr_list_elem
+ : TOK_IDENT '=' const_expr
+ {
+ $$ = new AssignmentASTNode($1, $3);
+ $$->setLocation(@1, @3);
+ }
+ ;
+
+section_defs : section_def
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | section_defs section_def
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+section_def : "section" '(' int_const_expr section_options_opt ')' section_contents
+ {
+ SectionContentsASTNode * sectionNode = dynamic_cast<SectionContentsASTNode*>($6);
+ if (sectionNode)
+ {
+ ExprASTNode * exprNode = dynamic_cast<ExprASTNode*>($3);
+ sectionNode->setSectionNumberExpr(exprNode);
+ sectionNode->setOptions(dynamic_cast<ListASTNode*>($4));
+ sectionNode->setLocation(@1, sectionNode->getLocation());
+ }
+ $$ = $6;
+ }
+ ;
+
+section_options_opt
+ : ';' source_attr_list_opt
+ {
+ $$ = $2;
+ }
+ | /* empty */
+ {
+ $$ = NULL;
+ }
+ ;
+
+source_attr_list_opt
+ : source_attr_list
+ {
+ $$ = $1;
+ }
+ | /* empty */
+ {
+ $$ = NULL;
+ }
+ ;
+
+section_contents
+ : "<=" load_data ';'
+ {
+ DataSectionContentsASTNode * dataSection = new DataSectionContentsASTNode($2);
+ dataSection->setLocation(@1, @3);
+ $$ = dataSection;
+ }
+ | '{' full_stmt_list '}'
+ {
+ ListASTNode * listNode = dynamic_cast<ListASTNode*>($2);
+ $$ = new BootableSectionContentsASTNode(listNode);
+ $$->setLocation(@1, @3);
+ }
+ ;
+
+full_stmt_list : full_stmt_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | full_stmt_list full_stmt_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+full_stmt_list_elem
+ : basic_stmt ';' { $$ = $1; }
+ | from_stmt { $$ = $1; }
+ | if_stmt { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+basic_stmt_list : basic_stmt_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | basic_stmt_list basic_stmt_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($2);
+ $$ = $1;
+ }
+ ;
+
+basic_stmt_list_elem
+ : basic_stmt ';' { $$ = $1; }
+ | if_stmt { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+basic_stmt : load_stmt { $$ = $1; }
+ | call_stmt { $$ = $1; }
+ | mode_stmt { $$ = $1; }
+ | message_stmt { $$ = $1; }
+ ;
+
+load_stmt : "load" dcd_opt load_data load_target_opt
+ {
+ LoadStatementASTNode * stmt = new LoadStatementASTNode();
+ stmt->setData($3);
+ stmt->setTarget($4);
+ // set dcd load flag if the "dcd" keyword was present.
+ if ($2)
+ {
+ stmt->setDCDLoad(true);
+ }
+ // set char locations for the statement
+ if ($4)
+ {
+ stmt->setLocation(@1, @4);
+ }
+ else
+ {
+ stmt->setLocation(@1, @3);
+ }
+ $$ = stmt;
+ }
+ ;
+
+dcd_opt : "dcd"
+ {
+ if (!elftosb::g_enableHABSupport)
+ {
+ yyerror(&yylloc, lexer, resultAST, "HAB features not supported with the selected family");
+ YYABORT;
+ }
+
+ $$ = 1;
+ }
+ | /* empty */ { $$ = 0; }
+
+load_data : int_const_expr
+ {
+ $$ = $1;
+ }
+ | TOK_STRING_LITERAL
+ {
+ $$ = new StringConstASTNode($1);
+ $$->setLocation(@1);
+ }
+ | TOK_SOURCE_NAME
+ {
+ $$ = new SourceASTNode($1);
+ $$->setLocation(@1);
+ }
+ | section_list
+ {
+ $$ = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>($1));
+ $$->setLocation(@1);
+ }
+ | section_list "from" TOK_SOURCE_NAME
+ {
+ $$ = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>($1), $3);
+ $$->setLocation(@1, @3);
+ }
+ | TOK_SOURCE_NAME '[' section_list ']'
+ {
+ $$ = new SectionMatchListASTNode(dynamic_cast<ListASTNode*>($3), $1);
+ $$->setLocation(@1, @4);
+ }
+ | TOK_BLOB
+ {
+ $$ = new BlobConstASTNode($1);
+ $$->setLocation(@1);
+ }
+ | ivt_def
+ {
+ }
+ ;
+
+section_list : section_list_elem
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($1);
+ $$ = list;
+ }
+ | section_list ',' section_list_elem
+ {
+ dynamic_cast<ListASTNode*>($1)->appendNode($3);
+ $$ = $1;
+ }
+ ;
+
+section_list_elem
+ : TOK_SECTION_NAME
+ {
+ $$ = new SectionASTNode($1, SectionASTNode::kInclude);
+ $$->setLocation(@1);
+ }
+ | '~' TOK_SECTION_NAME
+ {
+ $$ = new SectionASTNode($2, SectionASTNode::kExclude);
+ $$->setLocation(@1, @2);
+ }
+ ;
+
+load_target_opt : '>' load_target
+ {
+ $$ = $2;
+ }
+ | /* empty */
+ {
+ $$ = new NaturalLocationASTNode();
+// $$->setLocation();
+ }
+ ;
+
+load_target : '.'
+ {
+ $$ = new NaturalLocationASTNode();
+ $$->setLocation(@1);
+ }
+ | address_or_range
+ {
+ $$ = $1;
+ }
+ ;
+
+ivt_def : "ivt" '(' assignment_list_opt ')'
+ {
+ IVTConstASTNode * ivt = new IVTConstASTNode();
+ if ($3)
+ {
+ ivt->setFieldAssignments(dynamic_cast<ListASTNode*>($3));
+ }
+ ivt->setLocation(@1, @4);
+ $$ = ivt;
+ }
+ ;
+
+assignment_list_opt : source_attr_list { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+call_stmt : call_or_jump call_target call_arg_opt
+ {
+ CallStatementASTNode * stmt = new CallStatementASTNode();
+ switch ($1)
+ {
+ case 1:
+ stmt->setCallType(CallStatementASTNode::kCallType);
+ break;
+ case 2:
+ stmt->setCallType(CallStatementASTNode::kJumpType);
+ break;
+ default:
+ yyerror(&yylloc, lexer, resultAST, "invalid call_or_jump value");
+ YYABORT;
+ break;
+ }
+ stmt->setTarget($2);
+ stmt->setArgument($3);
+ stmt->setIsHAB(false);
+ if ($3)
+ {
+ stmt->setLocation(@1, @3);
+ }
+ else
+ {
+ stmt->setLocation(@1, @2);
+ }
+ $$ = stmt;
+ }
+ | "hab" call_or_jump address_or_range call_arg_opt
+ {
+ if (!elftosb::g_enableHABSupport)
+ {
+ yyerror(&yylloc, lexer, resultAST, "HAB features not supported with the selected family");
+ YYABORT;
+ }
+
+ CallStatementASTNode * stmt = new CallStatementASTNode();
+ switch ($2)
+ {
+ case 1:
+ stmt->setCallType(CallStatementASTNode::kCallType);
+ break;
+ case 2:
+ stmt->setCallType(CallStatementASTNode::kJumpType);
+ break;
+ default:
+ yyerror(&yylloc, lexer, resultAST, "invalid call_or_jump value");
+ YYABORT;
+ break;
+ }
+ stmt->setTarget($3);
+ stmt->setArgument($4);
+ stmt->setIsHAB(true);
+ if ($4)
+ {
+ stmt->setLocation(@1, @4);
+ }
+ else
+ {
+ stmt->setLocation(@1, @3);
+ }
+ $$ = stmt;
+ }
+ ;
+
+call_or_jump : "call" { $$ = 1; }
+ | "jump" { $$ = 2; }
+ ;
+
+call_target : TOK_SOURCE_NAME
+ {
+ $$ = new SymbolASTNode(NULL, $1);
+ $$->setLocation(@1);
+ }
+ | int_const_expr
+ {
+ $$ = new AddressRangeASTNode($1, NULL);
+ $$->setLocation($1);
+ }
+ ;
+
+call_arg_opt : '(' int_const_expr ')' { $$ = $2; }
+ | '(' ')' { $$ = NULL; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+from_stmt : "from" TOK_SOURCE_NAME '{' basic_stmt_list '}'
+ {
+ $$ = new FromStatementASTNode($2, dynamic_cast<ListASTNode*>($4));
+ $$->setLocation(@1, @5);
+ }
+ ;
+
+mode_stmt : "mode" int_const_expr
+ {
+ $$ = new ModeStatementASTNode(dynamic_cast<ExprASTNode*>($2));
+ $$->setLocation(@1, @2);
+ }
+ ;
+
+message_stmt : "info" TOK_STRING_LITERAL
+ {
+ $$ = new MessageStatementASTNode(MessageStatementASTNode::kInfo, $2);
+ $$->setLocation(@1, @2);
+ }
+ | "warning" TOK_STRING_LITERAL
+ {
+ $$ = new MessageStatementASTNode(MessageStatementASTNode::kWarning, $2);
+ $$->setLocation(@1, @2);
+ }
+ | "error" TOK_STRING_LITERAL
+ {
+ $$ = new MessageStatementASTNode(MessageStatementASTNode::kError, $2);
+ $$->setLocation(@1, @2);
+ }
+ ;
+
+if_stmt : "if" bool_expr '{' full_stmt_list '}' else_opt
+ {
+ IfStatementASTNode * ifStmt = new IfStatementASTNode();
+ ifStmt->setConditionExpr(dynamic_cast<ExprASTNode*>($2));
+ ifStmt->setIfStatements(dynamic_cast<ListASTNode*>($4));
+ ifStmt->setElseStatements(dynamic_cast<ListASTNode*>($6));
+ ifStmt->setLocation(@1, @6);
+ $$ = ifStmt;
+ }
+ ;
+
+else_opt : "else" '{' full_stmt_list '}'
+ {
+ $$ = $3;
+ }
+ | "else" if_stmt
+ {
+ ListASTNode * list = new ListASTNode();
+ list->appendNode($2);
+ $$ = list;
+ $$->setLocation(@1, @2);
+ }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+address_or_range : int_const_expr
+ {
+ $$ = new AddressRangeASTNode($1, NULL);
+ $$->setLocation($1);
+ }
+ | int_const_expr ".." int_const_expr
+ {
+ $$ = new AddressRangeASTNode($1, $3);
+ $$->setLocation(@1, @3);
+ }
+ ;
+
+const_expr : bool_expr
+ {
+ $$ = $1;
+ }
+ | TOK_STRING_LITERAL
+ {
+ $$ = new StringConstASTNode($1);
+ $$->setLocation(@1);
+ }
+ ;
+
+bool_expr : int_const_expr
+ {
+ $$ = $1;
+ }
+ | bool_expr '<' bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kLessThan, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr '>' bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kGreaterThan, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr ">=" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kGreaterThanEqual, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr "<=" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kLessThanEqual, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr "==" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kEqual, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr "!=" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kNotEqual, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr "&&" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBooleanAnd, right);
+ $$->setLocation(@1, @3);
+ }
+ | bool_expr "||" bool_expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBooleanOr, right);
+ $$->setLocation(@1, @3);
+ }
+ | '!' bool_expr %prec UNARY_OP
+ {
+ $$ = new BooleanNotExprASTNode(dynamic_cast<ExprASTNode*>($2));
+ $$->setLocation(@1, @2);
+ }
+ | TOK_IDENT '(' TOK_SOURCE_NAME ')'
+ {
+ $$ = new SourceFileFunctionASTNode($1, $3);
+ $$->setLocation(@1, @4);
+ }
+ | '(' bool_expr ')'
+ {
+ $$ = $2;
+ $$->setLocation(@1, @3);
+ }
+ | "defined" '(' TOK_IDENT ')'
+ {
+ $$ = new DefinedOperatorASTNode($3);
+ $$->setLocation(@1, @4);
+ }
+ ;
+
+int_const_expr : expr { $$ = $1; }
+ ;
+
+symbol_ref : TOK_SOURCE_NAME ':' TOK_IDENT
+ {
+ $$ = new SymbolASTNode($3, $1);
+ $$->setLocation(@1, @3);
+ }
+ | ':' TOK_IDENT
+ {
+ $$ = new SymbolASTNode($2);
+ $$->setLocation(@1, @2);
+ }
+ ;
+
+
+expr : int_value
+ {
+ $$ = $1;
+ }
+ | TOK_IDENT
+ {
+ $$ = new VariableExprASTNode($1);
+ $$->setLocation(@1);
+ }
+ | symbol_ref
+ {
+ $$ = new SymbolRefExprASTNode(dynamic_cast<SymbolASTNode*>($1));
+ $$->setLocation(@1);
+ }
+/* | expr '..' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new RangeExprASTNode(left, right);
+ }
+*/ | expr '+' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kAdd, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '-' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kSubtract, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '*' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kMultiply, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '/' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kDivide, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '%' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kModulus, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr "**" expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kPower, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '&' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseAnd, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '|' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseOr, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr '^' expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kBitwiseXor, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr "<<" expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kShiftLeft, right);
+ $$->setLocation(@1, @3);
+ }
+ | expr ">>" expr
+ {
+ ExprASTNode * left = dynamic_cast<ExprASTNode*>($1);
+ ExprASTNode * right = dynamic_cast<ExprASTNode*>($3);
+ $$ = new BinaryOpExprASTNode(left, BinaryOpExprASTNode::kShiftRight, right);
+ $$->setLocation(@1, @3);
+ }
+ | unary_expr
+ {
+ $$ = $1;
+ }
+ | expr '.' TOK_INT_SIZE
+ {
+ $$ = new IntSizeExprASTNode(dynamic_cast<ExprASTNode*>($1), $3->getWordSize());
+ $$->setLocation(@1, @3);
+ }
+ | '(' expr ')'
+ {
+ $$ = $2;
+ $$->setLocation(@1, @3);
+ }
+ | "sizeof" '(' symbol_ref ')'
+ {
+ $$ = new SizeofOperatorASTNode(dynamic_cast<SymbolASTNode*>($3));
+ $$->setLocation(@1, @4);
+ }
+ | "sizeof" '(' TOK_IDENT ')'
+ {
+ $$ = new SizeofOperatorASTNode($3);
+ $$->setLocation(@1, @4);
+ }
+ | "sizeof" '(' TOK_SOURCE_NAME ')'
+ {
+ $$ = new SizeofOperatorASTNode($3);
+ $$->setLocation(@1, @4);
+ }
+ ;
+
+unary_expr : '+' expr %prec UNARY_OP
+ {
+ $$ = $2;
+ }
+ | '-' expr %prec UNARY_OP
+ {
+ $$ = new NegativeExprASTNode(dynamic_cast<ExprASTNode*>($2));
+ $$->setLocation(@1, @2);
+ }
+ ;
+
+int_value : TOK_INT_LITERAL
+ {
+ $$ = new IntConstExprASTNode($1->getValue(), $1->getWordSize());
+ $$->setLocation(@1);
+ }
+ ;
+
+%%
+
+/* code goes here */
+
+static int yylex(YYSTYPE * lvalp, YYLTYPE * yylloc, ElftosbLexer * lexer)
+{
+ int token = lexer->yylex();
+ *yylloc = lexer->getLocation();
+ lexer->getSymbolValue(lvalp);
+ return token;
+}
+
+static void yyerror(YYLTYPE * yylloc, ElftosbLexer * lexer, CommandFileASTNode ** resultAST, const char * error)
+{
+ throw syntax_error(format_string("line %d: %s\n", yylloc->m_firstLine, error));
+}
+
diff --git a/encryptgpk/encryptgpk.cpp b/encryptgpk/encryptgpk.cpp
new file mode 100644
index 0000000..e389fef
--- /dev/null
+++ b/encryptgpk/encryptgpk.cpp
@@ -0,0 +1,442 @@
+/*
+ * File: encryptgpk.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdlib.h>
+#include <stdexcept>
+#include <stdio.h>
+#include "options.h"
+#include "EncoreBootImage.h"
+#include "smart_ptr.h"
+#include "Logging.h"
+#include "format_string.h"
+#include "Blob.h"
+#include "Random.h"
+#include "rijndael.h"
+
+using namespace elftosb;
+
+//! Size in bytes of the unencrypted group private key.
+#define GPK_LENGTH (40)
+
+//! Size in bytes of the encrypted output data. This size must be modulo 16, the chunk size for the
+//! AES-128 crypto algorithm. The group private key is inserted at offset 16.
+#define OUTPUT_DATA_LENGTH (64)
+
+//! Position in the output data of the first byte of the group private key.
+#define OUTPUT_DATA_GPK_OFFSET (16)
+
+//! The tool's name.
+const char k_toolName[] = "encryptgpk";
+
+//! Current version number for the tool.
+const char k_version[] = "1.0.2";
+
+//! Copyright string.
+const char k_copyright[] = "Copyright (c) 2008 Freescale Semiconductor. All rights reserved.";
+
+//! Default output array name.
+const char k_defaultArrayName[] = "_endDisplay";
+
+//! Definition of command line options.
+static const char * k_optionsDefinition[] = {
+ "?|help",
+ "v|version",
+ "k:key <file>",
+ "z|zero-key",
+ "o:output",
+ "p:prefix",
+ "a:array",
+ "d|debug",
+ "q|quiet",
+ "V|verbose",
+ NULL
+};
+
+//! Help string.
+const char k_usageText[] = "\nOptions:\n\
+ -?/--help Show this help\n\
+ -v/--version Display tool version\n\
+ -k/--key <file> Add OTP key used for decryption\n\
+ -z/--zero-key Add default key of all zeroes\n\
+ -o/--output <file> Write output to this file\n\
+ -p/--prefix <prefix> Set the output array prefix\n\
+ -a/--array <name> Specify the output array name\n\
+ -d/--debug Enable debug output\n\
+ -q/--quiet Output only warnings and errors\n\
+ -V/--verbose Print extra detailed log information\n\n";
+
+//! Init vector used for CBC encrypting the output data.
+static const uint8_t kInitVector[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+//! An array of strings.
+typedef std::vector<std::string> string_vector_t;
+
+// prototypes
+int main(int argc, char* argv[], char* envp[]);
+
+/*!
+ * \brief Class that encapsulates the sbtool interface.
+ *
+ * A single global logger instance is created during object construction. It is
+ * never freed because we need it up to the last possible minute, when an
+ * exception could be thrown.
+ */
+class encryptgpk
+{
+protected:
+ int m_argc; //!< Number of command line arguments.
+ char ** m_argv; //!< String value for each command line argument.
+ StdoutLogger * m_logger; //!< Singleton logger instance.
+ string_vector_t m_keyFilePaths; //!< Paths to OTP key files.
+ string_vector_t m_positionalArgs; //!< Arguments coming after explicit options.
+ bool m_isVerbose; //!< Whether the verbose flag was turned on.
+ bool m_useDefaultKey; //!< Include a default (zero) crypto key.
+ std::string m_outputPath; //!< Path to output file.
+ std::string m_gpkPath; //!< Path to input group private key file.
+ std::string m_outputPrefix; //!< Prefix to the output array.
+ std::string m_arrayName; //!< Output array's name.
+
+public:
+ /*!
+ * Constructor.
+ *
+ * Creates the singleton logger instance.
+ */
+ encryptgpk(int argc, char * argv[])
+ : m_argc(argc),
+ m_argv(argv),
+ m_logger(0),
+ m_keyFilePaths(),
+ m_positionalArgs(),
+ m_isVerbose(false),
+ m_useDefaultKey(false),
+ m_outputPath(),
+ m_gpkPath(),
+ m_outputPrefix(),
+ m_arrayName(k_defaultArrayName)
+ {
+ // create logger instance
+ m_logger = new StdoutLogger();
+ m_logger->setFilterLevel(Logger::INFO);
+ Log::setLogger(m_logger);
+ }
+
+ /*!
+ * Destructor.
+ */
+ ~encryptgpk()
+ {
+ }
+
+ /*!
+ * Reads the command line options passed into the constructor.
+ *
+ * This method can return a return code to its caller, which will cause the
+ * tool to exit immediately with that return code value. Normally, though, it
+ * will return -1 to signal that the tool should continue to execute and
+ * all options were processed successfully.
+ *
+ * The Options class is used to parse command line options. See
+ * #k_optionsDefinition for the list of options and #k_usageText for the
+ * descriptive help for each option.
+ *
+ * \retval -1 The options were processed successfully. Let the tool run normally.
+ * \return A zero or positive result is a return code value that should be
+ * returned from the tool as it exits immediately.
+ */
+ int processOptions()
+ {
+ Options options(*m_argv, k_optionsDefinition);
+ OptArgvIter iter(--m_argc, ++m_argv);
+
+ // process command line options
+ int optchar;
+ const char * optarg;
+ while (optchar = options(iter, optarg))
+ {
+ switch (optchar)
+ {
+ case '?':
+ printUsage(options);
+ return 0;
+
+ case 'v':
+ printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
+ return 0;
+
+ case 'k':
+ m_keyFilePaths.push_back(optarg);
+ break;
+
+ case 'z':
+ m_useDefaultKey = true;
+ break;
+
+ case 'o':
+ m_outputPath = optarg;
+ break;
+
+ case 'p':
+ m_outputPrefix = optarg;
+ break;
+
+ case 'a':
+ m_arrayName = optarg;
+ break;
+
+ case 'd':
+ Log::getLogger()->setFilterLevel(Logger::DEBUG);
+ break;
+
+ case 'q':
+ Log::getLogger()->setFilterLevel(Logger::WARNING);
+ break;
+
+ case 'V':
+ m_isVerbose = true;
+ break;
+
+ default:
+ Log::log(Logger::ERROR, "error: unrecognized option\n\n");
+ printUsage(options);
+ return 1;
+ }
+ }
+
+ // handle positional args
+ if (iter.index() < m_argc)
+ {
+// Log::SetOutputLevel leveler(Logger::DEBUG);
+// Log::log("positional args:\n");
+ int i;
+ for (i = iter.index(); i < m_argc; ++i)
+ {
+// Log::log("%d: %s\n", i - iter.index(), m_argv[i]);
+ m_positionalArgs.push_back(m_argv[i]);
+ }
+ }
+
+ // all is well
+ return -1;
+ }
+
+ /*!
+ * Prints help for the tool.
+ */
+ void printUsage(Options & options)
+ {
+ options.usage(std::cout, "gpk-file");
+ printf(k_usageText, k_toolName);
+ }
+
+ /*!
+ * Core of the tool. Calls processOptions() to handle command line options
+ * before performing the real work the tool does.
+ */
+ int run()
+ {
+ try
+ {
+ // read command line options
+ int result;
+ if ((result = processOptions()) != -1)
+ {
+ return result;
+ }
+
+ // set verbose logging
+ setVerboseLogging();
+
+ // make sure a file was provided
+ if (m_positionalArgs.size() < 1)
+ {
+ throw std::runtime_error("no input file path was provided");
+ }
+
+ // Make sure at least one key was specified.
+ if (m_keyFilePaths.size() == 0 && m_useDefaultKey == false)
+ {
+ throw std::runtime_error("no crypto key was specified");
+ }
+
+ // Do the work.
+ generateOutput();
+ }
+ catch (std::exception & e)
+ {
+ Log::log(Logger::ERROR, "error: %s\n", e.what());
+ return 1;
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /*!
+ * \brief Builds the output data blob, encrypts it, and writes it to the output file.
+ */
+ void generateOutput()
+ {
+ // Create the output data blob and set it to the correct size.
+ Blob data;
+ data.setLength(OUTPUT_DATA_LENGTH);
+
+ // Fill it with random values.
+ RandomNumberGenerator rng;
+ rng.generateBlock(data.getData(), OUTPUT_DATA_LENGTH);
+
+ // Read the GPK and overlay it into the output data.
+ // The first positional arg is the GPK file path.
+ Blob gpk = readGPK(m_positionalArgs[0]);
+ memcpy(data.getData() + OUTPUT_DATA_GPK_OFFSET, gpk.getData(), GPK_LENGTH);
+
+ // This is the key object for our crypto key.
+ AESKey<128> cryptoKey = readKeyFile();
+
+ // Read the key file.
+ // Encrypt the output data block.
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Encrypt, cryptoKey, Rijndael::Key16Bytes, (uint8_t *)&kInitVector);
+ cipher.blockEncrypt(data.getData(), OUTPUT_DATA_LENGTH * 8, data.getData());
+
+ // Open the output file.
+ std::ofstream outputStream(m_outputPath.c_str(), std::ios_base::out | std::ios_base::trunc);
+ if (!outputStream.is_open())
+ {
+ throw std::runtime_error(format_string("could not open output file %s", m_outputPath.c_str()));
+ }
+
+ writeCArray(outputStream, data);
+ }
+
+ /*!
+ * \brief Reads the group private key binary data.
+ */
+ Blob readGPK(std::string & path)
+ {
+ std::ifstream stream(path.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (!stream.is_open())
+ {
+ throw std::runtime_error("could not open group private key file");
+ }
+
+ Blob gpk;
+ gpk.setLength(GPK_LENGTH);
+
+ stream.read((char *)gpk.getData(), GPK_LENGTH);
+
+ return gpk;
+ }
+
+ /*!
+ * \brief Returns a key object based on the user's specified key.
+ */
+ AESKey<128> readKeyFile()
+ {
+ if (m_keyFilePaths.size() > 0)
+ {
+ // Open the key file.
+ std::string & keyPath = m_keyFilePaths[0];
+ std::ifstream keyStream(keyPath.c_str(), std::ios_base::in);
+ if (!keyStream.is_open())
+ {
+ throw std::runtime_error(format_string("unable to read key file %s\n", keyPath.c_str()));
+ }
+ keyStream.seekg(0);
+
+ // Read the first key in the file.
+ AESKey<128> key(keyStream);
+ return key;
+ }
+
+ // Otherwise, create a zero key and return it.
+ AESKey<128> defaultKey;
+ return defaultKey;
+
+ }
+
+ /*!
+ * \brief Writes the given data blob as an array in a C source file.
+ */
+ void writeCArray(std::ofstream & stream, const Blob & data)
+ {
+ const uint8_t * dataPtr = data.getData();
+ unsigned length = data.getLength();
+
+ // Write first line.
+ std::string text = format_string("%s%sunsigned char %s[%d] = {", m_outputPrefix.c_str(), m_outputPrefix.size() > 0 ? " " : "", m_arrayName.c_str(), length);
+ stream.write(text.c_str(), text.size());
+
+ // Write each word of the array.
+ unsigned i = 0;
+ while (i < length)
+ {
+ // Insert a comma at the end of the previous line unless this is the first word we're outputting.
+ text = format_string("%s\n 0x%02x", i == 0 ? "" : ",", (*dataPtr++) & 0xff);
+ stream.write(text.c_str(), text.size());
+
+ i++;
+ }
+
+ // Write last line, terminating the array.
+ text = "\n};\n\n";
+ stream.write(text.c_str(), text.size());
+ }
+
+ /*!
+ * \brief Turns on verbose logging.
+ */
+ void setVerboseLogging()
+ {
+ if (m_isVerbose)
+ {
+ // verbose only affects the INFO and DEBUG filter levels
+ // if the user has selected quiet mode, it overrides verbose
+ switch (Log::getLogger()->getFilterLevel())
+ {
+ case Logger::INFO:
+ Log::getLogger()->setFilterLevel(Logger::INFO2);
+ break;
+ case Logger::DEBUG:
+ Log::getLogger()->setFilterLevel(Logger::DEBUG2);
+ break;
+ }
+ }
+ }
+
+};
+
+/*!
+ * Main application entry point. Creates an sbtool instance and lets it take over.
+ */
+int main(int argc, char* argv[], char* envp[])
+{
+ try
+ {
+ return encryptgpk(argc, argv).run();
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+
diff --git a/keygen/Doxyfile b/keygen/Doxyfile
new file mode 100644
index 0000000..0b20ed1
--- /dev/null
+++ b/keygen/Doxyfile
@@ -0,0 +1,250 @@
+# Doxyfile 1.3.9
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = sbtool
+PROJECT_NUMBER = 1.0
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = YES
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH = "/Users/creed/projects/elftosb/sbtool" \
+ "/Users/creed/projects/sgtl/elftosb/sbtool" \
+ "/Users/creed/projects/elftosb/common" \
+ "/Users/creed/projects/sgtl/elftosb/common"
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 4
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . ../common
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/keygen/keygen.cpp b/keygen/keygen.cpp
new file mode 100644
index 0000000..b1b8362
--- /dev/null
+++ b/keygen/keygen.cpp
@@ -0,0 +1,346 @@
+/*
+ * File: keygen.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdlib.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include "options.h"
+#include "smart_ptr.h"
+#include "Logging.h"
+#include "AESKey.h"
+
+//! The tool's name.
+const char k_toolName[] = "keygen";
+
+//! Current version number for the tool.
+const char k_version[] = "1.0";
+
+//! Copyright string.
+const char k_copyright[] = "Copyright (c) 2006-2009 Freescale Semiconductor, Inc.\nAll rights reserved.";
+
+//! Definition of command line options.
+static const char * k_optionsDefinition[] = {
+ "?|help",
+ "v|version",
+ "q|quiet",
+ "V|verbose",
+ "n:number <int>",
+ NULL
+};
+
+//! Help string.
+const char k_usageText[] = "\nOptions:\n\
+ -?/--help Show this help\n\
+ -v/--version Display tool version\n\
+ -q/--quiet Output only warnings and errors\n\
+ -V/--verbose Print extra detailed log information\n\
+ -n/--number <int> Number of keys to generate per file (default=1)\n\n";
+
+//! An array of strings.
+typedef std::vector<std::string> string_vector_t;
+
+// prototypes
+int main(int argc, char* argv[], char* envp[]);
+
+/*!
+ * \brief Class that encapsulates the keygen interface.
+ *
+ * A single global logger instance is created during object construction. It is
+ * never freed because we need it up to the last possible minute, when an
+ * exception could be thrown.
+ */
+class keygen
+{
+protected:
+ int m_argc; //!< Number of command line arguments.
+ char ** m_argv; //!< String value for each command line argument.
+ StdoutLogger * m_logger; //!< Singleton logger instance.
+ string_vector_t m_positionalArgs; //!< Arguments coming after explicit options.
+ bool m_isVerbose; //!< Whether the verbose flag was turned on.
+ int m_keyCount; //!< Number of keys to generate.
+
+public:
+ /*!
+ * Constructor.
+ *
+ * Creates the singleton logger instance.
+ */
+ keygen(int argc, char * argv[])
+ : m_argc(argc),
+ m_argv(argv),
+ m_logger(0),
+ m_positionalArgs(),
+ m_isVerbose(false),
+ m_keyCount(1)
+ {
+ // create logger instance
+ m_logger = new StdoutLogger();
+ m_logger->setFilterLevel(Logger::INFO);
+ Log::setLogger(m_logger);
+ }
+
+ /*!
+ * Destructor.
+ */
+ ~keygen()
+ {
+ }
+
+ /*!
+ * Reads the command line options passed into the constructor.
+ *
+ * This method can return a return code to its caller, which will cause the
+ * tool to exit immediately with that return code value. Normally, though, it
+ * will return -1 to signal that the tool should continue to execute and
+ * all options were processed successfully.
+ *
+ * The Options class is used to parse command line options. See
+ * #k_optionsDefinition for the list of options and #k_usageText for the
+ * descriptive help for each option.
+ *
+ * \retval -1 The options were processed successfully. Let the tool run normally.
+ * \return A zero or positive result is a return code value that should be
+ * returned from the tool as it exits immediately.
+ */
+ int processOptions()
+ {
+ Options options(*m_argv, k_optionsDefinition);
+ OptArgvIter iter(--m_argc, ++m_argv);
+
+ // process command line options
+ int optchar;
+ const char * optarg;
+ while (optchar = options(iter, optarg))
+ {
+ switch (optchar)
+ {
+ case '?':
+ printUsage(options);
+ return 0;
+
+ case 'v':
+ printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
+ return 0;
+
+ case 'd':
+ Log::getLogger()->setFilterLevel(Logger::DEBUG);
+ break;
+
+ case 'q':
+ Log::getLogger()->setFilterLevel(Logger::WARNING);
+ break;
+
+ case 'V':
+ m_isVerbose = true;
+ break;
+
+ case 'n':
+ m_keyCount = strtol(optarg, NULL, 0);
+ break;
+
+ default:
+ Log::log(Logger::ERROR, "error: unrecognized option\n\n");
+ printUsage(options);
+ return 1;
+ }
+ }
+
+ // handle positional args
+ if (iter.index() < m_argc)
+ {
+// Log::SetOutputLevel leveler(Logger::DEBUG);
+// Log::log("positional args:\n");
+ int i;
+ for (i = iter.index(); i < m_argc; ++i)
+ {
+// Log::log("%d: %s\n", i - iter.index(), m_argv[i]);
+ m_positionalArgs.push_back(m_argv[i]);
+ }
+ }
+
+ // all is well
+ return -1;
+ }
+
+ /*!
+ * Prints help for the tool.
+ */
+ void printUsage(Options & options)
+ {
+ options.usage(std::cout, "key-files...");
+ printf(k_usageText, k_toolName);
+ }
+
+ /*!
+ * Core of the tool. Calls processOptions() to handle command line options
+ * before performing the real work the tool does.
+ */
+ int run()
+ {
+ try
+ {
+ // read command line options
+ int result;
+ if ((result = processOptions()) != -1)
+ {
+ return result;
+ }
+
+ // set verbose logging
+ setVerboseLogging();
+
+ // make sure a file was provided
+ if (m_positionalArgs.size() < 1)
+ {
+ throw std::runtime_error("no output file path was provided");
+ }
+
+ // generate key files
+ string_vector_t::const_iterator it = m_positionalArgs.begin();
+ for (; it != m_positionalArgs.end(); ++it)
+ {
+ generateKeyFile(*it);
+ }
+ }
+ catch (std::exception & e)
+ {
+ Log::log(Logger::ERROR, "error: %s\n", e.what());
+ return 1;
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /*!
+ * \brief Turns on verbose logging.
+ */
+ void setVerboseLogging()
+ {
+ if (m_isVerbose)
+ {
+ // verbose only affects the INFO and DEBUG filter levels
+ // if the user has selected quiet mode, it overrides verbose
+ switch (Log::getLogger()->getFilterLevel())
+ {
+ case Logger::INFO:
+ Log::getLogger()->setFilterLevel(Logger::INFO2);
+ break;
+ case Logger::DEBUG:
+ Log::getLogger()->setFilterLevel(Logger::DEBUG2);
+ break;
+ }
+ }
+ }
+
+ /*!
+ * \brief Opens the file at \a path and writes a random key file.
+ *
+ * Each key file will have #m_keyCount number of keys written into it,
+ * each on a line by itself.
+ */
+ void generateKeyFile(const std::string & path)
+ {
+ std::ofstream outputStream(path.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
+ if (outputStream.is_open())
+ {
+ int i;
+ for (i = 0; i < m_keyCount; ++i)
+ {
+ AESKey<128> key;
+ key.randomize();
+ key.writeToStream(outputStream);
+
+ // put a newline after the key
+ outputStream.write("\n", 1);
+
+ // dump it
+ dumpKey(key);
+ }
+
+ Log::log(Logger::INFO, "wrote key file %s\n", path.c_str());
+ }
+ else
+ {
+ throw std::runtime_error("could not open output file");
+ }
+ }
+
+ /*!
+ * \brief Write the value of each byte of the \a key to the log.
+ */
+ void dumpKey(const AESKey<128> & key)
+ {
+ // dump key bytes
+ Log::log(Logger::INFO2, "key bytes: ");
+ AESKey<128>::key_t the_key;
+ key.getKey(&the_key);
+ int q;
+ for (q=0; q<16; q++)
+ {
+ Log::log(Logger::INFO2, "%02x ", the_key[q]);
+ }
+ Log::log(Logger::INFO2, "\n");
+ }
+
+ /*!
+ * \brief Log an array of bytes as hex.
+ */
+ void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count)
+ {
+ Log::SetOutputLevel leveler(level);
+// Log::log(" ");
+ unsigned i;
+ for (i = 0; i < count; ++i, ++bytes)
+ {
+ if ((i % 16 == 0) && (i < count - 1))
+ {
+ if (i != 0)
+ {
+ Log::log("\n");
+ }
+ Log::log(" 0x%04x: ", i);
+ }
+ Log::log("%02x ", *bytes & 0xff);
+ }
+
+ Log::log("\n");
+ }
+
+};
+
+/*!
+ * Main application entry point. Creates an sbtool instance and lets it take over.
+ */
+int main(int argc, char* argv[], char* envp[])
+{
+ try
+ {
+ return keygen(argc, argv).run();
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..a98e71b
--- /dev/null
+++ b/makefile
@@ -0,0 +1,32 @@
+#*******************************************************************************
+# makefile
+# Description:
+# gnu make makefile for elftosb executable
+
+#*******************************************************************************
+# Environment
+
+# UNAMES is going to be set to either "Linux" or "CYGWIN_NT-5.1"
+UNAMES = $(shell uname -s)
+
+ifeq ("${UNAMES}", "Linux")
+
+SRC_DIR = $(shell pwd)
+BUILD_DIR = bld/linux
+
+else
+ifeq ("${UNAMES}", "CYGWIN_NT-5.1")
+
+SRC_DIR = $(shell pwd)
+BUILD_DIR = bld/cygwin
+
+endif
+endif
+
+
+#*******************************************************************************
+# Targets
+
+all clean elftosb sbtool keygen:
+ @mkdir -p ${BUILD_DIR};
+ make -C ${BUILD_DIR} -f ${SRC_DIR}/makefile.rules SRC_DIR=${SRC_DIR} $@;
diff --git a/makefile.rules b/makefile.rules
new file mode 100644
index 0000000..9cd649e
--- /dev/null
+++ b/makefile.rules
@@ -0,0 +1,178 @@
+#*******************************************************************************
+# makefile.rules
+# Description:
+# gnu make makefile rules for elftosb executable. make needs to be called
+# with the following command:
+#
+# make -C ${BUILD_DIR} -f ${SRC_DIR}/makefile.rules SRC_DIR=${SRC_DIR} $@;
+#
+# SRC_DIR needs to be passed in. It is assumed that make is running in
+# the build directory.
+
+#*******************************************************************************
+# Environment
+
+# UNAMES is going to be set to either "Linux" or "CYGWIN_NT-5.1"
+UNAMES = $(shell uname -s)
+
+#*******************************************************************************
+# Directories
+
+#*******************************************************************************
+# Paths
+
+# search path for source files. make finds them automatically.
+VPATH = \
+ ${SRC_DIR}/common \
+ ${SRC_DIR}/elftosb2 \
+ ${SRC_DIR}/sbtool \
+ ${SRC_DIR}/keygen
+
+# include directories
+INC_PATH = \
+ -I${SRC_DIR}/elftosb2 \
+ -I${SRC_DIR}/keygen \
+ -I${SRC_DIR}/sbtool \
+ -I${SRC_DIR}/common
+
+#*******************************************************************************
+# Build flags
+# gcc Compiler flags
+# -g : Produce debugging information.
+
+CFLAGS = -g $(INC_PATH) -D${UNAMES}
+
+#*******************************************************************************
+# File lists
+
+OBJ_FILES_COMMON = \
+ AESKey.o \
+ Blob.o \
+ crc.o \
+ DataSource.o \
+ DataTarget.o \
+ ELFSourceFile.o \
+ EncoreBootImage.o \
+ EvalContext.o \
+ GHSSecInfo.o \
+ GlobMatcher.o \
+ HexValues.o \
+ Logging.o \
+ Operation.o \
+ OptionDictionary.o \
+ options.o \
+ OutputSection.o \
+ Random.o \
+ RijndaelCBCMAC.o \
+ rijndael.o \
+ SHA1.o \
+ SourceFile.o \
+ SRecordSourceFile.o \
+ stdafx.o \
+ StELFFile.o \
+ StExecutableImage.o \
+ StSRecordFile.o \
+ Value.o \
+ Version.o \
+ format_string.o \
+ ExcludesListMatcher.o \
+ SearchPath.o \
+ DataSourceImager.o \
+ IVTDataSource.o
+
+OBJ_FILES_ELFTOSB2 = \
+ ${OBJ_FILES_COMMON} \
+ BootImageGenerator.o \
+ ConversionController.o \
+ ElftosbAST.o \
+ elftosb.o \
+ elftosb_lexer.o \
+ ElftosbLexer.o \
+ elftosb_parser.tab.o \
+ EncoreBootImageGenerator.o
+
+OBJ_FILES_SBTOOL = \
+ ${OBJ_FILES_COMMON} \
+ EncoreBootImageReader.o \
+ sbtool.o
+
+OBJ_FILES_KEYGEN = \
+ ${OBJ_FILES_COMMON} \
+ keygen.o
+
+
+LIBS = -lstdc++
+
+
+ifeq ("${UNAMES}", "Linux")
+EXEC_FILE_ELFTOSB2 = elftosb
+EXEC_FILE_SBTOOL = sbtool
+EXEC_FILE_KEYGEN = keygen
+else
+ifeq ("${UNAMES}", "CYGWIN_NT-5.1")
+EXEC_FILE_ELFTOSB2 = elftosb.exe
+EXEC_FILE_SBTOOL = sbtool.exe
+EXEC_FILE_KEYGEN = keygen.exe
+endif # ifeq ("${UNAMES}", "CYGWIN_NT-5.1")
+endif # ifeq ("${UNAMES}", "Linux")
+
+
+#*******************************************************************************
+# Targets
+
+all: elftosb sbtool keygen
+
+# Uncomment the next line to print out the environment variables.
+all: exec_always
+
+exec_always:
+ @echo "SRC_DIR = ${SRC_DIR}"
+ @echo "OBJ_FILES = ${OBJ_FILES_ELFTOSB2}"
+ @echo "LIBS = ${LIBS}"
+ @echo "EXEC_FILE = ${EXEC_FILE}"
+ @echo "BUILD_DIR = ${BUILD_DIR}"
+
+clean:
+ rm -f ${OBJ_FILES_ELFTOSB2} ${OBJ_FILES_SBTOOL} ${OBJ_FILES_KEYGEN} \
+ ${EXEC_FILE_ELFTOSB2} ${EXEC_FILE_SBTOOL} ${EXEC_FILE_KEYGEN}
+
+elftosb: ${OBJ_FILES_ELFTOSB2}
+ gcc ${OBJ_FILES_ELFTOSB2} ${LIBS} -o ${EXEC_FILE_ELFTOSB2}
+
+sbtool: ${OBJ_FILES_SBTOOL}
+ gcc ${OBJ_FILES_SBTOOL} ${LIBS} -o ${EXEC_FILE_SBTOOL}
+
+keygen: ${OBJ_FILES_KEYGEN}
+ gcc ${OBJ_FILES_KEYGEN} ${LIBS} -o ${EXEC_FILE_KEYGEN}
+
+
+#ifeq ("${UNAMES}", "Linux")
+#ifeq ("${UNAMES}", "Linux")
+# Use default rules for creating all the .o files from the .c files. Only
+# for linux
+.SUFFIXES : .c .cpp
+
+.c.o :
+ gcc ${CFLAGS} -c $<
+
+.cpp.o :
+ gcc ${CFLAGS} -c $<
+
+#endif
+
+#*******************************************************************************
+# Automatic dependency generation
+
+%.d: %.c
+ @set -e; \
+ $(CC) -MM $(CFLAGS) $< | \
+ sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+ [ -s $@ ] || rm -f $@
+
+%.d: %.cpp
+ @set -e; \
+ $(CC) -MM $(CFLAGS) $< | \
+ sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+ [ -s $@ ] || rm -f $@
+
+#*******************************************************************************
diff --git a/sbtool/Doxyfile b/sbtool/Doxyfile
new file mode 100644
index 0000000..0b20ed1
--- /dev/null
+++ b/sbtool/Doxyfile
@@ -0,0 +1,250 @@
+# Doxyfile 1.3.9
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = sbtool
+PROJECT_NUMBER = 1.0
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = YES
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH = "/Users/creed/projects/elftosb/sbtool" \
+ "/Users/creed/projects/sgtl/elftosb/sbtool" \
+ "/Users/creed/projects/elftosb/common" \
+ "/Users/creed/projects/sgtl/elftosb/common"
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 4
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . ../common
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/sbtool/EncoreBootImageReader.cpp b/sbtool/EncoreBootImageReader.cpp
new file mode 100644
index 0000000..b6eb474
--- /dev/null
+++ b/sbtool/EncoreBootImageReader.cpp
@@ -0,0 +1,370 @@
+/*
+ * File: EncoreBootImageReader.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "EncoreBootImageReader.h"
+#include "SHA1.h"
+#include "rijndael.h"
+#include "RijndaelCBCMAC.h"
+#include <assert.h>
+#include "EndianUtilities.h"
+#include "Logging.h"
+
+using namespace elftosb;
+
+//! \post Stream head points to just after the image header.
+//! \exception read_error Thrown if the image header is invalid.
+void EncoreBootImageReader::readImageHeader()
+{
+ // seek to beginning of the stream/file and read the plaintext header
+ m_stream.seekg(0, std::ios_base::beg);
+ if (m_stream.read((char *)&m_header, sizeof(m_header)).bad())
+ {
+ throw read_error("failed to read image header");
+ }
+
+ m_header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_flags);
+ m_header.m_imageBlocks = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_imageBlocks);
+ m_header.m_firstBootTagBlock = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootTagBlock);
+ m_header.m_firstBootableSectionID = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootableSectionID);
+ m_header.m_keyCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyCount);
+ m_header.m_keyDictionaryBlock = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyDictionaryBlock);
+ m_header.m_headerBlocks = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_headerBlocks);
+ m_header.m_sectionCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionCount);
+ m_header.m_sectionHeaderSize = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionHeaderSize);
+ m_header.m_timestamp = ENDIAN_LITTLE_TO_HOST_U64(m_header.m_timestamp);
+
+// m_header.m_componentVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_major);
+// m_header.m_componentVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_minor);
+// m_header.m_componentVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_revision);
+
+// m_header.m_productVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_major);
+// m_header.m_productVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_minor);
+// m_header.m_productVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_revision);
+
+ // check header signature 1
+ if (m_header.m_signature[0] != 'S' || m_header.m_signature[1] != 'T' || m_header.m_signature[2] != 'M' || m_header.m_signature[3] != 'P')
+ {
+ throw read_error("invalid signature 1");
+ }
+
+ // check header signature 2 for version 1.1 and greater
+ if ((m_header.m_majorVersion > 1 || (m_header.m_majorVersion == 1 && m_header.m_minorVersion >= 1)) && (m_header.m_signature2[0] != 's' || m_header.m_signature2[1] != 'g' || m_header.m_signature2[2] != 't' || m_header.m_signature2[3] != 'l'))
+ {
+// throw read_error("invalid signature 2");
+ Log::log(Logger::WARNING, "warning: invalid signature 2\n");
+ }
+}
+
+//! \pre The image header must have already been read with a call to readImageHeader().
+//!
+void EncoreBootImageReader::computeHeaderDigest(sha1_digest_t & digest)
+{
+ CSHA1 hash;
+ hash.Reset();
+ hash.Update((uint8_t *)&m_header.m_signature, sizeof(m_header) - sizeof(sha1_digest_t));
+ hash.Final();
+ hash.GetHash(digest);
+}
+
+//! \pre The image header must have already been read.
+//! \pre The DEK must have been found already.
+//! \post The stream head is at the end of the digest.
+void EncoreBootImageReader::readImageDigest()
+{
+ unsigned digestPosition = sizeOfCipherBlocks(m_header.m_imageBlocks - 2);
+ m_stream.seekg(digestPosition, std::ios_base::beg);
+
+ // read the two cipher blocks containing the digest, including padding
+ cipher_block_t digestBlocks[2];
+ if (m_stream.read((char *)&digestBlocks, sizeof(digestBlocks)).bad())
+ {
+ throw read_error("failed to read image digest");
+ }
+
+ // decrypt the digest
+ if (isEncrypted())
+ {
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
+ cipher.blockDecrypt((uint8_t *)&digestBlocks, sizeof(digestBlocks) * 8, (uint8_t *)&digestBlocks);
+ }
+
+ // copy the digest out of the padded blocks
+ memcpy(m_digest, &digestBlocks, sizeof(m_digest));
+}
+
+//! \pre The image header must have already been read with a call to readImageHeader().
+//! \post The stream head is at the end of the image minus the last two cipher blocks.
+//! \param digest Where to store the resulting digest.
+//! \exception read_error Thrown if the image header is invalid.
+void EncoreBootImageReader::computeImageDigest(sha1_digest_t & digest)
+{
+ m_stream.seekg(0, std::ios_base::beg);
+
+ CSHA1 hash;
+ hash.Reset();
+
+ unsigned blockCount = m_header.m_imageBlocks - 2; // exclude digest at end of image
+ while (blockCount--)
+ {
+ cipher_block_t block;
+ if (m_stream.read((char *)&block, sizeof(block)).bad())
+ {
+ throw read_error("failed to read block while computing image digest");
+ }
+ hash.Update(block, sizeof(block));
+ }
+
+ hash.Final();
+ hash.GetHash(digest);
+}
+
+//! \pre Image header must have been read before this method is called.
+//!
+void EncoreBootImageReader::readSectionTable()
+{
+ // seek to the table
+ m_stream.seekg(sizeOfCipherBlocks(m_header.m_headerBlocks), std::ios_base::beg);
+
+ unsigned sectionCount = m_header.m_sectionCount;
+ while (sectionCount--)
+ {
+ EncoreBootImage::section_header_t header;
+ if (m_stream.read((char *)&header, sizeof(header)).bad())
+ {
+ throw read_error("failed to read section header");
+ }
+
+ // swizzle section header
+ header.m_tag = ENDIAN_LITTLE_TO_HOST_U32(header.m_tag);
+ header.m_offset = ENDIAN_LITTLE_TO_HOST_U32(header.m_offset);
+ header.m_length = ENDIAN_LITTLE_TO_HOST_U32(header.m_length);
+ header.m_flags = ENDIAN_LITTLE_TO_HOST_U32(header.m_flags);
+
+ m_sections.push_back(header);
+ }
+}
+
+//! Requires that an OTP key has been provided as the sole argument. Passing the
+//! key into this method lets the caller search the key dictionary for any number
+//! of keys and determine which are valid. If \a kek is found in the dictionary,
+//! the decrypted DEK is saved and true is returned. A result of false means
+//! that \a kek was not found.
+//!
+//! \pre The image header and section table must have been read already.
+//! \post The stream head points somewhere inside the key dictionary, or just after it.
+//! \post If the search was successful, the #m_dek member will contain the decrypted
+//! session key. Otherwise #m_dek is not modified.
+//! \param kek Search for this KEK in the dictionary.
+//! \retval true The DEK was found and decrypted. True is also returned when the
+//! image is not encrypted at all.
+//! \retval false No matching key entry was found. The image cannot be decrypted.
+bool EncoreBootImageReader::readKeyDictionary(const AESKey<128> & kek)
+{
+ // do nothing if the image is not encrypted
+ if (!isEncrypted())
+ {
+ return true;
+ }
+
+ // first compute a CBC-MAC over the image header with our KEK
+ RijndaelCBCMAC mac(kek);
+ mac.update((const uint8_t *)&m_header, sizeof(m_header));
+
+ // run the CBC-MAC over each entry in the section table too
+ section_array_t::iterator it = m_sections.begin();
+ for (; it != m_sections.end(); ++it)
+ {
+ mac.update((const uint8_t *)&(*it), sizeof(EncoreBootImage::section_header_t));
+ }
+
+ // get the CBC-MAC result
+ mac.finalize();
+ const RijndaelCBCMAC::block_t & macResult = mac.getMAC();
+
+ // seek to the key dictionary
+ m_stream.seekg(sizeOfCipherBlocks(m_header.m_keyDictionaryBlock), std::ios_base::beg);
+
+ // decipher each key entry
+ unsigned entries = m_header.m_keyCount;
+ while (entries--)
+ {
+ // read the entry
+ EncoreBootImage::dek_dictionary_entry_t entry;
+ if (m_stream.read((char *)&entry, sizeof(entry)).bad())
+ {
+ throw read_error("failed to read key dictionary entry");
+ }
+
+ // compare the CBC-MAC we computed with the one in this entry
+ if (memcmp(macResult, entry.m_mac, sizeof(cipher_block_t)) == 0)
+ {
+ // it's a match! now decrypt this entry's key in place
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Decrypt, kek, Rijndael::Key16Bytes, m_header.m_iv);
+ cipher.blockDecrypt(entry.m_dek, sizeof(entry.m_dek) * 8, entry.m_dek);
+
+ m_dek = entry.m_dek;
+ memset(entry.m_dek, 0, sizeof(entry.m_dek)); // wipe the key value from memory
+ return true;
+ }
+ }
+
+ // if we exit the loop normally then no matching MAC was found
+ return false;
+}
+
+//! Before the boot tag is added to the #m_bootTags member, some basic checks are performed.
+//! The command tag field is checked to make sure it matches #ROM_TAG_CMD. And
+//! the checksum field is verified to be sure it's correct.
+//!
+//! After the call to this method returns, the array of boot tags is accessible
+//! with the getBootTags() method. The array is sorted in the order in which
+//! the boot tags appeared in the image.
+//!
+//! \pre Image header must have been read.
+//! \pre Key dictionary must have been read and a valid DEK found.
+//! \post The stream head is left pointing just after the last boot tag.
+//! \exception read_error A failure to read the boot tag, or a failure on one
+//! of the consistency checks will cause this exception to be thrown.
+void EncoreBootImageReader::readBootTags()
+{
+ assert(m_header.m_firstBootTagBlock != 0);
+
+ unsigned bootTagOffset = m_header.m_firstBootTagBlock;
+
+ while (1)
+ {
+ // seek to this boot tag and read it into a temporary buffer
+ EncoreBootImage::boot_command_t header;
+ m_stream.seekg(sizeOfCipherBlocks(bootTagOffset), std::ios_base::beg);
+ if (m_stream.read((char *)&header, sizeof(header)).bad())
+ {
+ throw read_error("failed to read boot tag");
+ }
+
+ // swizzle to command header
+ header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(header.m_flags);
+ header.m_address = ENDIAN_LITTLE_TO_HOST_U32(header.m_address);
+ header.m_count = ENDIAN_LITTLE_TO_HOST_U32(header.m_count);
+ header.m_data = ENDIAN_LITTLE_TO_HOST_U32(header.m_data);
+
+ // decrypt in place
+ if (isEncrypted())
+ {
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
+ cipher.blockDecrypt((uint8_t *)&header, sizeof(header) * 8, (uint8_t *)&header);
+ }
+
+ // perform some basic checks
+ if (header.m_tag != EncoreBootImage::ROM_TAG_CMD)
+ {
+ throw read_error("boot tag is wrong command type");
+ }
+
+ uint8_t checksum = calculateCommandChecksum(header);
+ if (checksum != header.m_checksum)
+ {
+ throw read_error("boot tag checksum is invalid");
+ }
+
+ // save this boot tag
+ m_bootTags.push_back(header);
+
+ // and finally, update offset and break out of loop
+ bootTagOffset += header.m_count + 1; // include this boot tag in offset
+ if (header.m_flags & EncoreBootImage::ROM_LAST_TAG || bootTagOffset >= m_header.m_imageBlocks - 2)
+ {
+ break;
+ }
+ }
+}
+
+uint8_t EncoreBootImageReader::calculateCommandChecksum(EncoreBootImage::boot_command_t & header)
+{
+ uint8_t * bytes = reinterpret_cast<uint8_t *>(&header);
+ uint8_t checksum = 0x5a;
+ int i;
+
+ // start at one to skip checksum field
+ for (i = 1; i < sizeof(header); ++i)
+ {
+ checksum += bytes[i];
+ }
+
+ return checksum;
+}
+
+//! \param index The index of the section to read.
+//!
+//! \pre Both the image header and section table must have been read already before
+//! calling this method.
+//! \exception read_error This exception is raised if the stream reports an error while
+//! trying to read from the section.
+EncoreBootImage::Section * EncoreBootImageReader::readSection(unsigned index)
+{
+ // look up section header
+ assert(index < m_sections.size());
+ EncoreBootImage::section_header_t & header = m_sections[index];
+
+ // seek to the section
+ m_stream.seekg(sizeOfCipherBlocks(header.m_offset), std::ios_base::beg);
+
+ uint8_t * contents = NULL;
+ try
+ {
+ // allocate memory for the section contents and read the whole thing
+ unsigned contentLength = sizeOfCipherBlocks(header.m_length);
+ contents = new uint8_t[contentLength];
+ if (m_stream.read((char *)contents, contentLength).bad())
+ {
+ throw read_error("failed to read section");
+ }
+
+ // decrypt the entire section at once, if the image is encrypted and
+ // the cleartext flag is not set
+ if (isEncrypted() && (header.m_flags & EncoreBootImage::ROM_SECTION_CLEARTEXT) == 0)
+ {
+ Rijndael cipher;
+ cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
+ cipher.blockDecrypt(contents, contentLength * 8, contents);
+ }
+
+ // create section object
+ EncoreBootImage::Section * resultSection = NULL;
+ if (header.m_flags & EncoreBootImage::ROM_SECTION_BOOTABLE)
+ {
+ // a boot command section.
+ EncoreBootImage::BootSection * bootSection = new EncoreBootImage::BootSection(header.m_tag);
+
+ bootSection->fillFromData((cipher_block_t *)contents, header.m_length);
+
+ resultSection = bootSection;
+ }
+ else
+ {
+ // this is a raw data section
+ EncoreBootImage::DataSection * dataSection = new EncoreBootImage::DataSection(header.m_tag);
+ dataSection->setDataNoCopy(contents, contentLength);
+ contents = NULL;
+ resultSection = dataSection;
+ }
+
+ return resultSection;
+ }
+ catch (...)
+ {
+ if (contents)
+ {
+ delete [] contents;
+ }
+ throw;
+ }
+}
+
+
diff --git a/sbtool/EncoreBootImageReader.h b/sbtool/EncoreBootImageReader.h
new file mode 100644
index 0000000..6150a92
--- /dev/null
+++ b/sbtool/EncoreBootImageReader.h
@@ -0,0 +1,117 @@
+/*
+ * File: EncoreBootImageReader.h
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+#if !defined(_EncoreBootImageReader_h_)
+#define _EncoreBootImageReader_h_
+
+#include "EncoreBootImage.h"
+
+namespace elftosb
+{
+
+/*!
+ * \brief Reads a Piano/Encore boot image from an input stream.
+ */
+class EncoreBootImageReader
+{
+public:
+ /*!
+ * \brief Exception class used for error found while reading a boot image.
+ */
+ class read_error : public std::runtime_error
+ {
+ public:
+ //! \brief Constructor.
+ read_error(const std::string & msg) : std::runtime_error(msg) {}
+ };
+
+ //! \brief An array of section headers.
+ typedef std::vector<EncoreBootImage::section_header_t> section_array_t;
+
+ //! \brief An array of boot tags.
+ typedef std::vector<EncoreBootImage::boot_command_t> boot_tag_array_t;
+
+public:
+ //! \brief Default constructor.
+ EncoreBootImageReader(std::istream & stream) : m_stream(stream) {}
+
+ //! \brief Destructor.
+ virtual ~EncoreBootImageReader() {}
+
+ //! \name Decryption key
+ //! These methods provide access to the Data Encryption Key (DEK). Normally
+ //! the DEK is discovered using the readKeyDictionary() method.
+ //@{
+ inline void setKey(const AESKey<128> & key) { m_dek = key; }
+ inline const AESKey<128> & getKey() const { return m_dek; }
+ //@}
+
+ //! \name Readers
+ //! This group of methods is responsible for reading and parsing different
+ //! pieces and parts of the boot image file.
+ //@{
+ //! \brief Reads the header from the image.
+ void readImageHeader();
+
+ //! \brief Computes the actual SHA-1 digest of the image header.
+ void computeHeaderDigest(sha1_digest_t & digest);
+
+ //! \brief Reads the digest at the end of the image.
+ void readImageDigest();
+
+ //! \brief Run a SHA-1 digest over the entire image.
+ void computeImageDigest(sha1_digest_t & digest);
+
+ //! \brief Read the plaintext section table entries.
+ void readSectionTable();
+
+ //! \brief Reads the key dictionary, if the image is encrypted.
+ bool readKeyDictionary(const AESKey<128> & kek);
+
+ //! \brief
+ void readBootTags();
+
+ //! \brief
+ EncoreBootImage::Section * readSection(unsigned index);
+ //@}
+
+ //! \name Accessors
+ //! Information retrieved with reader methods is accessible through
+ //! these methods.
+ //@{
+ //! \brief Returns whether the image is encrypted or not.
+ //! \pre The header must have been read already.
+ inline bool isEncrypted() const { return m_header.m_keyCount > 0; }
+
+ //! \brief Returns a reference to the image's header.
+ const EncoreBootImage::boot_image_header_t & getHeader() const { return m_header; }
+
+ //! \brief Returns a reference to the SHA-1 digest read from the image.
+ const sha1_digest_t & getDigest() const { return m_digest; }
+
+ //! \brief Returns a reference to the STL container holding the section headers.
+ inline const section_array_t & getSections() const { return m_sections; }
+
+ //! \brief Returns a reference to the STL container holding the boot tags.
+ inline const boot_tag_array_t & getBootTags() const { return m_bootTags; }
+ //@}
+
+protected:
+ std::istream & m_stream; //!< The input stream to read the image from.
+ AESKey<128> m_dek; //!< DEK (data encryption key) read from the key dictionary.
+ EncoreBootImage::boot_image_header_t m_header; //!< Header from the boot image.
+ sha1_digest_t m_digest; //!< SHA-1 digest as read from the image.
+ section_array_t m_sections; //!< The section table.
+ boot_tag_array_t m_bootTags; //!< The array of boot tags read from the image.
+
+protected:
+ //! \brief Calculates the 8-bit checksum on a boot command header.
+ uint8_t calculateCommandChecksum(EncoreBootImage::boot_command_t & header);
+};
+
+}; // namespace elftosb
+
+#endif // _EncoreBootImageReader_h_
diff --git a/sbtool/sbtool.cpp b/sbtool/sbtool.cpp
new file mode 100644
index 0000000..c83cee2
--- /dev/null
+++ b/sbtool/sbtool.cpp
@@ -0,0 +1,626 @@
+/*
+ * File: sbtool.cpp
+ *
+ * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
+ * See included license file for license details.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdlib.h>
+#include <stdexcept>
+#include <stdio.h>
+#include "options.h"
+#include "EncoreBootImage.h"
+#include "smart_ptr.h"
+#include "Logging.h"
+#include "EncoreBootImageReader.h"
+#include "format_string.h"
+
+using namespace elftosb;
+
+//! The tool's name.
+const char k_toolName[] = "sbtool";
+
+//! Current version number for the tool.
+const char k_version[] = "1.1.4";
+
+//! Copyright string.
+const char k_copyright[] = "Copyright (c) 2006-2010 Freescale Semiconductor, Inc.\nAll rights reserved.";
+
+//! Definition of command line options.
+static const char * k_optionsDefinition[] = {
+ "?|help",
+ "v|version",
+ "k:key <file>",
+ "z|zero-key",
+ "x:extract",
+ "b|binary",
+ "d|debug",
+ "q|quiet",
+ "V|verbose",
+ NULL
+};
+
+//! Help string.
+const char k_usageText[] = "\nOptions:\n\
+ -?/--help Show this help\n\
+ -v/--version Display tool version\n\
+ -k/--key <file> Add OTP key used for decryption\n\
+ -z/--zero-key Add default key of all zeroes\n\
+ -x/--extract <index> Extract section number <index>\n\
+ -b/--binary Extract section data as binary\n\
+ -d/--debug Enable debug output\n\
+ -q/--quiet Output only warnings and errors\n\
+ -V/--verbose Print extra detailed log information\n\n";
+
+//! An array of strings.
+typedef std::vector<std::string> string_vector_t;
+
+// prototypes
+int main(int argc, char* argv[], char* envp[]);
+
+/*!
+ * \brief Class that encapsulates the sbtool interface.
+ *
+ * A single global logger instance is created during object construction. It is
+ * never freed because we need it up to the last possible minute, when an
+ * exception could be thrown.
+ */
+class sbtool
+{
+protected:
+ int m_argc; //!< Number of command line arguments.
+ char ** m_argv; //!< String value for each command line argument.
+ StdoutLogger * m_logger; //!< Singleton logger instance.
+ string_vector_t m_keyFilePaths; //!< Paths to OTP key files.
+ string_vector_t m_positionalArgs; //!< Arguments coming after explicit options.
+ bool m_isVerbose; //!< Whether the verbose flag was turned on.
+ bool m_useDefaultKey; //!< Include a default (zero) crypto key.
+ bool m_doExtract; //!< True if extract mode is on.
+ unsigned m_sectionIndex; //!< Index of section to extract.
+ bool m_extractBinary; //!< True if extraction output is binary, false for hex.
+ smart_ptr<EncoreBootImageReader> m_reader; //!< Boot image reader object.
+
+public:
+ /*!
+ * Constructor.
+ *
+ * Creates the singleton logger instance.
+ */
+ sbtool(int argc, char * argv[])
+ : m_argc(argc),
+ m_argv(argv),
+ m_logger(0),
+ m_keyFilePaths(),
+ m_positionalArgs(),
+ m_isVerbose(false),
+ m_useDefaultKey(false),
+ m_doExtract(false),
+ m_sectionIndex(0),
+ m_extractBinary(false),
+ m_reader()
+ {
+ // create logger instance
+ m_logger = new StdoutLogger();
+ m_logger->setFilterLevel(Logger::INFO);
+ Log::setLogger(m_logger);
+ }
+
+ /*!
+ * Destructor.
+ */
+ ~sbtool()
+ {
+ }
+
+ /*!
+ * Reads the command line options passed into the constructor.
+ *
+ * This method can return a return code to its caller, which will cause the
+ * tool to exit immediately with that return code value. Normally, though, it
+ * will return -1 to signal that the tool should continue to execute and
+ * all options were processed successfully.
+ *
+ * The Options class is used to parse command line options. See
+ * #k_optionsDefinition for the list of options and #k_usageText for the
+ * descriptive help for each option.
+ *
+ * \retval -1 The options were processed successfully. Let the tool run normally.
+ * \return A zero or positive result is a return code value that should be
+ * returned from the tool as it exits immediately.
+ */
+ int processOptions()
+ {
+ Options options(*m_argv, k_optionsDefinition);
+ OptArgvIter iter(--m_argc, ++m_argv);
+
+ // process command line options
+ int optchar;
+ const char * optarg;
+ while (optchar = options(iter, optarg))
+ {
+ switch (optchar)
+ {
+ case '?':
+ printUsage(options);
+ return 0;
+
+ case 'v':
+ printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
+ return 0;
+
+ case 'k':
+ m_keyFilePaths.push_back(optarg);
+ break;
+
+ case 'z':
+ m_useDefaultKey = true;
+ break;
+
+ case 'x':
+ m_doExtract = true;
+ m_sectionIndex = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'b':
+ m_extractBinary = true;
+ Log::getLogger()->setFilterLevel(Logger::WARNING);
+ break;
+
+ case 'd':
+ Log::getLogger()->setFilterLevel(Logger::DEBUG);
+ break;
+
+ case 'q':
+ Log::getLogger()->setFilterLevel(Logger::WARNING);
+ break;
+
+ case 'V':
+ m_isVerbose = true;
+ break;
+
+ default:
+ Log::log(Logger::ERROR, "error: unrecognized option\n\n");
+ printUsage(options);
+ return 1;
+ }
+ }
+
+ // handle positional args
+ if (iter.index() < m_argc)
+ {
+// Log::SetOutputLevel leveler(Logger::DEBUG);
+// Log::log("positional args:\n");
+ int i;
+ for (i = iter.index(); i < m_argc; ++i)
+ {
+// Log::log("%d: %s\n", i - iter.index(), m_argv[i]);
+ m_positionalArgs.push_back(m_argv[i]);
+ }
+ }
+
+ // all is well
+ return -1;
+ }
+
+ /*!
+ * Prints help for the tool.
+ */
+ void printUsage(Options & options)
+ {
+ options.usage(std::cout, "sb-file");
+ printf(k_usageText, k_toolName);
+ }
+
+ /*!
+ * Core of the tool. Calls processOptions() to handle command line options
+ * before performing the real work the tool does.
+ */
+ int run()
+ {
+ try
+ {
+ // read command line options
+ int result;
+ if ((result = processOptions()) != -1)
+ {
+ return result;
+ }
+
+ // set verbose logging
+ setVerboseLogging();
+
+ // make sure a file was provided
+ if (m_positionalArgs.size() < 1)
+ {
+ throw std::runtime_error("no sb file path was provided");
+ }
+
+ // read the boot image
+ readBootImage();
+ }
+ catch (std::exception & e)
+ {
+ Log::log(Logger::ERROR, "error: %s\n", e.what());
+ return 1;
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /*!
+ * \brief Turns on verbose logging.
+ */
+ void setVerboseLogging()
+ {
+ if (m_isVerbose)
+ {
+ // verbose only affects the INFO and DEBUG filter levels
+ // if the user has selected quiet mode, it overrides verbose
+ switch (Log::getLogger()->getFilterLevel())
+ {
+ case Logger::INFO:
+ Log::getLogger()->setFilterLevel(Logger::INFO2);
+ break;
+ case Logger::DEBUG:
+ Log::getLogger()->setFilterLevel(Logger::DEBUG2);
+ break;
+ }
+ }
+ }
+
+ /*!
+ * \brief Opens and reads the boot image identified on the command line.
+ * \pre At least one position argument must be present.
+ */
+ void readBootImage()
+ {
+ Log::SetOutputLevel infoLevel(Logger::INFO);
+
+ // open the sb file stream
+ std::ifstream sbStream(m_positionalArgs[0].c_str(), std::ios_base::binary | std::ios_base::in);
+ if (!sbStream.is_open())
+ {
+ throw std::runtime_error("failed to open input file");
+ }
+
+ // create the boot image reader
+ m_reader = new EncoreBootImageReader(sbStream);
+
+ // read image header
+ m_reader->readImageHeader();
+ const EncoreBootImage::boot_image_header_t & header = m_reader->getHeader();
+ if (header.m_majorVersion > 1)
+ {
+ throw std::runtime_error(format_string("boot image format version is too new (format version %d.%d)\n", header.m_majorVersion, header.m_minorVersion));
+ }
+ Log::log("---- Boot image header ----\n");
+ dumpImageHeader(header);
+
+ // compute SHA-1 over image header and test against the digest stored in the header
+ sha1_digest_t computedDigest;
+ m_reader->computeHeaderDigest(computedDigest);
+ if (compareDigests(computedDigest, m_reader->getHeader().m_digest))
+ {
+ Log::log("Header digest is correct.\n");
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: stored SHA-1 header digest does not match the actual header digest\n");
+ Log::log(Logger::WARNING, "\n---- Actual SHA-1 digest of image header ----\n");
+ logHexArray(Logger::WARNING, (uint8_t *)&computedDigest, sizeof(computedDigest));
+ }
+
+ // read the section table
+ m_reader->readSectionTable();
+ const EncoreBootImageReader::section_array_t & sectionTable = m_reader->getSections();
+ EncoreBootImageReader::section_array_t::const_iterator it = sectionTable.begin();
+ Log::log("\n---- Section table ----\n");
+ unsigned n = 0;
+ for (; it != sectionTable.end(); ++it, ++n)
+ {
+ const EncoreBootImage::section_header_t & sectionHeader = *it;
+ Log::log("Section %d:\n", n);
+ dumpSectionHeader(sectionHeader);
+ }
+
+ // read the key dictionary
+ // XXX need to support multiple keys, not just the first!
+ if (m_reader->isEncrypted())
+ {
+ Log::log("\n---- Key dictionary ----\n");
+ if (m_keyFilePaths.size() > 0 || m_useDefaultKey)
+ {
+ if (m_keyFilePaths.size() > 0)
+ {
+ std::string & keyPath = m_keyFilePaths[0];
+ std::ifstream keyStream(keyPath.c_str(), std::ios_base::binary | std::ios_base::in);
+ if (!keyStream.is_open())
+ {
+ Log::log(Logger::WARNING, "warning: unable to read key %s\n", keyPath.c_str());
+ }
+ AESKey<128> kek(keyStream);
+
+ // search for this key in the key dictionary
+ if (!m_reader->readKeyDictionary(kek))
+ {
+ throw std::runtime_error("the provided key is not valid for this encrypted boot image");
+ }
+
+ Log::log("\nKey %s was found in key dictionary.\n", keyPath.c_str());
+ }
+ else
+ {
+ // default key of zero, overriden if -k was used
+ AESKey<128> defaultKek;
+
+ // search for this key in the key dictionary
+ if (!m_reader->readKeyDictionary(defaultKek))
+ {
+ throw std::runtime_error("the default key is not valid for this encrypted boot image");
+ }
+
+ Log::log("\nDefault key was found in key dictionary.\n");
+ }
+
+ // print out the DEK
+ AESKey<128> dek = m_reader->getKey();
+ std::stringstream dekStringStream(std::ios_base::in | std::ios_base::out);
+ dek.writeToStream(dekStringStream);
+ std::string dekString = dekStringStream.str();
+// Log::log("\nData encryption key: %s\n", dekString.c_str());
+ Log::log("\nData encryption key:\n");
+ logHexArray(Logger::INFO, (const uint8_t *)&dek.getKey(), sizeof(AESKey<128>::key_t));
+ }
+ else
+ {
+ throw std::runtime_error("the image is encrypted but no key was provided");
+ }
+ }
+
+ // read the SHA-1 digest over the entire image. this is done after
+ // reading the key dictionary because the digest is encrypted in
+ // encrypted boot images.
+ m_reader->readImageDigest();
+ const sha1_digest_t & embeddedDigest = m_reader->getDigest();
+ Log::log("\n---- SHA-1 digest of entire image ----\n");
+ logHexArray(Logger::INFO, (const uint8_t *)&embeddedDigest, sizeof(embeddedDigest));
+
+ // compute the digest over the entire image and compare
+ m_reader->computeImageDigest(computedDigest);
+ if (compareDigests(computedDigest, embeddedDigest))
+ {
+ Log::log("Image digest is correct.\n");
+ }
+ else
+ {
+ Log::log(Logger::WARNING, "warning: stored SHA-1 digest does not match the actual digest\n");
+ Log::log(Logger::WARNING, "\n---- Actual SHA-1 digest of entire image ----\n");
+ logHexArray(Logger::WARNING, (uint8_t *)&computedDigest, sizeof(computedDigest));
+ }
+
+ // read the boot tags
+ m_reader->readBootTags();
+ Log::log("\n---- Boot tags ----\n");
+ unsigned block = header.m_firstBootTagBlock;
+ const EncoreBootImageReader::boot_tag_array_t & tags = m_reader->getBootTags();
+ EncoreBootImageReader::boot_tag_array_t::const_iterator tagIt = tags.begin();
+ for (n = 0; tagIt != tags.end(); ++tagIt, ++n)
+ {
+ const EncoreBootImage::boot_command_t & command = *tagIt;
+ Log::log("%04u: @ block %06u | id=0x%08x | length=%06u | flags=0x%08x\n", n, block, command.m_address, command.m_count, command.m_data);
+
+ if (command.m_data & EncoreBootImage::ROM_SECTION_BOOTABLE)
+ {
+ Log::log(" 0x1 = ROM_SECTION_BOOTABLE\n");
+ }
+
+ if (command.m_data & EncoreBootImage::ROM_SECTION_CLEARTEXT)
+ {
+ Log::log(" 0x2 = ROM_SECTION_CLEARTEXT\n");
+ }
+
+ block += command.m_count + 1;
+ }
+
+ // now read all of the sections
+ Log::log(Logger::INFO2, "\n---- Sections ----\n");
+ for (n = 0; n < header.m_sectionCount; ++n)
+ {
+ EncoreBootImage::Section * section = m_reader->readSection(n);
+ section->debugPrint();
+
+ // Check if this is the section the user wants to extract.
+ if (m_doExtract && n == m_sectionIndex)
+ {
+ extractSection(section);
+ }
+ }
+ }
+
+ //! \brief Dumps the contents of a section to stdout.
+ //!
+ //! If #m_extractBinary is true then the contents are written as
+ //! raw binary to stdout. Otherwise the data is formatted using
+ //! logHexArray().
+ void extractSection(EncoreBootImage::Section * section)
+ {
+ // Allocate buffer to hold section data.
+ unsigned blockCount = section->getBlockCount();
+ unsigned dataLength = sizeOfCipherBlocks(blockCount);
+ smart_array_ptr<uint8_t> buffer = new uint8_t[dataLength];
+ cipher_block_t * data = reinterpret_cast<cipher_block_t *>(buffer.get());
+
+ // Read section data into the buffer one block at a time.
+ unsigned offset;
+ for (offset = 0; offset < blockCount;)
+ {
+ unsigned blocksRead = section->getBlocks(offset, 1, data);
+ offset += blocksRead;
+ data += blocksRead;
+ }
+
+ // Print header.
+ Log::log(Logger::INFO, "\nSection %d contents:\n", m_sectionIndex);
+
+ // Now dump the extracted data to stdout.
+ if (m_extractBinary)
+ {
+ if (fwrite(buffer.get(), 1, dataLength, stdout) != dataLength)
+ {
+ throw std::runtime_error(format_string("failed to write data to stdout (%d)", ferror(stdout)));
+ }
+ }
+ else
+ {
+ // Use the warning log level so the data will be visible even in quiet mode.
+ logHexArray(Logger::WARNING, buffer, dataLength);
+ }
+ }
+
+ //! \brief Compares two SHA-1 digests and returns whether they are equal.
+ //! \retval true The two digests are equal.
+ //! \retval false The \a a and \a b digests are different from each other.
+ bool compareDigests(const sha1_digest_t & a, const sha1_digest_t & b)
+ {
+ return memcmp(a, b, sizeof(sha1_digest_t)) == 0;
+ }
+
+ /*
+ struct boot_image_header_t
+ {
+ union
+ {
+ sha1_digest_t m_digest; //!< SHA-1 digest of image header. Also used as the crypto IV.
+ struct
+ {
+ cipher_block_t m_iv; //!< The first four bytes of the digest form the initialization vector.
+ uint8_t m_extra[4]; //!< The leftover top four bytes of the SHA-1 digest.
+ };
+ };
+ uint8_t m_signature[4]; //!< 'STMP', see #ROM_IMAGE_HEADER_SIGNATURE.
+ uint16_t m_version; //!< Version of the boot image format, see #ROM_BOOT_IMAGE_VERSION.
+ uint16_t m_flags; //!< Flags or options associated with the entire image.
+ uint32_t m_imageBlocks; //!< Size of entire image in blocks.
+ uint32_t m_firstBootTagBlock; //!< Offset from start of file to the first boot tag, in blocks.
+ section_id_t m_firstBootableSectionID; //!< ID of section to start booting from.
+ uint16_t m_keyCount; //!< Number of entries in DEK dictionary.
+ uint16_t m_keyDictionaryBlock; //!< Starting block number for the key dictionary.
+ uint16_t m_headerBlocks; //!< Size of this header, including this size word, in blocks.
+ uint16_t m_sectionCount; //!< Number of section headers in this table.
+ uint16_t m_sectionHeaderSize; //!< Size in blocks of a section header.
+ uint8_t m_padding0[6]; //!< Padding to align #m_timestamp to long word.
+ uint64_t m_timestamp; //!< Timestamp when image was generated in microseconds since 1-1-2000.
+ version_t m_productVersion; //!< Product version.
+ version_t m_componentVersion; //!< Component version.
+ uint16_t m_driveTag;
+ uint8_t m_padding1[6]; //!< Padding to round up to next cipher block.
+ };
+ */
+ void dumpImageHeader(const EncoreBootImage::boot_image_header_t & header)
+ {
+ version_t vers;
+
+ Log::SetOutputLevel infoLevel(Logger::INFO);
+ Log::log("Signature 1: %c%c%c%c\n", header.m_signature[0], header.m_signature[1], header.m_signature[2], header.m_signature[3]);
+ Log::log("Signature 2: %c%c%c%c\n", header.m_signature2[0], header.m_signature2[1], header.m_signature2[2], header.m_signature2[3]);
+ Log::log("Format version: %d.%d\n", header.m_majorVersion, header.m_minorVersion);
+ Log::log("Flags: 0x%04x\n", header.m_flags);
+ Log::log("Image blocks: %u\n", header.m_imageBlocks);
+ Log::log("First boot tag block: %u\n", header.m_firstBootTagBlock);
+ Log::log("First boot section ID: 0x%08x\n", header.m_firstBootableSectionID);
+ Log::log("Key count: %u\n", header.m_keyCount);
+ Log::log("Key dictionary block: %u\n", header.m_keyDictionaryBlock);
+ Log::log("Header blocks: %u\n", header.m_headerBlocks);
+ Log::log("Section count: %u\n", header.m_sectionCount);
+ Log::log("Section header size: %u\n", header.m_sectionHeaderSize);
+ Log::log("Timestamp: %llu\n", header.m_timestamp);
+ vers = header.m_productVersion;
+ vers.fixByteOrder();
+ Log::log("Product version: %x.%x.%x\n", vers.m_major, vers.m_minor, vers.m_revision);
+ vers = header.m_componentVersion;
+ vers.fixByteOrder();
+ Log::log("Component version: %x.%x.%x\n", vers.m_major, vers.m_minor, vers.m_revision);
+ if (header.m_majorVersion == 1 && header.m_minorVersion >= 1)
+ {
+ Log::log("Drive tag: 0x%04x\n", header.m_driveTag);
+ }
+ Log::log("SHA-1 digest of header:\n");
+ logHexArray(Logger::INFO, (uint8_t *)&header.m_digest, sizeof(header.m_digest));
+ }
+
+ void dumpSectionHeader(const EncoreBootImage::section_header_t & header)
+ {
+ Log::SetOutputLevel infoLevel(Logger::INFO);
+ Log::log(" Identifier: 0x%x\n", header.m_tag);
+ Log::log(" Offset: %d block%s (%d bytes)\n", header.m_offset, header.m_offset!=1?"s":"", sizeOfCipherBlocks(header.m_offset));
+ Log::log(" Length: %d block%s (%d bytes)\n", header.m_length, header.m_length!=1?"s":"", sizeOfCipherBlocks(header.m_length));
+ Log::log(" Flags: 0x%08x\n", header.m_flags);
+
+ if (header.m_flags & EncoreBootImage::ROM_SECTION_BOOTABLE)
+ {
+ Log::log(" 0x1 = ROM_SECTION_BOOTABLE\n");
+ }
+
+ if (header.m_flags & EncoreBootImage::ROM_SECTION_CLEARTEXT)
+ {
+ Log::log(" 0x2 = ROM_SECTION_CLEARTEXT\n");
+ }
+ }
+
+ /*!
+ * \brief Log an array of bytes as hex.
+ */
+ void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count)
+ {
+ Log::SetOutputLevel leveler(level);
+
+ unsigned i;
+ for (i = 0; i < count; ++i, ++bytes)
+ {
+ if ((i % 16 == 0) && (i < count - 1))
+ {
+ if (i != 0)
+ {
+ Log::log("\n");
+ }
+ Log::log(" 0x%08x: ", i);
+ }
+ Log::log("%02x ", *bytes & 0xff);
+ }
+
+ Log::log("\n");
+ }
+
+};
+
+/*!
+ * Main application entry point. Creates an sbtool instance and lets it take over.
+ */
+int main(int argc, char* argv[], char* envp[])
+{
+ try
+ {
+ return sbtool(argc, argv).run();
+ }
+ catch (...)
+ {
+ Log::log(Logger::ERROR, "error: unexpected exception\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+
diff --git a/stdafx.h b/stdafx.h
new file mode 100644
index 0000000..ce80458
--- /dev/null
+++ b/stdafx.h
@@ -0,0 +1,66 @@
+#ifndef stdafx_h_
+#define stdafx_h_
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+// Default to external release.
+#ifndef SGTL_INTERNAL
+ #define SGTL_INTERNAL 0
+#endif
+
+#include <iostream>
+#include <stdexcept>
+
+#if defined(WIN32)
+//#include <tchar.h>
+
+ // define this macro for use in VC++
+ #if !defined(__LITTLE_ENDIAN__)
+ #define __LITTLE_ENDIAN__ 1
+ #endif // !defined(__LITTLE_ENDIAN__)
+#endif // defined(WIN32)
+
+#if defined(Linux)
+// For Linux systems only, types.h only defines the signed
+// integer types. This is not professional code.
+// Update: They are defined in the header files in the more recent version of redhat enterprise gcc.
+#include "/usr/include/sys/types.h"
+//typedef unsigned long uint32_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned char uint8_t;
+
+//#define TCHAR char
+//#define _tmain main
+
+ // give a default endian in case one is not defined on Linux (it should be, though)
+ #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+ #define __LITTLE_ENDIAN__ 1
+ #endif // !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+
+#endif // defined(Linux)
+
+
+#if !defined(Linux)
+// redefine missing typedefs from stdint.h or syst/types.h
+
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+
+typedef long int32_t;
+typedef short int16_t;
+typedef char int8_t;
+#endif // !defined(Linux)
+
+#if !defined(TRUE)
+ #define TRUE 1
+#endif // !defined(TRUE)
+
+#if !defined(FALSE)
+ #define FALSE 0
+#endif // !defined(FALSE)
+
+#endif // stdafx_h_