With this patch, I get the following loading a FreeBSD 10.0.510 elf object file:

tfiala-macpro:lldb tfiala$ DerivedData/lldb/Build/Products/Debug/lldb
(lldb) log enable lldb modules
(lldb) file /tmp/ls-freebsd
...
<lldb.driver.main-thread> ObjectFileELF::RefineModuleDetailsFromNote parsing 
note name='FreeBSD', type=1
<lldb.driver.main-thread> ObjectFileELF::RefineModuleDetailsFromNote detected 
FreeBSD 10.0.510
...
Current executable set to '/tmp/ls-freebsd' (x86_64).
(lldb) image list -b -t
[  0] ls-freebsd x86_64-unknown-freebsd10.0
(lldb)

http://reviews.llvm.org/D4302

Files:
  source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
  source/Plugins/ObjectFile/ELF/ObjectFileELF.h
Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
===================================================================
--- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -41,6 +41,23 @@
 using namespace llvm::ELF;
 
 namespace {
+
+// ELF note owner definitions
+const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
+const char *const LLDB_NT_OWNER_GNU     = "GNU";
+const char *const LLDB_NT_OWNER_NETBSD  = "NetBSD";
+
+// ELF note type definitions
+const elf_word LLDB_NT_FREEBSD_ABI_TAG  = 0x01;
+const elf_word LLDB_NT_GNU_ABI_TAG      = 0x01;
+const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03;
+const elf_word LLDB_NT_NETBSD_ABI_TAG   = 0x01;
+
+// GNU ABI note OS constants
+const elf_word LLDB_NT_GNU_ABI_OS_LINUX   = 0x00;
+const elf_word LLDB_NT_GNU_ABI_OS_HURD    = 0x01;
+const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02;
+
 //===----------------------------------------------------------------------===//
 /// @class ELFRelocation
 /// @brief Generic wrapper for ELFRel and ELFRela.
@@ -448,6 +465,55 @@
     return core_notes_crc;
 }
 
+static const char*
+OSABIAsCString (unsigned char osabi_byte)
+{
+#define _MAKE_OSABI_CASE(x) case x: return #x
+    switch (osabi_byte)
+    {
+        _MAKE_OSABI_CASE(ELFOSABI_NONE);
+        _MAKE_OSABI_CASE(ELFOSABI_HPUX);
+        _MAKE_OSABI_CASE(ELFOSABI_NETBSD);
+        _MAKE_OSABI_CASE(ELFOSABI_GNU);
+        _MAKE_OSABI_CASE(ELFOSABI_HURD);
+        _MAKE_OSABI_CASE(ELFOSABI_SOLARIS);
+        _MAKE_OSABI_CASE(ELFOSABI_AIX);
+        _MAKE_OSABI_CASE(ELFOSABI_IRIX);
+        _MAKE_OSABI_CASE(ELFOSABI_FREEBSD);
+        _MAKE_OSABI_CASE(ELFOSABI_TRU64);
+        _MAKE_OSABI_CASE(ELFOSABI_MODESTO);
+        _MAKE_OSABI_CASE(ELFOSABI_OPENBSD);
+        _MAKE_OSABI_CASE(ELFOSABI_OPENVMS);
+        _MAKE_OSABI_CASE(ELFOSABI_NSK);
+        _MAKE_OSABI_CASE(ELFOSABI_AROS);
+        _MAKE_OSABI_CASE(ELFOSABI_FENIXOS);
+        _MAKE_OSABI_CASE(ELFOSABI_C6000_ELFABI);
+        _MAKE_OSABI_CASE(ELFOSABI_C6000_LINUX);
+        _MAKE_OSABI_CASE(ELFOSABI_ARM);
+        _MAKE_OSABI_CASE(ELFOSABI_STANDALONE);
+        default:
+            return "<unknown-osabi>";
+    }
+#undef _MAKE_OSABI_CASE
+}
+
+static bool
+GetOsFromOSABI (unsigned char osabi_byte, llvm::Triple::OSType &ostype)
+{
+    switch (osabi_byte)
+    {
+        case ELFOSABI_AIX:      ostype = llvm::Triple::OSType::AIX; break;
+        case ELFOSABI_FREEBSD:  ostype = llvm::Triple::OSType::FreeBSD; break;
+        case ELFOSABI_GNU:      ostype = llvm::Triple::OSType::Linux; break;
+        case ELFOSABI_NETBSD:   ostype = llvm::Triple::OSType::NetBSD; break;
+        case ELFOSABI_OPENBSD:  ostype = llvm::Triple::OSType::OpenBSD; break;
+        case ELFOSABI_SOLARIS:  ostype = llvm::Triple::OSType::Solaris; break;
+        default:
+            ostype = llvm::Triple::OSType::UnknownOS;
+    }
+    return ostype != llvm::Triple::OSType::UnknownOS;
+}
+
 size_t
 ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
                                         lldb::DataBufferSP& data_sp,
