Browse Source

LibELF+LibCoreDump: Add a Metadata notes entry

This is a new NotesEntry type which will allow applications to embed
arbitrary metadata in crashdumps (stored as a JSON string). It will be
used to store an assertion message, for example.
Linus Groh 4 years ago
parent
commit
7413a7c509
3 changed files with 42 additions and 2 deletions
  1. 32 1
      Libraries/LibCoreDump/Reader.cpp
  2. 3 1
      Libraries/LibCoreDump/Reader.h
  3. 7 0
      Libraries/LibELF/CoreDump.h

+ 32 - 1
Libraries/LibCoreDump/Reader.cpp

@@ -24,6 +24,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <AK/JsonObject.h>
+#include <AK/JsonValue.h>
 #include <LibCoreDump/Backtrace.h>
 #include <LibCoreDump/Reader.h>
 #include <string.h>
@@ -69,6 +71,7 @@ ELF::Core::NotesEntryHeader::Type Reader::NotesEntryIterator::type() const
     ASSERT(m_current->header.type == ELF::Core::NotesEntryHeader::Type::ProcessInfo
         || m_current->header.type == ELF::Core::NotesEntryHeader::Type::MemoryRegionInfo
         || m_current->header.type == ELF::Core::NotesEntryHeader::Type::ThreadInfo
+        || m_current->header.type == ELF::Core::NotesEntryHeader::Type::Metadata
         || m_current->header.type == ELF::Core::NotesEntryHeader::Type::Null);
     return m_current->header.type;
 }
@@ -97,6 +100,11 @@ void Reader::NotesEntryIterator::next()
         m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current->region_name + strlen(current->region_name) + 1);
         break;
     }
+    case ELF::Core::NotesEntryHeader::Type::Metadata: {
+        const auto* current = reinterpret_cast<const ELF::Core::Metadata*>(m_current);
+        m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current->json_data + strlen(current->json_data) + 1);
+        break;
+    }
     default:
         ASSERT_NOT_REACHED();
     }
@@ -141,9 +149,32 @@ const ELF::Core::MemoryRegionInfo* Reader::region_containing(FlatPtr address) co
     return ret;
 }
 
-Backtrace Reader::backtrace() const
+const Backtrace Reader::backtrace() const
 {
     return Backtrace(*this);
 }
 
+const HashMap<String, String> Reader::metadata() const
+{
+    const ELF::Core::Metadata* metadata_notes_entry = nullptr;
+    for (NotesEntryIterator it((const u8*)m_coredump_image.program_header(m_notes_segment_index).raw_data()); !it.at_end(); it.next()) {
+        if (it.type() != ELF::Core::NotesEntryHeader::Type::Metadata)
+            continue;
+        metadata_notes_entry = reinterpret_cast<const ELF::Core::Metadata*>(it.current());
+        break;
+    }
+    if (!metadata_notes_entry)
+        return {};
+    auto metadata_json_value = JsonValue::from_string(metadata_notes_entry->json_data);
+    if (!metadata_json_value.has_value())
+        return {};
+    if (!metadata_json_value.value().is_object())
+        return {};
+    HashMap<String, String> metadata;
+    metadata_json_value.value().as_object().for_each_member([&](auto& key, auto& value) {
+        metadata.set(key, value.as_string_or({}));
+    });
+    return metadata;
+}
+
 }

+ 3 - 1
Libraries/LibCoreDump/Reader.h

@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include <AK/HashMap.h>
 #include <AK/MappedFile.h>
 #include <AK/Noncopyable.h>
 #include <AK/OwnPtr.h>
@@ -57,7 +58,8 @@ public:
     Optional<uint32_t> peek_memory(FlatPtr address) const;
     const ELF::Core::MemoryRegionInfo* region_containing(FlatPtr address) const;
 
-    Backtrace backtrace() const;
+    const Backtrace backtrace() const;
+    const HashMap<String, String> metadata() const;
 
 private:
     class NotesEntryIterator {

+ 7 - 0
Libraries/LibELF/CoreDump.h

@@ -39,6 +39,7 @@ struct [[gnu::packed]] NotesEntryHeader
         ProcessInfo,
         ThreadInfo,
         MemoryRegionInfo,
+        Metadata,
     };
     Type type;
 };
@@ -82,4 +83,10 @@ struct [[gnu::packed]] MemoryRegionInfo
     }
 };
 
+struct [[gnu::packed]] Metadata
+{
+    NotesEntryHeader header;
+    char json_data[]; // Null terminated
+};
+
 }