1 //===------ macho2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "Error.h" 11 #include "obj2yaml.h" 12 #include "llvm/Object/MachOUniversal.h" 13 #include "llvm/ObjectYAML/MachOYAML.h" 14 #include "llvm/Support/ErrorHandling.h" 15 #include "llvm/Support/LEB128.h" 16 17 #include <string.h> // for memcpy 18 19 using namespace llvm; 20 21 class MachODumper { 22 23 template <typename StructType> 24 const char *processLoadCommandData( 25 MachOYAML::LoadCommand &LC, 26 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd); 27 28 const object::MachOObjectFile &Obj; 29 void dumpHeader(std::unique_ptr<MachOYAML::Object> &Y); 30 void dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y); 31 void dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y); 32 void dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y); 33 void dumpBindOpcodes(std::vector<MachOYAML::BindOpcode> &BindOpcodes, 34 ArrayRef<uint8_t> OpcodeBuffer, bool Lazy = false); 35 36 public: 37 MachODumper(const object::MachOObjectFile &O) : Obj(O) {} 38 Expected<std::unique_ptr<MachOYAML::Object>> dump(); 39 }; 40 41 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 42 case MachO::LCName: \ 43 memcpy((void *) & (LC.Data.LCStruct##_data), LoadCmd.Ptr, \ 44 sizeof(MachO::LCStruct)); \ 45 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \ 46 MachO::swapStruct(LC.Data.LCStruct##_data); \ 47 EndPtr = processLoadCommandData<MachO::LCStruct>(LC, LoadCmd); \ 48 break; 49 50 template <typename SectionType> 51 MachOYAML::Section constructSectionCommon(SectionType Sec) { 52 MachOYAML::Section TempSec; 53 memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16); 54 memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16); 55 TempSec.addr = Sec.addr; 56 TempSec.size = Sec.size; 57 TempSec.offset = Sec.offset; 58 TempSec.align = Sec.align; 59 TempSec.reloff = Sec.reloff; 60 TempSec.nreloc = Sec.nreloc; 61 TempSec.flags = Sec.flags; 62 TempSec.reserved1 = Sec.reserved1; 63 TempSec.reserved2 = Sec.reserved2; 64 TempSec.reserved3 = 0; 65 return TempSec; 66 } 67 68 template <typename SectionType> 69 MachOYAML::Section constructSection(SectionType Sec); 70 71 template <> MachOYAML::Section constructSection(MachO::section Sec) { 72 MachOYAML::Section TempSec = constructSectionCommon(Sec); 73 TempSec.reserved3 = 0; 74 return TempSec; 75 } 76 77 template <> MachOYAML::Section constructSection(MachO::section_64 Sec) { 78 MachOYAML::Section TempSec = constructSectionCommon(Sec); 79 TempSec.reserved3 = Sec.reserved3; 80 return TempSec; 81 } 82 83 template <typename SectionType, typename SegmentType> 84 const char * 85 extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, 86 std::vector<MachOYAML::Section> &Sections, 87 bool IsLittleEndian) { 88 auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; 89 const SectionType *Curr = 90 reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType)); 91 for (; reinterpret_cast<const void *>(Curr) < End; Curr++) { 92 if (IsLittleEndian != sys::IsLittleEndianHost) { 93 SectionType Sec; 94 memcpy((void *)&Sec, Curr, sizeof(SectionType)); 95 MachO::swapStruct(Sec); 96 Sections.push_back(constructSection(Sec)); 97 } else { 98 Sections.push_back(constructSection(*Curr)); 99 } 100 } 101 return reinterpret_cast<const char *>(Curr); 102 } 103 104 template <typename StructType> 105 const char *MachODumper::processLoadCommandData( 106 MachOYAML::LoadCommand &LC, 107 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 108 return LoadCmd.Ptr + sizeof(StructType); 109 } 110 111 template <> 112 const char *MachODumper::processLoadCommandData<MachO::segment_command>( 113 MachOYAML::LoadCommand &LC, 114 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 115 return extractSections<MachO::section, MachO::segment_command>( 116 LoadCmd, LC.Sections, Obj.isLittleEndian()); 117 } 118 119 template <> 120 const char *MachODumper::processLoadCommandData<MachO::segment_command_64>( 121 MachOYAML::LoadCommand &LC, 122 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 123 return extractSections<MachO::section_64, MachO::segment_command_64>( 124 LoadCmd, LC.Sections, Obj.isLittleEndian()); 125 } 126 127 template <typename StructType> 128 const char * 129 readString(MachOYAML::LoadCommand &LC, 130 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 131 auto Start = LoadCmd.Ptr + sizeof(StructType); 132 auto MaxSize = LoadCmd.C.cmdsize - sizeof(StructType); 133 auto Size = strnlen(Start, MaxSize); 134 LC.PayloadString = StringRef(Start, Size).str(); 135 return Start + Size; 136 } 137 138 template <> 139 const char *MachODumper::processLoadCommandData<MachO::dylib_command>( 140 MachOYAML::LoadCommand &LC, 141 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 142 return readString<MachO::dylib_command>(LC, LoadCmd); 143 } 144 145 template <> 146 const char *MachODumper::processLoadCommandData<MachO::dylinker_command>( 147 MachOYAML::LoadCommand &LC, 148 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { 149 return readString<MachO::dylinker_command>(LC, LoadCmd); 150 } 151 152 Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { 153 auto Y = make_unique<MachOYAML::Object>(); 154 dumpHeader(Y); 155 dumpLoadCommands(Y); 156 dumpLinkEdit(Y); 157 return std::move(Y); 158 } 159 160 void MachODumper::dumpHeader(std::unique_ptr<MachOYAML::Object> &Y) { 161 Y->Header.magic = Obj.getHeader().magic; 162 Y->Header.cputype = Obj.getHeader().cputype; 163 Y->Header.cpusubtype = Obj.getHeader().cpusubtype; 164 Y->Header.filetype = Obj.getHeader().filetype; 165 Y->Header.ncmds = Obj.getHeader().ncmds; 166 Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds; 167 Y->Header.flags = Obj.getHeader().flags; 168 Y->Header.reserved = 0; 169 } 170 171 void MachODumper::dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y) { 172 for (auto LoadCmd : Obj.load_commands()) { 173 MachOYAML::LoadCommand LC; 174 const char *EndPtr = LoadCmd.Ptr; 175 switch (LoadCmd.C.cmd) { 176 default: 177 memcpy((void *)&(LC.Data.load_command_data), LoadCmd.Ptr, 178 sizeof(MachO::load_command)); 179 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) 180 MachO::swapStruct(LC.Data.load_command_data); 181 EndPtr = processLoadCommandData<MachO::load_command>(LC, LoadCmd); 182 break; 183 #include "llvm/Support/MachO.def" 184 } 185 auto RemainingBytes = LoadCmd.C.cmdsize - (EndPtr - LoadCmd.Ptr); 186 if (!std::all_of(EndPtr, &EndPtr[RemainingBytes], 187 [](const char C) { return C == 0; })) { 188 LC.PayloadBytes.insert(LC.PayloadBytes.end(), EndPtr, 189 &EndPtr[RemainingBytes]); 190 RemainingBytes = 0; 191 } 192 LC.ZeroPadBytes = RemainingBytes; 193 Y->LoadCommands.push_back(std::move(LC)); 194 } 195 } 196 197 void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) { 198 dumpRebaseOpcodes(Y); 199 dumpBindOpcodes(Y->LinkEdit.BindOpcodes, Obj.getDyldInfoBindOpcodes()); 200 dumpBindOpcodes(Y->LinkEdit.WeakBindOpcodes, 201 Obj.getDyldInfoWeakBindOpcodes()); 202 dumpBindOpcodes(Y->LinkEdit.LazyBindOpcodes, 203 Obj.getDyldInfoLazyBindOpcodes(), true); 204 } 205 206 void MachODumper::dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y) { 207 MachOYAML::LinkEditData &LEData = Y->LinkEdit; 208 209 auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes(); 210 for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end(); 211 ++OpCode) { 212 MachOYAML::RebaseOpcode RebaseOp; 213 RebaseOp.Opcode = 214 static_cast<MachO::RebaseOpcode>(*OpCode & MachO::REBASE_OPCODE_MASK); 215 RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK; 216 217 unsigned Count; 218 uint64_t ULEB = 0; 219 220 switch (RebaseOp.Opcode) { 221 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: 222 223 ULEB = decodeULEB128(OpCode + 1, &Count); 224 RebaseOp.ExtraData.push_back(ULEB); 225 OpCode += Count; 226 // Intentionally no break here -- This opcode has two ULEB values 227 case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 228 case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: 229 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: 230 case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: 231 232 ULEB = decodeULEB128(OpCode + 1, &Count); 233 RebaseOp.ExtraData.push_back(ULEB); 234 OpCode += Count; 235 break; 236 default: 237 break; 238 } 239 240 LEData.RebaseOpcodes.push_back(RebaseOp); 241 242 if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE) 243 break; 244 } 245 } 246 247 void MachODumper::dumpBindOpcodes( 248 std::vector<MachOYAML::BindOpcode> &BindOpcodes, 249 ArrayRef<uint8_t> OpcodeBuffer, bool Lazy) { 250 for (auto OpCode = OpcodeBuffer.begin(); OpCode != OpcodeBuffer.end(); 251 ++OpCode) { 252 MachOYAML::BindOpcode BindOp; 253 BindOp.Opcode = 254 static_cast<MachO::BindOpcode>(*OpCode & MachO::BIND_OPCODE_MASK); 255 BindOp.Imm = *OpCode & MachO::BIND_IMMEDIATE_MASK; 256 257 unsigned Count; 258 uint64_t ULEB = 0; 259 int64_t SLEB = 0; 260 const uint8_t *SymStart; 261 262 switch (BindOp.Opcode) { 263 case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: 264 ULEB = decodeULEB128(OpCode + 1, &Count); 265 BindOp.ULEBExtraData.push_back(ULEB); 266 OpCode += Count; 267 // Intentionally no break here -- this opcode has two ULEB values 268 269 case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: 270 case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 271 case MachO::BIND_OPCODE_ADD_ADDR_ULEB: 272 case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: 273 ULEB = decodeULEB128(OpCode + 1, &Count); 274 BindOp.ULEBExtraData.push_back(ULEB); 275 OpCode += Count; 276 break; 277 278 case MachO::BIND_OPCODE_SET_ADDEND_SLEB: 279 SLEB = decodeSLEB128(OpCode + 1, &Count); 280 BindOp.SLEBExtraData.push_back(SLEB); 281 OpCode += Count; 282 break; 283 284 case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: 285 SymStart = ++OpCode; 286 while (*OpCode) { 287 ++OpCode; 288 } 289 BindOp.Symbol = StringRef(reinterpret_cast<const char *>(SymStart), 290 OpCode - SymStart); 291 break; 292 default: 293 break; 294 } 295 296 BindOpcodes.push_back(BindOp); 297 298 // Lazy bindings have DONE opcodes between operations, so we need to keep 299 // processing after a DONE. 300 if (!Lazy && BindOp.Opcode == MachO::BIND_OPCODE_DONE) 301 break; 302 } 303 } 304 305 Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { 306 MachODumper Dumper(Obj); 307 Expected<std::unique_ptr<MachOYAML::Object>> YAML = Dumper.dump(); 308 if (!YAML) 309 return YAML.takeError(); 310 311 yaml::Output Yout(Out); 312 Yout << *(YAML.get()); 313 return Error::success(); 314 } 315 316 Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { 317 return make_error<Obj2YamlError>(obj2yaml_error::not_implemented); 318 } 319 320 std::error_code macho2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { 321 if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Obj)) { 322 if (auto Err = macho2yaml(Out, *MachOObj)) { 323 return errorToErrorCode(std::move(Err)); 324 } 325 return obj2yaml_error::success; 326 } 327 328 if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) { 329 if (auto Err = macho2yaml(Out, *MachOObj)) { 330 return errorToErrorCode(std::move(Err)); 331 } 332 return obj2yaml_error::success; 333 } 334 335 return obj2yaml_error::unsupported_obj_file_format; 336 } 337