@@ -456,6 +522,8 @@
                                         lldb::offset_t length,
                                         lldb_private::ModuleSpecList &specs)
 {
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+
     const size_t initial_count = specs.GetSize();
 
     if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
@@ -474,14 +542,23 @@
                                                        LLDB_INVALID_CPUTYPE);
                 if (spec.GetArchitecture().IsValid())
                 {
-                    // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the
-                    // machine information. However, this info isn't guaranteed to exist or be correct. Details:
-                    //  http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
-                    // Instead of passing potentially incorrect information down the pipeline, grab
-                    // the host information and use it.
-                    spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString());
-                    spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString());
+                    llvm::Triple::OSType ostype;
+                    // First try to determine the OS type from the OSABI field in the elf header.
 
+                    if (log)
+                        log->Printf ("ObjectFileELF::%s file '%s' module OSABI: %s", __FUNCTION__, file.GetPath ().c_str (), OSABIAsCString (header.e_ident[EI_OSABI]));
+                    if (GetOsFromOSABI (header.e_ident[EI_OSABI], ostype) && ostype != llvm::Triple::OSType::UnknownOS)
+                    {
+                        spec.GetArchitecture ().GetTriple ().setOS (ostype);
+
+                        // Also clear the vendor so we don't end up with situations like
+                        // x86_64-apple-FreeBSD.
+                        spec.GetArchitecture ().GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+                        if (log)
+                            log->Printf ("ObjectFileELF::%s file '%s' set ELF module OS type from ELF header OSABI.", __FUNCTION__, file.GetPath ().c_str ());
+                    }
+
                     // Try to get the UUID from the section list. Usually that's at the end, so
                     // map the file in if we don't have it already.
                     size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize;
@@ -495,9 +572,21 @@
                     std::string gnu_debuglink_file;
                     SectionHeaderColl section_headers;
                     lldb_private::UUID &uuid = spec.GetUUID();
-                    GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc);
 
+                    GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture ());
 
+                    // If the module vendor is not set and the module OS matches this host OS, set the module vendor to the host vendor.
+                    llvm::Triple &spec_triple = spec.GetArchitecture ().GetTriple ();
+                    if (spec_triple.getVendor () == llvm::Triple::VendorType::UnknownVendor)
+                    {
+                        const llvm::Triple &host_triple = Host::GetArchitecture ().GetTriple ();
+                        if (spec_triple.getOS () == host_triple.getOS ())
+                            spec_triple.setVendor (host_triple.getVendor ());
+                    }
+
+                    if (log)
+                        log->Printf ("ObjectFileELF::%s file '%s' module set to triple: %s (architecture %s)", __FUNCTION__, file.GetPath ().c_str (), spec_triple.getTriple ().c_str (), spec.GetArchitecture ().GetArchitectureName ());
+
                     if (!uuid.IsValid())
                     {
                         uint32_t core_notes_crc = 0;
@@ -596,15 +685,19 @@
                               lldb::offset_t length) : 
     ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
     m_header(),
