[llvm] r363243 - [llvm-objcopy] Implement IHEX reader

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 13 02:56:15 PDT 2019


Author: evgeny777
Date: Thu Jun 13 02:56:14 2019
New Revision: 363243

URL: http://llvm.org/viewvc/llvm-project?rev=363243&view=rev
Log:
[llvm-objcopy] Implement IHEX reader

This is the final part of IHEX format support in llvm-objcopy
Differential revision: https://reviews.llvm.org/D62583

Added:
    llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex
    llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test
Modified:
    llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
    llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h
    llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
    llvm/trunk/tools/llvm-objcopy/ELF/Object.h
    llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp

Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex?rev=363243&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex Thu Jun 13 02:56:14 2019
@@ -0,0 +1,15 @@
+:020000021000EC
+:08FFF8000001020304050607E5
+:020000022000DC
+:0300000008090AE2
+:02000002F0000C
+:08FFF800303132333435363765
+:020000020000FC
+:020000040010EA
+:030000003839404C
+:02000004001FDB
+:08FFF8004041424344454647E5
+:020000040020DA
+:030000004849501C
+:0400000300000000F9
+:00000001FF

Added: llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test?rev=363243&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test Thu Jun 13 02:56:14 2019
@@ -0,0 +1,203 @@
+# Check section headers when converting from hex to ELF
+# RUN: yaml2obj %p/Inputs/ihex-elf-sections.yaml -o %t
+# RUN: llvm-objcopy -O ihex %t %t.hex
+# RUN: llvm-objcopy -I ihex -O elf32-i386 %t.hex %t2
+# RUN: llvm-readobj -section-headers %t2 | FileCheck %s
+
+# Check section contents
+# RUN: llvm-objcopy -O binary --only-section=.text %t %t.text
+# RUN: llvm-objcopy -O binary --only-section=.sec1 %t2 %t2.sec1
+# RUN: cmp %t.text %t2.sec1
+# RUN: llvm-objcopy -O binary --only-section=.data %t %t.data
+# RUN: llvm-objcopy -O binary --only-section=.sec2 %t2 %t2.sec2
+# RUN: cmp %t.data %t2.sec2
+# RUN: llvm-objcopy -O binary --only-section=.data2 %t %t.data2
+# RUN: llvm-objcopy -O binary --only-section=.sec3 %t2 %t2.sec3
+# RUN: cmp %t.data2 %t2.sec3
+# RUN: llvm-objcopy -O binary --only-section=.data3 %t %t.data3
+# RUN: llvm-objcopy -O binary --only-section=.sec4 %t2 %t2.sec4
+# RUN: cmp %t.data3 %t2.sec4
+
+# Check loading from raw hex file
+# RUN: llvm-objcopy -I ihex -O elf32-i386 %p/Inputs/sections.hex %t-raw
+# RUN: llvm-readobj -section-headers %t-raw | FileCheck %s --check-prefix=RAW
+
+# Check section contents
+# RUN: llvm-objcopy -O ihex --only-section=.sec1 %t-raw - | FileCheck %s --check-prefix=RAW-SEC1
+# RUN: llvm-objcopy -O ihex --only-section=.sec2 %t-raw - | FileCheck %s --check-prefix=RAW-SEC2
+# RUN: llvm-objcopy -O ihex --only-section=.sec3 %t-raw - | FileCheck %s --check-prefix=RAW-SEC3
+
+# Check that line is trimmed from whitespace
+# RUN: echo "   :0100000001FE   " | llvm-objcopy -I ihex -O elf64-x86-64 - - \
+# RUN: | llvm-objcopy -O ihex - - | FileCheck %s --check-prefix=SPACES
+
+# Check for various parsing errors
+# 1. String too short
+# RUN: echo "01000000FF" | not llvm-objcopy -I ihex -O elf32-i386  - - 2>&1 | FileCheck %s --check-prefix=BAD_LENGTH
+
+# 2. missing ':'
+# RUN: echo "0100000000FF" | not llvm-objcopy -I ihex -O elf32-i386  - - 2>&1 | FileCheck %s --check-prefix=MISSING_COLON
+
+# 3. invalid charatcer
+# RUN: echo ":01000000xF" |  not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_CHAR
+
+# 4. incorrect string length
+# RUN: echo ":010000000000000F" | not llvm-objcopy -I ihex -O elf32-i386  - - 2>&1 | FileCheck %s --check-prefix=BAD_LENGTH2
+
+# 5. invalid type (06)
+# RUN: echo ":00000006FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_TYPE
+
+# 6. invalid checksum
+# RUN: echo ":00000001FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_CKSUM
+
+# 7. zero data length
+# RUN: echo ":00010000FF" | not llvm-objcopy -I ihex - - 2>&1 | FileCheck %s --check-prefix=ZERO_DATA_LEN
+
+# 8. Bad data length for '02' (SegmentAddr) record
+# RUN: echo ":03000002000000FB" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_SEGADDR_LEN
+
+# 9. Bad data length for '03' (StartAddr80x86) record
+# RUN: echo ":03000003000000FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR_LEN
+
+# 10. Bad data length for '05' (StartAddr) record
+# RUN: echo ":03000005000000F8" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR_LEN
+
+# 11. Address value for 'StartAddr80x86' is greater then 0xFFFFFU
+# RUN: echo ":04000003FFFFFFFFFD" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR
+
+# 12. Invalid extended address data size
+# RUN: echo ":04000004FFFFFFFFFC" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_EXTADDR_LEN
+
+# 13. no sections in the hex file
+# a) try empty file:
+# RUN: echo "" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=NO_SECTIONS
+# b) EOF record should cancel processing further records. Not having any section data
+#    before EOF should trigger an error
+# RUN: echo ":00000001FF" > %t-bad14.hex
+# RUN: echo ":0100000001FE" >> %t-bad14.hex
+# RUN: not llvm-objcopy -I ihex %t-bad14.hex %t-none 2>&1 | FileCheck %s --check-prefix=NO_SECTIONS
+
+# CHECK:         Index: 1
+# CHECK-NEXT:    Name: .sec1
+# CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:    Flags [ (0x3)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x0
+# CHECK-NEXT:    Offset: 0x34
+# CHECK-NEXT:    Size: 21
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+
+# CHECK:         Index: 2
+# CHECK-NEXT:    Name: .sec2
+# CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:    Flags [ (0x3)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0xFFF8
+# CHECK-NEXT:    Offset: 0x49
+# CHECK-NEXT:    Size: 11
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+
+# CHECK:         Index: 3
+# CHECK-NEXT:    Name: .sec3
+# CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:    Flags [ (0x3)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x10100
+# CHECK-NEXT:    Offset: 0x54
+# CHECK-NEXT:    Size: 4
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+
+# CHECK:         Index: 4
+# CHECK-NEXT:    Name: .sec4
+# CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:    Flags [ (0x3)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:      SHF_WRITE (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x10FFF8
+# CHECK-NEXT:    Offset: 0x58
+# CHECK-NEXT:    Size: 11
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+  
+# RAW:          Index: 1
+# RAW-NEXT:     Name: .sec1
+# RAW-NEXT:     Type: SHT_PROGBITS (0x1)
+# RAW-NEXT:     Flags [ (0x3)
+# RAW-NEXT:       SHF_ALLOC (0x2)
+# RAW-NEXT:       SHF_WRITE (0x1)
+# RAW-NEXT:     ]
+# RAW-NEXT:     Address: 0x1FFF8
+# RAW-NEXT:     Offset: 0x34
+# RAW-NEXT:     Size: 11
+
+# RAW:          Index: 2
+# RAW-NEXT:     Name: .sec2
+# RAW-NEXT:     Type: SHT_PROGBITS (0x1)
+# RAW-NEXT:     Flags [ (0x3)
+# RAW-NEXT:       SHF_ALLOC (0x2)
+# RAW-NEXT:       SHF_WRITE (0x1)
+# RAW-NEXT:     ]
+# RAW-NEXT:     Address: 0xFFFF8
+# RAW-NEXT:     Offset: 0x3F
+# RAW-NEXT:     Size: 11
+
+# RAW:          Index: 3
+# RAW-NEXT:     Name: .sec3
+# RAW-NEXT:     Type: SHT_PROGBITS (0x1)
+# RAW-NEXT:     Flags [ (0x3)
+# RAW-NEXT:       SHF_ALLOC (0x2)
+# RAW-NEXT:       SHF_WRITE (0x1)
+# RAW-NEXT:     ]
+# RAW-NEXT:     Address: 0x1FFFF8
+# RAW-NEXT:     Offset: 0x4A
+# RAW-NEXT:     Size: 11
+
+# RAW-SEC1:         :020000021000EC
+# RAW-SEC1-NEXT:    :08FFF8000001020304050607E5
+# RAW-SEC1-NEXT:    :020000022000DC
+# RAW-SEC1-NEXT:    :0300000008090AE2
+
+# RAW-SEC2:         :02000002F0000C
+# RAW-SEC2-NEXT:    :08FFF800303132333435363765
+# RAW-SEC2-NEXT:    :020000020000FC
+# RAW-SEC2-NEXT:    :020000040010EA
+# RAW-SEC2-NEXT:    :030000003839404C
+
+# RAW-SEC3:         :02000004001FDB
+# RAW-SEC3-NEXT:    :08FFF8004041424344454647E5
+# RAW-SEC3-NEXT:    :020000040020DA
+# RAW-SEC3-NEXT:    :030000004849501C
+
+# SPACES:       :0100000001FE
+# SPACES-NEXT:  :00000001FF
+
+# BAD_LENGTH: error: '{{.*}}': line 1: line is too short: 10 chars
+# MISSING_COLON: error: '{{.*}}': line 1: missing ':' in the beginning of line
+# BAD_CHAR: error: '{{.*}}': line 1: invalid character at position 10
+# BAD_LENGTH2: error: '{{.*}}': line 1: invalid line length 17 (should be 13)
+# BAD_TYPE: error: '{{.*}}': line 1: unknown record type: 6
+# BAD_CKSUM: error: '{{.*}}': line 1: incorrect checksum
+# ZERO_DATA_LEN: error: '{{.*}}': line 1: zero data length is not allowed for data records
+# BAD_SEGADDR_LEN: error: '{{.*}}': line 1: segment address data should be 2 bytes in size
+# BAD_STARTADDR_LEN: error: '{{.*}}': line 1: start address data should be 4 bytes in size
+# BAD_STARTADDR:  error: '{{.*}}': line 1: start address exceeds 20 bit for 80x86
+# BAD_EXTADDR_LEN: error: '{{.*}}': line 1: extended address data should be 2 bytes in size
+# NO_SECTIONS: error: '{{.*}}': no sections

Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp Thu Jun 13 02:56:14 2019
@@ -741,6 +741,17 @@ static Error writeOutput(const CopyConfi
   return Writer->write();
 }
 
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+                           Buffer &Out) {
+  IHexReader Reader(&In);
+  std::unique_ptr<Object> Obj = Reader.create();
+  const ElfType OutputElfType =
+      getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch));
+  if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
+    return E;
+  return writeOutput(Config, *Obj, Out, OutputElfType);
+}
+
 Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
                                 Buffer &Out) {
   BinaryReader Reader(Config.BinaryArch, &In);

Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h Thu Jun 13 02:56:14 2019
@@ -22,6 +22,8 @@ struct CopyConfig;
 class Buffer;
 
 namespace elf {
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+                           Buffer &Out);
 Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
                                 Buffer &Out);
 Error executeObjcopyOnBinary(const CopyConfig &Config,

Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp Thu Jun 13 02:56:14 2019
@@ -205,6 +205,98 @@ IHexLineData IHexRecord::getLine(uint8_t
   return Line;
 }
 
+static Error checkRecord(const IHexRecord &R) {
+  switch (R.Type) {
+  case IHexRecord::Data:
+    if (R.HexData.size() == 0)
+      return createStringError(
+          errc::invalid_argument,
+          "zero data length is not allowed for data records");
+    break;
+  case IHexRecord::EndOfFile:
+    break;
+  case IHexRecord::SegmentAddr:
+    // 20-bit segment address. Data length must be 2 bytes
+    // (4 bytes in hex)
+    if (R.HexData.size() != 4)
+      return createStringError(
+          errc::invalid_argument,
+          "segment address data should be 2 bytes in size");
+    break;
+  case IHexRecord::StartAddr80x86:
+  case IHexRecord::StartAddr:
+    if (R.HexData.size() != 8)
+      return createStringError(errc::invalid_argument,
+                               "start address data should be 4 bytes in size");
+    // According to Intel HEX specification '03' record
+    // only specifies the code address within the 20-bit
+    // segmented address space of the 8086/80186. This
+    // means 12 high order bits should be zeroes.
+    if (R.Type == IHexRecord::StartAddr80x86 &&
+        R.HexData.take_front(3) != "000")
+      return createStringError(errc::invalid_argument,
+                               "start address exceeds 20 bit for 80x86");
+    break;
+  case IHexRecord::ExtendedAddr:
+    // 16-31 bits of linear base address
+    if (R.HexData.size() != 4)
+      return createStringError(
+          errc::invalid_argument,
+          "extended address data should be 2 bytes in size");
+    break;
+  default:
+    // Unknown record type
+    return createStringError(errc::invalid_argument, "unknown record type: %u",
+                             static_cast<unsigned>(R.Type));
+  }
+  return Error::success();
+}
+
+// Checks that IHEX line contains valid characters.
+// This allows converting hexadecimal data to integers
+// without extra verification.
+static Error checkChars(StringRef Line) {
+  assert(!Line.empty());
+  if (Line[0] != ':')
+    return createStringError(errc::invalid_argument,
+                             "missing ':' in the beginning of line.");
+
+  for (size_t Pos = 1; Pos < Line.size(); ++Pos)
+    if (hexDigitValue(Line[Pos]) == -1U)
+      return createStringError(errc::invalid_argument,
+                               "invalid character at position %zu.", Pos + 1);
+  return Error::success();
+}
+
+Expected<IHexRecord> IHexRecord::parse(StringRef Line) {
+  assert(!Line.empty());
+
+  // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC'
+  if (Line.size() < 11)
+    return createStringError(errc::invalid_argument,
+                             "line is too short: %zu chars.", Line.size());
+
+  if (Error E = checkChars(Line))
+    return std::move(E);
+
+  IHexRecord Rec;
+  size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2));
+  if (Line.size() != getLength(DataLen))
+    return createStringError(errc::invalid_argument,
+                             "invalid line length %zu (should be %zu)",
+                             Line.size(), getLength(DataLen));
+
+  Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4));
+  Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2));
+  Rec.HexData = Line.substr(9, DataLen * 2);
+
+  if (getChecksum(Line.drop_front(1)) != 0)
+    return createStringError(errc::invalid_argument, "incorrect checksum.");
+  if (Error E = checkRecord(Rec))
+    return std::move(E);
+  return Rec;
+}
+
 static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
   Segment *Seg = Sec->ParentSegment;
   if (Seg && Seg->Type != ELF::PT_LOAD)
