llvm.org GIT mirror llvm / 09166ea
[obj2yaml] [yaml2obj] Support for MachO Load Command data This re-applies r270115. Many of the MachO load commands can have data appended after the command structure. This data is frequently strings, but can actually be anything. This patch adds support for three optional fields on load command yaml descriptions. The new PayloadString YAML field is populated with the data after load commands known to have strings as extra data. The new ZeroPadBytes YAML field is a count of zero'd bytes after the end of the load command structure before the next command. This can apply anywhere in the file. MachO2YAML verifies that bytes are zero before populating this field, and YAML2MachO will add zero'd bytes. The new PayloadBytes YAML field stores all bytes after the end of the load command structure before the next command if they are non-zero. This is a catch all for all unhandled bytes. If MachO2Yaml populates PayloadBytes it will not populate ZeroPadBytes, instead zero'd bytes will be in the PayloadBytes structure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@270124 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Bieneman 3 years ago
4 changed file(s) with 173 addition(s) and 34 deletion(s). Raw diff Collapse all Expand all
5151 virtual ~LoadCommand();
5252 llvm::MachO::macho_load_command Data;
5353 std::vector
Sections;
54 std::vector PayloadBytes;
55 std::string PayloadString;
56 uint64_t ZeroPadBytes;
5457 };
5558
5659 struct Object {
6467
6568 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand)
6669 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section)
70 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8)
6771
6872 namespace llvm {
6973 namespace yaml {
9595 IO.setContext(nullptr);
9696 }
9797
98 template
99 void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {}
100
101 template <>
102 void mapLoadCommandData(
103 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
104 IO.mapOptional("Sections", LoadCommand.Sections);
105 }
106
107 template <>
108 void mapLoadCommandData(
109 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
110 IO.mapOptional("Sections", LoadCommand.Sections);
111 }
112
113 template <>
114 void mapLoadCommandData(
115 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
116 IO.mapOptional("PayloadString", LoadCommand.PayloadString);
117 }
118
119 template <>
120 void mapLoadCommandData(
121 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
122 IO.mapOptional("PayloadString", LoadCommand.PayloadString);
123 }
124
98125 void MappingTraits::mapping(
99126 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
100127 IO.mapRequired(
105132 case MachO::LCName: \
106133 MappingTraits::mapping(IO, \
107134 LoadCommand.Data.LCStruct##_data); \
135 mapLoadCommandData(IO, LoadCommand); \
108136 break;
109137
110138 switch (LoadCommand.Data.load_command_data.cmd) {
111139 #include "llvm/Support/MachO.def"
112140 }
113 if (LoadCommand.Data.load_command_data.cmd == MachO::LC_SEGMENT ||
114 LoadCommand.Data.load_command_data.cmd == MachO::LC_SEGMENT_64) {
115 IO.mapOptional("Sections", LoadCommand.Sections);
116 }
141 IO.mapOptional("PayloadBytes", LoadCommand.PayloadBytes);
142 IO.mapOptional("ZeroPadBytes", LoadCommand.ZeroPadBytes, (uint64_t)0ull);
117143 }
118144
119145 void MappingTraits::mapping(
1818
1919 class MachODumper {
2020
21 template
22 const char *processLoadCommandData(
23 MachOYAML::LoadCommand &LC,
24 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd);
25
2126 const object::MachOObjectFile &Obj;
2227
2328 public:
3136 sizeof(MachO::LCStruct)); \
3237 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \
3338 MachO::swapStruct(LC.Data.LCStruct##_data); \
39 EndPtr = processLoadCommandData(LC, LoadCmd); \
3440 break;
3541
3642 template
6773 }
6874
6975 template
70 void extractSections(
71 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
72 std::vector &Sections, bool IsLittleEndian) {
76 const char *
77 extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
78 std::vector &Sections,
79 bool IsLittleEndian) {
7380 auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
7481 const SectionType *Curr =
7582 reinterpret_cast(LoadCmd.Ptr + sizeof(SegmentType));
8390 Sections.push_back(constructSection(*Curr));
8491 }
8592 }
93 return reinterpret_cast(Curr);
94 }
95
96 template
97 const char *MachODumper::processLoadCommandData(
98 MachOYAML::LoadCommand &LC,
99 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
100 return LoadCmd.Ptr + sizeof(StructType);
101 }
102
103 template <>
104 const char *MachODumper::processLoadCommandData(
105 MachOYAML::LoadCommand &LC,
106 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
107 return extractSections(
108 LoadCmd, LC.Sections, Obj.isLittleEndian());
109 }
110
111 template <>
112 const char *MachODumper::processLoadCommandData(
113 MachOYAML::LoadCommand &LC,
114 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
115 return extractSections(
116 LoadCmd, LC.Sections, Obj.isLittleEndian());
117 }
118
119 template
120 const char *
121 readString(MachOYAML::LoadCommand &LC,
122 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
123 auto Start = LoadCmd.Ptr + sizeof(StructType);
124 auto MaxSize = LoadCmd.C.cmdsize - sizeof(StructType);
125 auto Size = strnlen(Start, MaxSize);
126 LC.PayloadString = StringRef(Start, Size).str();
127 return Start + Size;
128 }
129
130 template <>
131 const char *MachODumper::processLoadCommandData(
132 MachOYAML::LoadCommand &LC,
133 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
134 return readString(LC, LoadCmd);
135 }
136
137 template <>
138 const char *MachODumper::processLoadCommandData(
139 MachOYAML::LoadCommand &LC,
140 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
141 return readString(LC, LoadCmd);
86142 }
87143
88144 Expected> MachODumper::dump() {
98154
99155 for (auto LoadCmd : Obj.load_commands()) {
100156 MachOYAML::LoadCommand LC;
157 const char *EndPtr = LoadCmd.Ptr;
101158 switch (LoadCmd.C.cmd) {
102159 default:
103160 memcpy((void *)&(LC.Data.load_command_data), LoadCmd.Ptr,
104161 sizeof(MachO::load_command));
105162 if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
106163 MachO::swapStruct(LC.Data.load_command_data);
164 EndPtr = processLoadCommandData(LC, LoadCmd);
107165 break;
108166 #include "llvm/Support/MachO.def"
109167 }
110 switch (LoadCmd.C.cmd) {
111 case MachO::LC_SEGMENT:
112 extractSections(
113 LoadCmd, LC.Sections, Obj.isLittleEndian());
114 break;
115 case MachO::LC_SEGMENT_64:
116 extractSections(
117 LoadCmd, LC.Sections, Obj.isLittleEndian());
118 break;
119 }
168 auto RemainingBytes = LoadCmd.C.cmdsize - (EndPtr - LoadCmd.Ptr);
169 if (!std::all_of(EndPtr, &EndPtr[RemainingBytes],
170 [](const char C) { return C == 0; })) {
171 LC.PayloadBytes.insert(LC.PayloadBytes.end(), EndPtr,
172 &EndPtr[RemainingBytes]);
173 RemainingBytes = 0;
174 }
175 LC.ZeroPadBytes = RemainingBytes;
120176 Y->LoadCommands.push_back(std::move(LC));
121177 }
122178
9393 return TempSec;
9494 }
9595
96 template
97 size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
98 return 0;
99 }
100
101 template <>
102 size_t writeLoadCommandData(MachOYAML::LoadCommand &LC,
103 raw_ostream &OS) {
104 size_t BytesWritten = 0;
105 for (auto Sec : LC.Sections) {
106 auto TempSec = constructSection(Sec);
107 OS.write(reinterpret_cast(&(TempSec)),
108 sizeof(MachO::section));
109 BytesWritten += sizeof(MachO::section);
110 }
111 return BytesWritten;
112 }
113
114 template <>
115 size_t
116 writeLoadCommandData(MachOYAML::LoadCommand &LC,
117 raw_ostream &OS) {
118 size_t BytesWritten = 0;
119 for (auto Sec : LC.Sections) {
120 auto TempSec = constructSection(Sec);
121 TempSec.reserved3 = Sec.reserved3;
122 OS.write(reinterpret_cast(&(TempSec)),
123 sizeof(MachO::section_64));
124 BytesWritten += sizeof(MachO::section_64);
125 }
126 return BytesWritten;
127 }
128
129 size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
130 size_t BytesWritten = 0;
131 if (!LC.PayloadString.empty()) {
132 OS.write(LC.PayloadString.c_str(), LC.PayloadString.length());
133 BytesWritten = LC.PayloadString.length();
134 }
135 return BytesWritten;
136 }
137
138 template <>
139 size_t writeLoadCommandData(MachOYAML::LoadCommand &LC,
140 raw_ostream &OS) {
141 return writePayloadString(LC, OS);
142 }
143
144 template <>
145 size_t writeLoadCommandData(MachOYAML::LoadCommand &LC,
146 raw_ostream &OS) {
147 return writePayloadString(LC, OS);
148 }
149
96150 Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
97151 for (auto &LC : Obj.LoadCommands) {
98152 size_t BytesWritten = 0;
101155 OS.write(reinterpret_cast(&(LC.Data.LCStruct##_data)), \
102156 sizeof(MachO::LCStruct)); \
103157 BytesWritten = sizeof(MachO::LCStruct); \
158 BytesWritten += writeLoadCommandData(LC, OS); \
104159 break;
105160
106161 switch (LC.Data.load_command_data.cmd) {
108163 OS.write(reinterpret_cast(&(LC.Data.load_command_data)),
109164 sizeof(MachO::load_command));
110165 BytesWritten = sizeof(MachO::load_command);
166 BytesWritten += writeLoadCommandData(LC, OS);
111167 break;
112168 #include "llvm/Support/MachO.def"
113169 }
114170
115 if(LC.Data.load_command_data.cmd == MachO::LC_SEGMENT) {
116 for(auto Sec : LC.Sections) {
117 auto TempSec = constructSection(Sec);
118 OS.write(reinterpret_cast(&(TempSec)), sizeof(MachO::section));
119 BytesWritten += sizeof(MachO::section);
120 }
121 } else if(LC.Data.load_command_data.cmd == MachO::LC_SEGMENT_64) {
122 for(auto Sec : LC.Sections) {
123 auto TempSec = constructSection(Sec);
124 TempSec.reserved3 = Sec.reserved3;
125 OS.write(reinterpret_cast(&(TempSec)), sizeof(MachO::section_64));
126 BytesWritten += sizeof(MachO::section_64);
127 }
128 }
129
130 auto BytesRemaining =
131 LC.Data.load_command_data.cmdsize - BytesWritten;
171 if (LC.PayloadBytes.size() > 0) {
172 OS.write(reinterpret_cast(LC.PayloadBytes.data()),
173 LC.PayloadBytes.size());
174 BytesWritten += LC.PayloadBytes.size();
175 }
176
177 if (LC.ZeroPadBytes > 0) {
178 std::vector FillData;
179 FillData.insert(FillData.begin(), LC.ZeroPadBytes, 0);
180 OS.write(reinterpret_cast(FillData.data()), LC.ZeroPadBytes);
181 BytesWritten += LC.ZeroPadBytes;
182 }
183
184 auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
132185 if (BytesRemaining > 0) {
133186 // TODO: Replace all this once the load command data is present in yaml.
134187 // For now I fill with 0xDEADBEEF because it is easy to spot on a hex