+    m_uuid(),
+    m_gnu_debuglink_file(),
+    m_gnu_debuglink_crc(0),
     m_program_headers(),
     m_section_headers(),
-    m_filespec_ap()
+    m_dynamic_symbols(),
+    m_filespec_ap(),
+    m_entry_point_address(),
+    m_arch_spec()
 {
     if (file)
         m_file = *file;
     ::memset(&m_header, 0, sizeof(m_header));
-    m_gnu_debuglink_crc = 0;
-    m_gnu_debuglink_file.clear();
 }
 
 ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
@@ -613,9 +706,15 @@
                               addr_t header_addr) :
     ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, data_sp),
     m_header(),
+    m_uuid(),
+    m_gnu_debuglink_file(),
+    m_gnu_debuglink_crc(0),
     m_program_headers(),
     m_section_headers(),
-    m_filespec_ap()
+    m_dynamic_symbols(),
+    m_filespec_ap(),
+    m_entry_point_address(),
+    m_arch_spec()
 {
     ::memset(&m_header, 0, sizeof(m_header));
 }
@@ -963,35 +1062,170 @@
     return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
 }
 
-static bool
-ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid)
+lldb_private::Error
+ObjectFileELF::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid)
 {
-    // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id.
-    // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+    Error error;
+
     lldb::offset_t offset = 0;
-    static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h
 
     while (true)
     {
+        // Parse the note header.  If this fails, bail out.
         ELFNote note = ELFNote();
         if (!note.Parse(data, &offset))
-            return false;
+        {
+            // We're done.
+            return error;
+        }
 
-        // 16 bytes is UUID|MD5, 20 bytes is SHA1
-        if (note.n_name == "GNU" && (note.n_type == g_gnu_build_id) &&
-            (note.n_descsz == 16 || note.n_descsz == 20))
+        // If a tag processor handles the tag, it should set processed to true, and
+        // the loop will assume the tag processing has moved entirely past the note's payload.
+        // Otherwise, leave it false and the end of the loop will handle the offset properly.
+        bool processed = false;
+
+        if (log)
+            log->Printf ("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, __FUNCTION__, note.n_name.c_str (), note.n_type);
+
+        // Process FreeBSD ELF notes.
+        if (note.n_name == LLDB_NT_OWNER_FREEBSD)
         {
-            uint8_t uuidbuf[20]; 
-            if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == NULL)
-                return false;
-            uuid.SetBytes (uuidbuf, note.n_descsz);
-            return true;
+            if (note.n_type == LLDB_NT_FREEBSD_ABI_TAG)
+            {
+                // We'll consume the payload below.
+                processed = true;
+
+                // Pull out the min version info.
+                uint32_t version_info;
+                if (data.GetU32 (&offset, &version_info, 1) == nullptr)
+                {
+                    error.SetErrorString ("failed to read FreeBSD ABI note payload");
+                    return error;
+                }
+
+                // Convert the version info into a major/minor number.
+                const uint32_t version_major = version_info / 100000;
+                const uint32_t version_minor = (version_info / 1000) % 100;
+
+                char os_name[32];
+                snprintf (os_name, sizeof (os_name), "freebsd%" PRIu32 ".%" PRIu32, version_major, version_minor);
+
+                // Set the elf OS version to FreeBSD.  Also clear the vendor.
+                arch_spec.GetTriple ().setOSName (os_name);
+                arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+                if (log)
+                    log->Printf ("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_major, version_minor, static_cast<uint32_t> (version_info % 1000));
+            }
         }
-        offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
+        // Process GNU ELF notes.
+        else if (note.n_name == LLDB_NT_OWNER_GNU)
+        {
+            switch (note.n_type)
+            {
+                case LLDB_NT_GNU_ABI_TAG:
+                    {
+                        // We'll consume the payload below.
+                        processed = true;
+
+                        // Pull out the min OS version supporting the ABI.
+                        uint32_t version_info[4];
+                        if (data.GetU32 (&offset, &version_info[0], note.n_descsz / 4) == nullptr)
+                        {
+                            error.SetErrorString ("failed to read GNU ABI note payload");
+                            return error;
+                        }
+
+                        // Set the OS per the OS field.
+                        switch (version_info[0])
+                        {
+                            case LLDB_NT_GNU_ABI_OS_LINUX:
+                                arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Linux);
+                                arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+                                if (log)
+                                    log->Printf ("ObjectFileELF::%s detected Linux, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+                                // FIXME we have the minimal version number, we could be propagating that.  version_info[1] = OS Major, version_info[2] = OS Minor, version_info[3] = Revision.
+                                break;
+                            case LLDB_NT_GNU_ABI_OS_HURD:
+                                arch_spec.GetTriple ().setOS (llvm::Triple::OSType::UnknownOS);
+                                arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+                                if (log)
+                                    log->Printf ("ObjectFileELF::%s detected Hurd (unsupported), min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+                                break;
+                            case LLDB_NT_GNU_ABI_OS_SOLARIS:
+                                arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Solaris);
+                                arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+                                if (log)
+                                    log->Printf ("ObjectFileELF::%s detected Solaris, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+                                break;
+                            default:
+                                if (log)
+                                    log->Printf ("ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[0], version_info[1], version_info[2], version_info[3]);
+                                break;
+                        }
+                    }
+                    break;
+
+                case LLDB_NT_GNU_BUILD_ID_TAG:
+                    // Only bother processing this if we don't already have the uuid set.
+                    if (!uuid.IsValid())
+                    {
+                        // We'll consume the payload below.
+                        processed = true;
+
+                        // 16 bytes is UUID|MD5, 20 bytes is SHA1
+                        if ((note.n_descsz == 16 || note.n_descsz == 20))
+                        {
+                            uint8_t uuidbuf[20];
+                            if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == nullptr)
+                            {
+                                error.SetErrorString ("failed to read GNU_BUILD_ID note payload");
+                                return error;
+                            }
+
+                            // Save the build id as the UUID for the module.
+                            uuid.SetBytes (uuidbuf, note.n_descsz);
+                        }
+                    }
+                    break;
+            }
+        }
+        // Process NetBSD ELF notes.
+        else if (note.n_name == LLDB_NT_OWNER_NETBSD)
+        {
+            if (note.n_type == LLDB_NT_NETBSD_ABI_TAG)
+            {
+
+                // We'll consume the payload below.
+                processed = true;
+
+                // Pull out the min version info.
+                uint32_t version_info;
+                if (data.GetU32 (&offset, &version_info, 1) == nullptr)
+                {
+                    error.SetErrorString ("failed to read NetBSD ABI note payload");
+                    return error;
+                }
+
+                // Set the elf OS version to NetBSD.  Also clear the vendor.
+                arch_spec.GetTriple ().setOS (llvm::Triple::OSType::NetBSD);
+                arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+                if (log)
+                    log->Printf ("ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, __FUNCTION__, version_info);
+            }
+        }
+        // Add other OS version notes here.
+
+        if (!processed)
+            offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
     }
-    return false;
+
+    return error;
 }
 
+
 //----------------------------------------------------------------------
 // GetSectionHeaderInfo
 //----------------------------------------------------------------------
@@ -1001,8 +1235,18 @@
                                     const elf::ELFHeader &header,
                                     lldb_private::UUID &uuid,
                                     std::string &gnu_debuglink_file,
-                                    uint32_t &gnu_debuglink_crc)
+                                    uint32_t &gnu_debuglink_crc,
+                                    ArchSpec &arch_spec)
 {
+    // Only intialize the arch_spec to okay defaults if they're not already set.
+    // We'll refine this with note data as we parse the notes.
+    if (arch_spec.GetTriple ().getOS () == llvm::Triple::OSType::UnknownOS)
+    {
+        arch_spec.SetArchitecture (eArchTypeELF, header.e_machine, LLDB_INVALID_CPUTYPE);
+        arch_spec.GetTriple().setOSName (Host::GetOSString().GetCString());
+        arch_spec.GetTriple().setVendorName(Host::GetVendorString().GetCString());
+    }
+
     // We have already parsed the section headers
     if (!section_headers.empty())
         return section_headers.size();
@@ -1011,6 +1255,8 @@
     if (header.e_shnum == 0)
         return 0;
 
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+
     section_headers.resize(header.e_shnum);
     if (section_headers.size() != header.e_shnum)
         return 0;
@@ -1063,12 +1309,19 @@
                     }
                 }
 