@@ -829,32 +921,33 @@ void DynamicRelocationSection::accept(Se
 }
 
 void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
-  Visitor.visit(*this);
-}
-
-Error DynamicRelocationSection::removeSectionReferences(
-    bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
-  if (ToRemove(Symbols)) {
-    if (!AllowBrokenLinks)
-      return createStringError(
-          llvm::errc::invalid_argument,
+  Visitor.visit(*this);
+}
+
+Error DynamicRelocationSection::removeSectionReferences(
+    bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
+  if (ToRemove(Symbols)) {
+    if (!AllowBrokenLinks)
+      return createStringError(
+          llvm::errc::invalid_argument,
           "symbol table '%s' cannot be removed because it is "
           "referenced by the relocation section '%s'",
-          Symbols->Name.data(), this->Name.data());
-    Symbols = nullptr;
-  }
-
-  // SecToApplyRel contains a section referenced by sh_info field. It keeps
-  // a section to which the relocation section applies. When we remove any
-  // sections we also remove their relocation sections. Since we do that much
-  // earlier, this assert should never be triggered.
-  assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
-  return Error::success();
-}
-
-Error Section::removeSectionReferences(bool AllowBrokenDependency,
-    function_ref<bool(const SectionBase *)> ToRemove) {
-  if (ToRemove(LinkSection)) {
+          Symbols->Name.data(), this->Name.data());
+    Symbols = nullptr;
+  }
+
+  // SecToApplyRel contains a section referenced by sh_info field. It keeps
+  // a section to which the relocation section applies. When we remove any
+  // sections we also remove their relocation sections. Since we do that much
+  // earlier, this assert should never be triggered.
+  assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
+  return Error::success();
+}
+
+Error Section::removeSectionReferences(
+    bool AllowBrokenDependency,
+    function_ref<bool(const SectionBase *)> ToRemove) {
+  if (ToRemove(LinkSection)) {
     if (!AllowBrokenDependency)
       return createStringError(llvm::errc::invalid_argument,
                                "section '%s' cannot be removed because it is "
@@ -1013,7 +1106,7 @@ static bool compareSegmentsByPAddr(const
   return A->Index < B->Index;
 }
 
-void BinaryELFBuilder::initFileHeader() {
+void BasicELFBuilder::initFileHeader() {
   Obj->Flags = 0x0;
   Obj->Type = ET_REL;
   Obj->OSABI = ELFOSABI_NONE;
@@ -1023,9 +1116,9 @@ void BinaryELFBuilder::initFileHeader()
   Obj->Version = 1;
 }
 
-void BinaryELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
+void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
 
-StringTableSection *BinaryELFBuilder::addStrTab() {
+StringTableSection *BasicELFBuilder::addStrTab() {
   auto &StrTab = Obj->addSection<StringTableSection>();
   StrTab.Name = ".strtab";
 
@@ -1033,7 +1126,7 @@ StringTableSection *BinaryELFBuilder::ad
   return &StrTab;
 }
 
-SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
+SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
   auto &SymTab = Obj->addSection<SymbolTableSection>();
 
   SymTab.Name = ".symtab";
@@ -1046,6 +1139,11 @@ SymbolTableSection *BinaryELFBuilder::ad
   return &SymTab;
 }
 
+void BasicELFBuilder::initSections() {
+  for (auto &Section : Obj->sections())
+    Section.initialize(Obj->sections());
+}
+
 void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
   auto Data = ArrayRef<uint8_t>(
       reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
@@ -1069,11 +1167,6 @@ void BinaryELFBuilder::addData(SymbolTab
                     /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0);
 }
 
-void BinaryELFBuilder::initSections() {
-  for (SectionBase &Section : Obj->sections())
-    Section.initialize(Obj->sections());
-}
-
 std::unique_ptr<Object> BinaryELFBuilder::build() {
   initFileHeader();
   initHeaderSegment();
@@ -1085,6 +1178,62 @@ std::unique_ptr<Object> BinaryELFBuilder
   return std::move(Obj);
 }
 
+// Adds sections from IHEX data file. Data should have been
+// fully validated by this time.
+void IHexELFBuilder::addDataSections() {
+  OwnedDataSection *Section = nullptr;
+  uint64_t SegmentAddr = 0, BaseAddr = 0;
+  uint32_t SecNo = 1;
+
+  for (const IHexRecord &R : Records) {
+    uint64_t RecAddr;
+    switch (R.Type) {
+    case IHexRecord::Data:
+      // Ignore empty data records
+      if (R.HexData.empty())
+        continue;
+      RecAddr = R.Addr + SegmentAddr + BaseAddr;
+      if (!Section || Section->Addr + Section->Size != RecAddr)
+        // OriginalOffset field is only used to sort section properly, so
+        // instead of keeping track of real offset in IHEX file, we use
+        // section number.
+        Section = &Obj->addSection<OwnedDataSection>(
+            ".sec" + std::to_string(SecNo++), RecAddr,
+            ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo);
+      Section->appendHexData(R.HexData);
+      break;
+    case IHexRecord::EndOfFile:
+      break;
+    case IHexRecord::SegmentAddr:
+      // 20-bit segment address.
+      SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4;
+      break;
+    case IHexRecord::StartAddr80x86:
+    case IHexRecord::StartAddr:
+      Obj->Entry = checkedGetHex<uint32_t>(R.HexData);
+      assert(Obj->Entry <= 0xFFFFFU);
+      break;
+    case IHexRecord::ExtendedAddr:
+      // 16-31 bits of linear base address
+      BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16;
+      break;
+    default:
+      llvm_unreachable("unknown record type");
+    }
+  }
+}
+
+std::unique_ptr<Object> IHexELFBuilder::build() {
+  initFileHeader();
+  initHeaderSegment();
+  StringTableSection *StrTab = addStrTab();
+  addSymTab(StrTab);
+  initSections();
+  addDataSections();
+
+  return std::move(Obj);
+}
+
 template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
   for (Segment &Parent : Obj.segments()) {
     // Every segment will overlap with itself but we don't want a segment to
@@ -1463,6 +1612,37 @@ std::unique_ptr<Object> BinaryReader::cr
   return BinaryELFBuilder(MInfo.EMachine, MemBuf).build();
 }
 
+Expected<std::vector<IHexRecord>> IHexReader::parse() const {
+  SmallVector<StringRef, 16> Lines;
+  std::vector<IHexRecord> Records;
+  bool HasSections = false;
+
+  MemBuf->getBuffer().split(Lines, '\n');
+  Records.reserve(Lines.size());
+  for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) {
+    StringRef Line = Lines[LineNo - 1].trim();
+    if (Line.empty())
+      continue;
+
+    Expected<IHexRecord> R = IHexRecord::parse(Line);
+    if (!R)
+      return parseError(LineNo, R.takeError());
+    if (R->Type == IHexRecord::EndOfFile)
+      break;
+    HasSections |= (R->Type == IHexRecord::Data);
+    Records.push_back(*R);
+  }
+  if (!HasSections)
+    return parseError(-1U, "no sections");
+
+  return std::move(Records);
+}
+
+std::unique_ptr<Object> IHexReader::create() const {
+  std::vector<IHexRecord> Records = unwrapOrError(parse());
+  return IHexELFBuilder(Records).build();
+}
+
 std::unique_ptr<Object> ELFReader::create() const {
   auto Obj = llvm::make_unique<Object>();
   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {

Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h Thu Jun 13 02:56:14 2019
@@ -216,6 +216,10 @@ struct IHexRecord {
   static IHexLineData getLine(uint8_t Type, uint16_t Addr,
                               ArrayRef<uint8_t> Data);
 
+  // Parses the line and returns record if possible.
+  // Line should be trimmed from whitespace characters.
+  static Expected<IHexRecord> parse(StringRef Line);
+
   // Calculates checksum of stringified record representation
   // S must NOT contain leading ':' and trailing whitespace
   // characters
@@ -821,15 +825,15 @@ private:
 
 public:
   explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
-
-  void accept(SectionVisitor &) const override;
-  void accept(MutableSectionVisitor &Visitor) override;
-  Error removeSectionReferences(
-      bool AllowBrokenLinks,
-      function_ref<bool(const SectionBase *)> ToRemove) override;
-
-  static bool classof(const SectionBase *S) {
-    if (!(S->Flags & ELF::SHF_ALLOC))
+
+  void accept(SectionVisitor &) const override;
+  void accept(MutableSectionVisitor &Visitor) override;
+  Error removeSectionReferences(
+      bool AllowBrokenLinks,
+      function_ref<bool(const SectionBase *)> ToRemove) override;
+
+  static bool classof(const SectionBase *S) {
+    if (!(S->Flags & ELF::SHF_ALLOC))
       return false;
     return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA;
   }
@@ -862,21 +866,41 @@ using object::ELFFile;
 using object::ELFObjectFile;
 using object::OwningBinary;
 
-class BinaryELFBuilder {
+class BasicELFBuilder {
+protected:
   uint16_t EMachine;
-  MemoryBuffer *MemBuf;
   std::unique_ptr<Object> Obj;
 
   void initFileHeader();
   void initHeaderSegment();
   StringTableSection *addStrTab();
   SymbolTableSection *addSymTab(StringTableSection *StrTab);
-  void addData(SymbolTableSection *SymTab);
   void initSections();
 
 public:
+  BasicELFBuilder(uint16_t EM)
+      : EMachine(EM), Obj(llvm::make_unique<Object>()) {}
+};
+
+class BinaryELFBuilder : public BasicELFBuilder {
+  MemoryBuffer *MemBuf;
+  void addData(SymbolTableSection *SymTab);
+
+public:
   BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB)
-      : EMachine(EM), MemBuf(MB), Obj(llvm::make_unique<Object>()) {}
+      : BasicELFBuilder(EM), MemBuf(MB) {}
+
+  std::unique_ptr<Object> build();
+};
+
+class IHexELFBuilder : public BasicELFBuilder {
+  const std::vector<IHexRecord> &Records;
+
+  void addDataSections();
+
+public:
+  IHexELFBuilder(const std::vector<IHexRecord> &Records)
+      : BasicELFBuilder(ELF::EM_386), Records(Records) {}
 
   std::unique_ptr<Object> build();
 };
@@ -920,6 +944,28 @@ public:
   std::unique_ptr<Object> create() const override;
 };
 
+class IHexReader : public Reader {
+  MemoryBuffer *MemBuf;
+
+  Expected<std::vector<IHexRecord>> parse() const;
+  Error parseError(size_t LineNo, Error E) const {
+    return LineNo == -1U
+               ? createFileError(MemBuf->getBufferIdentifier(), std::move(E))
+               : createFileError(MemBuf->getBufferIdentifier(), LineNo,
+                                 std::move(E));
+  }
+  template <typename... Ts>
+  Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const {
+    Error E = createStringError(errc::invalid_argument, Fmt, Vals...);
+    return parseError(LineNo, std::move(E));
+  }
+
+public:
+  IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
+
+  std::unique_ptr<Object> create() const override;
+};
+
 class ELFReader : public Reader {
   Binary *Bin;
   Optional<StringRef> ExtractPartition;

Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Jun 13 02:56:14 2019
@@ -123,6 +123,14 @@ static Error deepWriteArchive(StringRef
   return Error::success();
 }
 
+/// The function executeObjcopyOnIHex does the dispatch based on the format
+/// of the output specified by the command line options.
+static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+                                  Buffer &Out) {
+  // TODO: support output formats other than ELF.
+  return elf::executeObjcopyOnIHex(Config, In, Out);
+}
+
 /// The function executeObjcopyOnRawBinary does the dispatch based on the format
 /// of the output specified by the command line options.
 static Error executeObjcopyOnRawBinary(const CopyConfig &Config,
@@ -210,12 +218,18 @@ static Error executeObjcopy(const CopyCo
     if (auto EC = sys::fs::status(Config.InputFilename, Stat))
       return createFileError(Config.InputFilename, EC);
 
-  if (Config.InputFormat == "binary") {
-    auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
+  typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
+  auto ProcessRaw = StringSwitch<ProcessRawFn>(Config.InputFormat)
+                        .Case("binary", executeObjcopyOnRawBinary)
+                        .Case("ihex", executeObjcopyOnIHex)
+                        .Default(nullptr);
+
+  if (ProcessRaw) {
+    auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
     if (!BufOrErr)
       return createFileError(Config.InputFilename, BufOrErr.getError());
     FileBuffer FB(Config.OutputFilename);
-    if (Error E = executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB))
+    if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
       return E;
   } else {
     Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =




More information about the llvm-commits mailing list