1 //===- lld/unittest/MachOTests/MachONormalizedFileToAtomsTests.cpp --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
10 #include "lld/Core/Atom.h"
11 #include "lld/Core/DefinedAtom.h"
12 #include "lld/Core/File.h"
13 #include "lld/Core/UndefinedAtom.h"
14 #include "lld/ReaderWriter/MachOLinkingContext.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/BinaryFormat/MachO.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/YAMLTraits.h"
19 #include "gtest/gtest.h"
20 #include <cstdint>
21 #include <memory>
22 
23 using namespace lld::mach_o::normalized;
24 using namespace llvm::MachO;
25 
TEST(ToAtomsTest,empty_obj_x86_64)26 TEST(ToAtomsTest, empty_obj_x86_64) {
27   NormalizedFile f;
28   f.arch = lld::MachOLinkingContext::arch_x86_64;
29   llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
30       normalizedToAtoms(f, "", false);
31   EXPECT_FALSE(!atom_f);
32   EXPECT_EQ(0U, (*atom_f)->defined().size());
33 }
34 
TEST(ToAtomsTest,basic_obj_x86_64)35 TEST(ToAtomsTest, basic_obj_x86_64) {
36   NormalizedFile f;
37   f.arch = lld::MachOLinkingContext::arch_x86_64;
38   Section textSection;
39   static const uint8_t contentBytes[] = { 0x90, 0xC3, 0xC3, 0xC4 };
40   const unsigned contentSize = sizeof(contentBytes) / sizeof(contentBytes[0]);
41   textSection.content = llvm::makeArrayRef(contentBytes, contentSize);
42   f.sections.push_back(textSection);
43   Symbol fooSymbol;
44   fooSymbol.name = "_foo";
45   fooSymbol.type = N_SECT;
46   fooSymbol.scope = N_EXT;
47   fooSymbol.sect = 1;
48   fooSymbol.value = 0;
49   f.globalSymbols.push_back(fooSymbol);
50   Symbol barSymbol;
51   barSymbol.name = "_bar";
52   barSymbol.type = N_SECT;
53   barSymbol.scope = N_EXT;
54   barSymbol.sect = 1;
55   barSymbol.value = 2;
56   f.globalSymbols.push_back(barSymbol);
57   Symbol undefSym;
58   undefSym.name = "_undef";
59   undefSym.type = N_UNDF;
60   f.undefinedSymbols.push_back(undefSym);
61   Symbol bazSymbol;
62   bazSymbol.name = "_baz";
63   bazSymbol.type = N_SECT;
64   bazSymbol.scope = N_EXT | N_PEXT;
65   bazSymbol.sect = 1;
66   bazSymbol.value = 3;
67   f.localSymbols.push_back(bazSymbol);
68 
69   llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
70       normalizedToAtoms(f, "", false);
71   EXPECT_FALSE(!atom_f);
72   const lld::File &file = **atom_f;
73   EXPECT_EQ(3U, file.defined().size());
74   auto it = file.defined().begin();
75   const lld::DefinedAtom *atom1 = *it;
76   ++it;
77   const lld::DefinedAtom *atom2 = *it;
78   ++it;
79   const lld::DefinedAtom *atom3 = *it;
80   const lld::UndefinedAtom *atom4 = *file.undefined().begin();
81   EXPECT_TRUE(atom1->name().equals("_foo"));
82   EXPECT_EQ(2U, atom1->rawContent().size());
83   EXPECT_EQ(0x90, atom1->rawContent()[0]);
84   EXPECT_EQ(0xC3, atom1->rawContent()[1]);
85   EXPECT_EQ(lld::Atom::scopeGlobal, atom1->scope());
86 
87   EXPECT_TRUE(atom2->name().equals("_bar"));
88   EXPECT_EQ(1U, atom2->rawContent().size());
89   EXPECT_EQ(0xC3, atom2->rawContent()[0]);
90   EXPECT_EQ(lld::Atom::scopeGlobal, atom2->scope());
91 
92   EXPECT_TRUE(atom3->name().equals("_baz"));
93   EXPECT_EQ(1U, atom3->rawContent().size());
94   EXPECT_EQ(0xC4, atom3->rawContent()[0]);
95   EXPECT_EQ(lld::Atom::scopeLinkageUnit, atom3->scope());
96 
97   EXPECT_TRUE(atom4->name().equals("_undef"));
98   EXPECT_EQ(lld::Atom::definitionUndefined, atom4->definition());
99 }
100 
TEST(ToAtomsTest,reservedUnitLength)101 TEST(ToAtomsTest, reservedUnitLength) {
102   static const uint8_t debugInfoWithReservedLengthContent[12] = {
103       0xf0, 0xff, 0xff, 0xff // Reserved length value
104   };
105   static const uint8_t debugInfoWithValidBigLengthContent[12] = {
106       0xef, 0xff, 0xff, 0xff, // The maximum valid length value for DWARF32
107       0x00, 0x00              // Wrong version
108   };
109   static const uint8_t dummyContent[] = {0x00};
110 
111   NormalizedFile fReservedLength, fValidBigLength;
112   fReservedLength.arch = lld::MachOLinkingContext::arch_x86;
113   fValidBigLength.arch = lld::MachOLinkingContext::arch_x86;
114   Section section;
115   section.segmentName = "__DWARF";
116   section.sectionName = "__debug_info";
117   section.content = llvm::makeArrayRef(debugInfoWithReservedLengthContent);
118   fReservedLength.sections.push_back(section);
119   section.content = llvm::makeArrayRef(debugInfoWithValidBigLengthContent);
120   fValidBigLength.sections.push_back(section);
121   section.sectionName = "__debug_abbrev";
122   section.content = llvm::makeArrayRef(dummyContent);
123   fReservedLength.sections.push_back(section);
124   fValidBigLength.sections.push_back(section);
125   section.sectionName = "__debug_str";
126   fReservedLength.sections.push_back(section);
127   fValidBigLength.sections.push_back(section);
128 
129   auto resultReservedLength = normalizedToAtoms(fReservedLength, "foo", false);
130   auto resultValidBigLength = normalizedToAtoms(fValidBigLength, "foo", false);
131 
132   // Both cases should return errors, but different.
133   ASSERT_FALSE(resultReservedLength);
134   ASSERT_FALSE(resultValidBigLength);
135 
136   EXPECT_STREQ("Malformed DWARF in foo",
137                toString(resultReservedLength.takeError()).c_str());
138   EXPECT_STREQ("Unsupported DWARF version in foo",
139                toString(resultValidBigLength.takeError()).c_str());
140 }
141