-                if (header.sh_type == SHT_NOTE && !uuid.IsValid())
+                // Process ELF note section entries.
+                if (header.sh_type == SHT_NOTE)
                 {
+                    // Allow notes to refine module info.
                     DataExtractor data;
                     if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
                     {
-                        ParseNoteGNUBuildID (data, uuid);
+                        Error error = RefineModuleDetailsFromNote (data, arch_spec, uuid);
+                        if (error.Fail ())
+                        {
+                            if (log)
+                                log->Printf ("ObjectFileELF::%s ELF note processing failed: %s", __FUNCTION__, error.AsCString ());
+                        }
                     }
                 }
             }
@@ -1114,7 +1367,7 @@
 size_t
 ObjectFileELF::ParseSectionHeaders()
 {
-    return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc);
+    return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
 }
 
 const ObjectFileELF::ELFSectionHeaderInfo *
@@ -2309,12 +2562,10 @@
 bool
 ObjectFileELF::GetArchitecture (ArchSpec &arch)
 {
-    if (!ParseHeader())
+    if (!ParseHeader() || !ParseSectionHeaders())
         return false;
 
-    arch.SetArchitecture (eArchTypeELF, m_header.e_machine, LLDB_INVALID_CPUTYPE);
-    arch.GetTriple().setOSName (Host::GetOSString().GetCString());
-    arch.GetTriple().setVendorName(Host::GetVendorString().GetCString());
+    arch = m_arch_spec;
     return true;
 }
 
Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.h
===================================================================
--- source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -17,6 +17,7 @@
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Core/UUID.h"
+#include "lldb/Core/ArchSpec.h"
 
 #include "ELFHeader.h"
 
