Home | History | Annotate | Download | only in Universal-Mach-O
      1 //===-- ObjectContainerUniversalMachO.cpp -----------------------*- 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 "ObjectContainerUniversalMachO.h"
     11 #include "lldb/Core/ArchSpec.h"
     12 #include "lldb/Core/DataBuffer.h"
     13 #include "lldb/Core/Module.h"
     14 #include "lldb/Core/ModuleSpec.h"
     15 #include "lldb/Core/PluginManager.h"
     16 #include "lldb/Core/Stream.h"
     17 #include "lldb/Symbol/ObjectFile.h"
     18 #include "lldb/Target/Target.h"
     19 
     20 using namespace lldb;
     21 using namespace lldb_private;
     22 using namespace llvm::MachO;
     23 
     24 void
     25 ObjectContainerUniversalMachO::Initialize()
     26 {
     27     PluginManager::RegisterPlugin (GetPluginNameStatic(),
     28                                    GetPluginDescriptionStatic(),
     29                                    CreateInstance,
     30                                    GetModuleSpecifications);
     31 }
     32 
     33 void
     34 ObjectContainerUniversalMachO::Terminate()
     35 {
     36     PluginManager::UnregisterPlugin (CreateInstance);
     37 }
     38 
     39 
     40 lldb_private::ConstString
     41 ObjectContainerUniversalMachO::GetPluginNameStatic()
     42 {
     43     static ConstString g_name("mach-o");
     44     return g_name;
     45 }
     46 
     47 const char *
     48 ObjectContainerUniversalMachO::GetPluginDescriptionStatic()
     49 {
     50     return "Universal mach-o object container reader.";
     51 }
     52 
     53 
     54 ObjectContainer *
     55 ObjectContainerUniversalMachO::CreateInstance
     56 (
     57     const lldb::ModuleSP &module_sp,
     58     DataBufferSP& data_sp,
     59     lldb::offset_t data_offset,
     60     const FileSpec *file,
     61     lldb::offset_t file_offset,
     62     lldb::offset_t length
     63 )
     64 {
     65     // We get data when we aren't trying to look for cached container information,
     66     // so only try and look for an architecture slice if we get data
     67     if (data_sp)
     68     {
     69         DataExtractor data;
     70         data.SetData (data_sp, data_offset, length);
     71         if (ObjectContainerUniversalMachO::MagicBytesMatch(data))
     72         {
     73             std::unique_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module_sp, data_sp, data_offset, file, file_offset, length));
     74             if (container_ap->ParseHeader())
     75             {
     76                 return container_ap.release();
     77             }
     78         }
     79     }
     80     return NULL;
     81 }
     82 
     83 bool
     84 ObjectContainerUniversalMachO::MagicBytesMatch (const DataExtractor &data)
     85 {
     86     lldb::offset_t offset = 0;
     87     uint32_t magic = data.GetU32(&offset);
     88     return magic == UniversalMagic || magic == UniversalMagicSwapped;
     89 }
     90 
     91 ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
     92 (
     93     const lldb::ModuleSP &module_sp,
     94     DataBufferSP& data_sp,
     95     lldb::offset_t data_offset,
     96     const FileSpec *file,
     97     lldb::offset_t file_offset,
     98     lldb::offset_t length
     99 ) :
    100     ObjectContainer (module_sp, file, file_offset, length, data_sp, data_offset),
    101     m_header(),
    102     m_fat_archs()
    103 {
    104     memset(&m_header, 0, sizeof(m_header));
    105 }
    106 
    107 
    108 ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
    109 {
    110 }
    111 
    112 bool
    113 ObjectContainerUniversalMachO::ParseHeader ()
    114 {
    115     bool success = ParseHeader (m_data, m_header, m_fat_archs);
    116     // We no longer need any data, we parsed all we needed to parse
    117     // and cached it in m_header and m_fat_archs
    118     m_data.Clear();
    119     return success;
    120 }
    121 
    122 bool
    123 ObjectContainerUniversalMachO::ParseHeader (lldb_private::DataExtractor &data,
    124                                             llvm::MachO::fat_header &header,
    125                                             std::vector<llvm::MachO::fat_arch> &fat_archs)
    126 {
    127     bool success = false;
    128     // Store the file offset for this universal file as we could have a universal .o file
    129     // in a BSD archive, or be contained in another kind of object.
    130     // Universal mach-o files always have their headers in big endian.
    131     lldb::offset_t offset = 0;
    132     data.SetByteOrder (eByteOrderBig);
    133     header.magic = data.GetU32(&offset);
    134     fat_archs.clear();
    135 
    136     if (header.magic == UniversalMagic)
    137     {
    138 
    139         data.SetAddressByteSize(4);
    140 
    141         header.nfat_arch = data.GetU32(&offset);
    142 
    143         // Now we should have enough data for all of the fat headers, so lets index
    144         // them so we know how many architectures that this universal binary contains.
    145         uint32_t arch_idx = 0;
    146         for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx)
    147         {
    148             if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch)))
    149             {
    150                 fat_arch arch;
    151                 if (data.GetU32(&offset, &arch, sizeof(fat_arch)/sizeof(uint32_t)))
    152                     fat_archs.push_back(arch);
    153             }
    154         }
    155         success = true;
    156     }
    157     else
    158     {
    159         memset(&header, 0, sizeof(header));
    160     }
    161     return success;
    162 }
    163 
    164 void
    165 ObjectContainerUniversalMachO::Dump (Stream *s) const
    166 {
    167     s->Printf("%p: ", this);
    168     s->Indent();
    169     const size_t num_archs = GetNumArchitectures();
    170     const size_t num_objects = GetNumObjects();
    171     s->Printf("ObjectContainerUniversalMachO, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
    172     uint32_t i;
    173     ArchSpec arch;
    174     s->IndentMore();
    175     for (i=0; i<num_archs; i++)
    176     {
    177         s->Indent();
    178         GetArchitectureAtIndex(i, arch);
    179         s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
    180     }
    181     for (i=0; i<num_objects; i++)
    182     {
    183         s->Indent();
    184         s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
    185     }
    186     s->IndentLess();
    187     s->EOL();
    188 }
    189 
    190 size_t
    191 ObjectContainerUniversalMachO::GetNumArchitectures () const
    192 {
    193     return m_header.nfat_arch;
    194 }
    195 
    196 bool
    197 ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
    198 {
    199     if (idx < m_header.nfat_arch)
    200     {
    201         arch.SetArchitecture (eArchTypeMachO, m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
    202         return true;
    203     }
    204     return false;
    205 }
    206 
    207 ObjectFileSP
    208 ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
    209 {
    210     uint32_t arch_idx = 0;
    211     ArchSpec arch;
    212     // If the module hasn't specified an architecture yet, set it to the default
    213     // architecture:
    214     ModuleSP module_sp (GetModule());
    215     if (module_sp)
    216     {
    217         if (!module_sp->GetArchitecture().IsValid())
    218         {
    219             arch = Target::GetDefaultArchitecture ();
    220             if (!arch.IsValid())
    221                 arch.SetTriple (LLDB_ARCH_DEFAULT);
    222         }
    223         else
    224             arch = module_sp->GetArchitecture();
    225 
    226         ArchSpec curr_arch;
    227         // First, try to find an exact match for the Arch of the Target.
    228         for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
    229         {
    230             if (GetArchitectureAtIndex (arch_idx, curr_arch) && arch.IsExactMatch(curr_arch))
    231                 break;
    232         }
    233 
    234         // Failing an exact match, try to find a compatible Arch of the Target.
    235         if (arch_idx >= m_header.nfat_arch)
    236         {
    237             for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
    238             {
    239                 if (GetArchitectureAtIndex (arch_idx, curr_arch) && arch.IsCompatibleMatch(curr_arch))
    240                     break;
    241             }
    242         }
    243 
    244         if (arch_idx < m_header.nfat_arch)
    245         {
    246             DataBufferSP data_sp;
    247             lldb::offset_t data_offset = 0;
    248             return ObjectFile::FindPlugin (module_sp,
    249                                            file,
    250                                            m_offset + m_fat_archs[arch_idx].offset,
    251                                            m_fat_archs[arch_idx].size,
    252                                            data_sp,
    253                                            data_offset);
    254         }
    255     }
    256     return ObjectFileSP();
    257 }
    258 
    259 
    260 //------------------------------------------------------------------
    261 // PluginInterface protocol
    262 //------------------------------------------------------------------
    263 lldb_private::ConstString
    264 ObjectContainerUniversalMachO::GetPluginName()
    265 {
    266     return GetPluginNameStatic();
    267 }
    268 
    269 uint32_t
    270 ObjectContainerUniversalMachO::GetPluginVersion()
    271 {
    272     return 1;
    273 }
    274 
    275 
    276 size_t
    277 ObjectContainerUniversalMachO::GetModuleSpecifications (const lldb_private::FileSpec& file,
    278                                                         lldb::DataBufferSP& data_sp,
    279                                                         lldb::offset_t data_offset,
    280                                                         lldb::offset_t file_offset,
    281                                                         lldb::offset_t file_size,
    282                                                         lldb_private::ModuleSpecList &specs)
    283 {
    284     const size_t initial_count = specs.GetSize();
    285 
    286     DataExtractor data;
    287     data.SetData (data_sp, data_offset, data_sp->GetByteSize());
    288 
    289     if (ObjectContainerUniversalMachO::MagicBytesMatch(data))
    290     {
    291         llvm::MachO::fat_header header;
    292         std::vector<llvm::MachO::fat_arch> fat_archs;
    293         if (ParseHeader (data, header, fat_archs))
    294         {
    295             for (const llvm::MachO::fat_arch &fat_arch : fat_archs)
    296             {
    297                 const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
    298                 if (fat_arch.offset < file_size && file_size > slice_file_offset)
    299                 {
    300                     ObjectFile::GetModuleSpecifications (file,
    301                                                          slice_file_offset,
    302                                                          file_size - slice_file_offset,
    303                                                          specs);
    304                 }
    305             }
    306         }
    307     }
    308     return specs.GetSize() - initial_count;
    309 }
    310 
    311