@@ -242,6 +243,9 @@
     /// Cached value of the entry point for this module.
     lldb_private::Address  m_entry_point_address;
 
+    /// The architecture detected from parsing elf file contents.
+    lldb_private::ArchSpec m_arch_spec;
+
     /// Returns a 1 based index of the given section header.
     size_t
     SectionIndex(const SectionHeaderCollIter &I);
@@ -273,14 +277,15 @@
     size_t
     ParseSectionHeaders();
 
-    /// Parses the elf section headers and returns the uuid, debug link name, crc.
+    /// Parses the elf section headers and returns the uuid, debug link name, crc, archspec.
     static size_t
     GetSectionHeaderInfo(SectionHeaderColl &section_headers,
                          lldb_private::DataExtractor &data,
                          const elf::ELFHeader &header,
                          lldb_private::UUID &uuid,
                          std::string &gnu_debuglink_file,
-                         uint32_t &gnu_debuglink_crc);
+                         uint32_t &gnu_debuglink_crc,
+                         lldb_private::ArchSpec &arch_spec);
 
     /// Scans the dynamic section and locates all dependent modules (shared
     /// libraries) populating m_filespec_ap.  This method will compute the
@@ -407,6 +412,9 @@
         
     unsigned
     PLTRelocationType();
+
+    static lldb_private::Error
+    RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid);
 };
 
 #endif // #ifndef liblldb_ObjectFileELF_h_
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to