[Lldb-commits] [lldb] 2cab996 - Add "process metadata" Mach-O LC_NOTE for corefiles

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 11 16:46:25 PDT 2023


Author: Jason Molenda
Date: 2023-09-11T16:46:18-07:00
New Revision: 2cab996192cf143d10e3381fcefa75e270cc7ddb

URL: https://github.com/llvm/llvm-project/commit/2cab996192cf143d10e3381fcefa75e270cc7ddb
DIFF: https://github.com/llvm/llvm-project/commit/2cab996192cf143d10e3381fcefa75e270cc7ddb.diff

LOG: Add "process metadata" Mach-O LC_NOTE for corefiles

Add a new LC_NOTE for Mach-O corefiles, "proces metadata", which is a
JSON string.  Currently there may be a `threads` key in the JSON,
and if `threads` is present, it is an array with the same number of
elements as there are LC_THREADs in the corefile.  This patch adds
support for a `thread_id` key-value for each `thread` entry, to
supply a thread ID for that LC_THREAD.

Differential Revision: https://reviews.llvm.org/D158785
rdar://113037252

Added: 
    

Modified: 
    lldb/include/lldb/Symbol/ObjectFile.h
    lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
    lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
    lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
    lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
    lldb/source/Plugins/Process/mach-core/ThreadMachCore.h
    lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index 9519635c24f9ff..6348d8103f85de 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -538,6 +538,30 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
     return false;
   }
 
+  /// Get metadata about threads from the corefile.
+  ///
+  /// The corefile may have metadata (e.g. a Mach-O "thread extrainfo"
+  /// LC_NOTE) which for the threads in the process; this method tries
+  /// to retrieve them.
+  ///
+  /// \param[out] tids
+  ///     Filled in with a vector of tid_t's that matches the number
+  ///     of threads in the corefile (ObjectFile::GetNumThreadContexts).
+  ///     If a tid is not specified for one of the corefile threads,
+  ///     that entry in the vector will have LLDB_INVALID_THREAD_ID and
+  ///     the caller should assign a tid to the thread that does not
+  ///     conflict with the ones provided in this array.
+  ///     As additional metadata are added, this method may return a
+  ///     \a tids vector with no thread id's specified at all; the
+  ///     corefile may only specify one of the other metadata.
+  ///
+  /// \return
+  ///     Returns true if thread metadata was found in this corefile.
+  ///
+  virtual bool GetCorefileThreadExtraInfos(std::vector<lldb::tid_t> &tids) {
+    return false;
+  }
+
   virtual lldb::RegisterContextSP
   GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) {
     return lldb::RegisterContextSP();

diff  --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 3ce2057d537227..efcfdf5ac2cd37 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5415,17 +5415,14 @@ uint32_t ObjectFileMachO::GetNumThreadContexts() {
   return m_thread_context_offsets.GetSize();
 }
 
-std::string ObjectFileMachO::GetIdentifierString() {
-  std::string result;
-  Log *log(
-      GetLog(LLDBLog::Symbols | LLDBLog::Process | LLDBLog::DynamicLoader));
+std::vector<std::tuple<offset_t, offset_t>>
+ObjectFileMachO::FindLC_NOTEByName(std::string name) {
+  std::vector<std::tuple<offset_t, offset_t>> results;
   ModuleSP module_sp(GetModule());
   if (module_sp) {
     std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
 
-    // First, look over the load commands for an LC_NOTE load command with
-    // data_owner string "kern ver str" & use that if found.
-    lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+    offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
     for (uint32_t i = 0; i < m_header.ncmds; ++i) {
       const uint32_t cmd_offset = offset;
       llvm::MachO::load_command lc = {};
@@ -5436,58 +5433,67 @@ std::string ObjectFileMachO::GetIdentifierString() {
         m_data.CopyData(offset, 16, data_owner);
         data_owner[16] = '\0';
         offset += 16;
-        uint64_t fileoff = m_data.GetU64_unchecked(&offset);
-        uint64_t size = m_data.GetU64_unchecked(&offset);
-
-        // "kern ver str" has a uint32_t version and then a nul terminated
-        // c-string.
-        if (strcmp("kern ver str", data_owner) == 0) {
-          offset = fileoff;
-          uint32_t version;
-          if (m_data.GetU32(&offset, &version, 1) != nullptr) {
-            if (version == 1) {
-              uint32_t strsize = size - sizeof(uint32_t);
-              char *buf = (char *)malloc(strsize);
-              if (buf) {
-                m_data.CopyData(offset, strsize, buf);
-                buf[strsize - 1] = '\0';
-                result = buf;
-                if (buf)
-                  free(buf);
-                LLDB_LOGF(log, "LC_NOTE 'kern ver str' found with text '%s'",
-                          result.c_str());
-                return result;
-              }
-            }
-          }
+
+        if (name == data_owner) {
+          offset_t payload_offset = m_data.GetU64_unchecked(&offset);
+          offset_t payload_size = m_data.GetU64_unchecked(&offset);
+          results.push_back({payload_offset, payload_size});
         }
       }
       offset = cmd_offset + lc.cmdsize;
     }
+  }
+  return results;
+}
+
+std::string ObjectFileMachO::GetIdentifierString() {
+  Log *log(
+      GetLog(LLDBLog::Symbols | LLDBLog::Process | LLDBLog::DynamicLoader));
+  ModuleSP module_sp(GetModule());
+  if (module_sp) {
+    std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+
+    auto lc_notes = FindLC_NOTEByName("kern ver str");
+    for (auto lc_note : lc_notes) {
+      offset_t payload_offset = std::get<0>(lc_note);
+      offset_t payload_size = std::get<1>(lc_note);
+      uint32_t version;
+      if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+        if (version == 1) {
+          uint32_t strsize = payload_size - sizeof(uint32_t);
+          std::string result(strsize, '\0');
+          m_data.CopyData(payload_offset, strsize, result.data());
+          while (result.back() == '\0')
+            result.resize(result.size() - 1);
+          LLDB_LOGF(log, "LC_NOTE 'kern ver str' found with text '%s'",
+                    result.c_str());
+          return result;
+        }
+      }
+    }
 
     // Second, make a pass over the load commands looking for an obsolete
     // LC_IDENT load command.
-    offset = MachHeaderSizeFromMagic(m_header.magic);
+    offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
     for (uint32_t i = 0; i < m_header.ncmds; ++i) {
       const uint32_t cmd_offset = offset;
       llvm::MachO::ident_command ident_command;
       if (m_data.GetU32(&offset, &ident_command, 2) == nullptr)
         break;
       if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) {
-        char *buf = (char *)malloc(ident_command.cmdsize);
-        if (buf != nullptr && m_data.CopyData(offset, ident_command.cmdsize,
-                                              buf) == ident_command.cmdsize) {
-          buf[ident_command.cmdsize - 1] = '\0';
-          result = buf;
+        std::string result(ident_command.cmdsize, '\0');
+        if (m_data.CopyData(offset, ident_command.cmdsize, result.data()) ==
+            ident_command.cmdsize) {
+          while (result.back() == '\0')
+            result.resize(result.size() - 1);
           LLDB_LOGF(log, "LC_IDENT found with text '%s'", result.c_str());
+          return result;
         }
-        if (buf)
-          free(buf);
       }
       offset = cmd_offset + ident_command.cmdsize;
     }
   }
-  return result;
+  return {};
 }
 
 AddressableBits ObjectFileMachO::GetAddressableBits() {
@@ -5497,52 +5503,31 @@ AddressableBits ObjectFileMachO::GetAddressableBits() {
   ModuleSP module_sp(GetModule());
   if (module_sp) {
     std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
-    lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
-    for (uint32_t i = 0; i < m_header.ncmds; ++i) {
-      const uint32_t cmd_offset = offset;
-      llvm::MachO::load_command lc = {};
-      if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
-        break;
-      if (lc.cmd == LC_NOTE) {
-        char data_owner[17];
-        m_data.CopyData(offset, 16, data_owner);
-        data_owner[16] = '\0';
-        offset += 16;
-        uint64_t fileoff = m_data.GetU64_unchecked(&offset);
-
-        // "addrable bits" has a uint32_t version and a uint32_t
-        // number of bits used in addressing.
-        if (strcmp("addrable bits", data_owner) == 0) {
-          offset = fileoff;
-          uint32_t version;
-          if (m_data.GetU32(&offset, &version, 1) != nullptr) {
-            if (version == 3) {
-              uint32_t num_addr_bits = m_data.GetU32_unchecked(&offset);
-              addressable_bits.SetAddressableBits(num_addr_bits);
-              LLDB_LOGF(log,
-                        "LC_NOTE 'addrable bits' v3 found, value %d "
-                        "bits",
-                        num_addr_bits);
-              break;
-            }
-            if (version == 4) {
-              uint32_t lo_addr_bits = m_data.GetU32_unchecked(&offset);
-              uint32_t hi_addr_bits = m_data.GetU32_unchecked(&offset);
-
-              if (lo_addr_bits == hi_addr_bits)
-                addressable_bits.SetAddressableBits(lo_addr_bits);
-              else
-                addressable_bits.SetAddressableBits(lo_addr_bits, hi_addr_bits);
-              LLDB_LOGF(log,
-                        "LC_NOTE 'addrable bits' v4 found, value %d & %d bits",
-                        lo_addr_bits, hi_addr_bits);
-
-              break;
-            }
-          }
+    auto lc_notes = FindLC_NOTEByName("addrable bits");
+    for (auto lc_note : lc_notes) {
+      offset_t payload_offset = std::get<0>(lc_note);
+      uint32_t version;
+      if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+        if (version == 3) {
+          uint32_t num_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+          addressable_bits.SetAddressableBits(num_addr_bits);
+          LLDB_LOGF(log,
+                    "LC_NOTE 'addrable bits' v3 found, value %d "
+                    "bits",
+                    num_addr_bits);
+        }
+        if (version == 4) {
+          uint32_t lo_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+          uint32_t hi_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+
+          if (lo_addr_bits == hi_addr_bits)
+            addressable_bits.SetAddressableBits(lo_addr_bits);
+          else
+            addressable_bits.SetAddressableBits(lo_addr_bits, hi_addr_bits);
+          LLDB_LOGF(log, "LC_NOTE 'addrable bits' v4 found, value %d & %d bits",
+                    lo_addr_bits, hi_addr_bits);
         }
       }
-      offset = cmd_offset + lc.cmdsize;
     }
   }
   return addressable_bits;
@@ -5562,112 +5547,166 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
   ModuleSP module_sp(GetModule());
   if (module_sp) {
     std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
-    lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
-    for (uint32_t i = 0; i < m_header.ncmds; ++i) {
-      const uint32_t cmd_offset = offset;
-      llvm::MachO::load_command lc = {};
-      if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
-        break;
-      if (lc.cmd == LC_NOTE) {
-        char data_owner[17];
-        memset(data_owner, 0, sizeof(data_owner));
-        m_data.CopyData(offset, 16, data_owner);
-        offset += 16;
-        uint64_t fileoff = m_data.GetU64_unchecked(&offset);
-        uint64_t size = m_data.GetU64_unchecked(&offset);
-
-        // struct main_bin_spec
-        // {
-        //     uint32_t version;       // currently 2
-        //     uint32_t type;          // 0 == unspecified, 1 == kernel,
-        //                             // 2 == user process,
-        //                             // 3 == standalone binary
-        //     uint64_t address;       // UINT64_MAX if address not specified
-        //     uint64_t slide;         // slide, UINT64_MAX if unspecified
-        //                             // 0 if no slide needs to be applied to
-        //                             // file address
-        //     uuid_t   uuid;          // all zero's if uuid not specified
-        //     uint32_t log2_pagesize; // process page size in log base 2,
-        //                             // e.g. 4k pages are 12.
-        //                             // 0 for unspecified
-        //     uint32_t platform;      // The Mach-O platform for this corefile.
-        //                             // 0 for unspecified.
-        //                             // The values are defined in
-        //                             // <mach-o/loader.h>, PLATFORM_*.
-        // } __attribute((packed));
-
-        // "main bin spec" (main binary specification) data payload is
-        // formatted:
-        //    uint32_t version       [currently 1]
-        //    uint32_t type          [0 == unspecified, 1 == kernel,
-        //                            2 == user process, 3 == firmware ]
-        //    uint64_t address       [ UINT64_MAX if address not specified ]
-        //    uuid_t   uuid          [ all zero's if uuid not specified ]
-        //    uint32_t log2_pagesize [ process page size in log base
-        //                             2, e.g. 4k pages are 12.
-        //                             0 for unspecified ]
-        //    uint32_t unused        [ for alignment ]
-
-        if (strcmp("main bin spec", data_owner) == 0 && size >= 32) {
-          offset = fileoff;
-          uint32_t version;
-          if (m_data.GetU32(&offset, &version, 1) != nullptr && version <= 2) {
-            uint32_t binspec_type = 0;
-            uuid_t raw_uuid;
-            memset(raw_uuid, 0, sizeof(uuid_t));
-
-            if (!m_data.GetU32(&offset, &binspec_type, 1))
-              return false;
-            if (!m_data.GetU64(&offset, &value, 1))
-              return false;
-            uint64_t slide = LLDB_INVALID_ADDRESS;
-            if (version > 1 && !m_data.GetU64(&offset, &slide, 1))
-              return false;
-            if (value == LLDB_INVALID_ADDRESS &&
-                slide != LLDB_INVALID_ADDRESS) {
-              value = slide;
-              value_is_offset = true;
-            }
 
-            if (m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
-              uuid = UUID(raw_uuid, sizeof(uuid_t));
-              // convert the "main bin spec" type into our
-              // ObjectFile::BinaryType enum
-              const char *typestr = "unrecognized type";
-              switch (binspec_type) {
-              case 0:
-                type = eBinaryTypeUnknown;
-                typestr = "uknown";
-                break;
-              case 1:
-                type = eBinaryTypeKernel;
-                typestr = "xnu kernel";
-                break;
-              case 2:
-                type = eBinaryTypeUser;
-                typestr = "userland dyld";
-                break;
-              case 3:
-                type = eBinaryTypeStandalone;
-                typestr = "standalone";
-                break;
-              }
-              LLDB_LOGF(log,
-                        "LC_NOTE 'main bin spec' found, version %d type %d "
-                        "(%s), value 0x%" PRIx64 " value-is-slide==%s uuid %s",
-                        version, type, typestr, value,
-                        value_is_offset ? "true" : "false",
-                        uuid.GetAsString().c_str());
-              if (!m_data.GetU32(&offset, &log2_pagesize, 1))
-                return false;
-              if (version > 1 && !m_data.GetU32(&offset, &platform, 1))
-                return false;
-              return true;
-            }
+    auto lc_notes = FindLC_NOTEByName("main bin spec");
+    for (auto lc_note : lc_notes) {
+      offset_t payload_offset = std::get<0>(lc_note);
+
+      // struct main_bin_spec
+      // {
+      //     uint32_t version;       // currently 2
+      //     uint32_t type;          // 0 == unspecified, 1 == kernel,
+      //                             // 2 == user process,
+      //                             // 3 == standalone binary
+      //     uint64_t address;       // UINT64_MAX if address not specified
+      //     uint64_t slide;         // slide, UINT64_MAX if unspecified
+      //                             // 0 if no slide needs to be applied to
+      //                             // file address
+      //     uuid_t   uuid;          // all zero's if uuid not specified
+      //     uint32_t log2_pagesize; // process page size in log base 2,
+      //                             // e.g. 4k pages are 12.
+      //                             // 0 for unspecified
+      //     uint32_t platform;      // The Mach-O platform for this corefile.
+      //                             // 0 for unspecified.
+      //                             // The values are defined in
+      //                             // <mach-o/loader.h>, PLATFORM_*.
+      // } __attribute((packed));
+
+      // "main bin spec" (main binary specification) data payload is
+      // formatted:
+      //    uint32_t version       [currently 1]
+      //    uint32_t type          [0 == unspecified, 1 == kernel,
+      //                            2 == user process, 3 == firmware ]
+      //    uint64_t address       [ UINT64_MAX if address not specified ]
+      //    uuid_t   uuid          [ all zero's if uuid not specified ]
+      //    uint32_t log2_pagesize [ process page size in log base
+      //                             2, e.g. 4k pages are 12.
+      //                             0 for unspecified ]
+      //    uint32_t unused        [ for alignment ]
+
+      uint32_t version;
+      if (m_data.GetU32(&payload_offset, &version, 1) != nullptr &&
+          version <= 2) {
+        uint32_t binspec_type = 0;
+        uuid_t raw_uuid;
+        memset(raw_uuid, 0, sizeof(uuid_t));
+
+        if (!m_data.GetU32(&payload_offset, &binspec_type, 1))
+          return false;
+        if (!m_data.GetU64(&payload_offset, &value, 1))
+          return false;
+        uint64_t slide = LLDB_INVALID_ADDRESS;
+        if (version > 1 && !m_data.GetU64(&payload_offset, &slide, 1))
+          return false;
+        if (value == LLDB_INVALID_ADDRESS && slide != LLDB_INVALID_ADDRESS) {
+          value = slide;
+          value_is_offset = true;
+        }
+
+        if (m_data.CopyData(payload_offset, sizeof(uuid_t), raw_uuid) != 0) {
+          uuid = UUID(raw_uuid, sizeof(uuid_t));
+          // convert the "main bin spec" type into our
+          // ObjectFile::BinaryType enum
+          const char *typestr = "unrecognized type";
+          switch (binspec_type) {
+          case 0:
+            type = eBinaryTypeUnknown;
+            typestr = "uknown";
+            break;
+          case 1:
+            type = eBinaryTypeKernel;
+            typestr = "xnu kernel";
+            break;
+          case 2:
+            type = eBinaryTypeUser;
+            typestr = "userland dyld";
+            break;
+          case 3:
+            type = eBinaryTypeStandalone;
+            typestr = "standalone";
+            break;
           }
+          LLDB_LOGF(log,
+                    "LC_NOTE 'main bin spec' found, version %d type %d "
+                    "(%s), value 0x%" PRIx64 " value-is-slide==%s uuid %s",
+                    version, type, typestr, value,
+                    value_is_offset ? "true" : "false",
+                    uuid.GetAsString().c_str());
+          if (!m_data.GetU32(&payload_offset, &log2_pagesize, 1))
+            return false;
+          if (version > 1 && !m_data.GetU32(&payload_offset, &platform, 1))
+            return false;
+          return true;
         }
       }
-      offset = cmd_offset + lc.cmdsize;
+    }
+  }
+  return false;
+}
+
+bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector<tid_t> &tids) {
+  tids.clear();
+  ModuleSP module_sp(GetModule());
+  if (module_sp) {
+    std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+
+    Log *log(GetLog(LLDBLog::Object | LLDBLog::Process | LLDBLog::Thread));
+    auto lc_notes = FindLC_NOTEByName("process metadata");
+    for (auto lc_note : lc_notes) {
+      offset_t payload_offset = std::get<0>(lc_note);
+      offset_t strsize = std::get<1>(lc_note);
+      std::string buf(strsize, '\0');
+      if (m_data.CopyData(payload_offset, strsize, buf.data()) != strsize) {
+        LLDB_LOGF(log,
+                  "Unable to read %" PRIu64
+                  " bytes of 'process metadata' LC_NOTE JSON contents",
+                  strsize);
+        return false;
+      }
+      while (buf.back() == '\0')
+        buf.resize(buf.size() - 1);
+      StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(buf);
+      StructuredData::Dictionary *dict = object_sp->GetAsDictionary();
+      if (!dict) {
+        LLDB_LOGF(log, "Unable to read 'process metadata' LC_NOTE, did not "
+                       "get a dictionary.");
+        return false;
+      }
+      StructuredData::Array *threads;
+      if (!dict->GetValueForKeyAsArray("threads", threads) || !threads) {
+        LLDB_LOGF(log,
+                  "'process metadata' LC_NOTE does not have a 'threads' key");
+        return false;
+      }
+      if (threads->GetSize() != GetNumThreadContexts()) {
+        LLDB_LOGF(log, "Unable to read 'process metadata' LC_NOTE, number of "
+                       "threads does not match number of LC_THREADS.");
+        return false;
+      }
+      const size_t num_threads = threads->GetSize();
+      for (size_t i = 0; i < num_threads; i++) {
+        StructuredData::Dictionary *thread;
+        if (!threads->GetItemAtIndexAsDictionary(i, thread) || !thread) {
+          LLDB_LOGF(log,
+                    "Unable to read 'process metadata' LC_NOTE, threads "
+                    "array does not have a dictionary at index %zu.",
+                    i);
+          return false;
+        }
+        tid_t tid = LLDB_INVALID_THREAD_ID;
+        if (thread->GetValueForKeyAsInteger<tid_t>("thread_id", tid))
+          if (tid == 0)
+            tid = LLDB_INVALID_THREAD_ID;
+        tids.push_back(tid);
+      }
+
+      if (log) {
+        StreamString logmsg;
+        logmsg.Printf("LC_NOTE 'process metadata' found: ");
+        dict->Dump(logmsg, /* pretty_print */ false);
+        LLDB_LOGF(log, "%s", logmsg.GetData());
+      }
+      return true;
     }
   }
   return false;
@@ -6656,6 +6695,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
           mach_header.sizeofcmds += sizeof(llvm::MachO::note_command);
         }
 
+        // LC_NOTE "process metadata"
+        mach_header.ncmds++;
+        mach_header.sizeofcmds += sizeof(llvm::MachO::note_command);
+
         // LC_NOTE "all image infos"
         mach_header.ncmds++;
         mach_header.sizeofcmds += sizeof(llvm::MachO::note_command);
@@ -6698,6 +6741,33 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
           lc_notes.push_back(std::move(addrable_bits_lcnote_up));
         }
 
+        // Add "process metadata" LC_NOTE
+        std::unique_ptr<LCNoteEntry> thread_extrainfo_lcnote_up(
+            new LCNoteEntry(addr_byte_size, byte_order));
+        thread_extrainfo_lcnote_up->name = "process metadata";
+        thread_extrainfo_lcnote_up->payload_file_offset = file_offset;
+
+        StructuredData::DictionarySP dict(
+            std::make_shared<StructuredData::Dictionary>());
+        StructuredData::ArraySP threads(
+            std::make_shared<StructuredData::Array>());
+        for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+          ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
+          StructuredData::DictionarySP thread(
+              std::make_shared<StructuredData::Dictionary>());
+          thread->AddIntegerItem("thread_id", thread_sp->GetID());
+          threads->AddItem(thread);
+        }
+        dict->AddItem("threads", threads);
+        StreamString strm;
+        dict->Dump(strm, /* pretty */ false);
+        thread_extrainfo_lcnote_up->payload.PutRawBytes(strm.GetData(),
+                                                        strm.GetSize());
+
+        file_offset += thread_extrainfo_lcnote_up->payload.GetSize();
+        file_offset = llvm::alignTo(file_offset, 16);
+        lc_notes.push_back(std::move(thread_extrainfo_lcnote_up));
+
         // Add "all image infos" LC_NOTE
         std::unique_ptr<LCNoteEntry> all_image_infos_lcnote_up(
             new LCNoteEntry(addr_byte_size, byte_order));
@@ -6852,108 +6922,93 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
 ObjectFileMachO::MachOCorefileAllImageInfos
 ObjectFileMachO::GetCorefileAllImageInfos() {
   MachOCorefileAllImageInfos image_infos;
-  Log *log(
-      GetLog(LLDBLog::Symbols | LLDBLog::Process | LLDBLog::DynamicLoader));
-
-  // Look for an "all image infos" LC_NOTE.
-  lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
-  for (uint32_t i = 0; i < m_header.ncmds; ++i) {
-    const uint32_t cmd_offset = offset;
-    llvm::MachO::load_command lc = {};
-    if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
-      break;
-    if (lc.cmd == LC_NOTE) {
-      char data_owner[17];
-      m_data.CopyData(offset, 16, data_owner);
-      data_owner[16] = '\0';
-      offset += 16;
-      uint64_t fileoff = m_data.GetU64_unchecked(&offset);
-      offset += 4; /* size unused */
-
-      if (strcmp("all image infos", data_owner) == 0) {
-        offset = fileoff;
-        // Read the struct all_image_infos_header.
-        uint32_t version = m_data.GetU32(&offset);
-        if (version != 1) {
-          return image_infos;
-        }
-        uint32_t imgcount = m_data.GetU32(&offset);
-        uint64_t entries_fileoff = m_data.GetU64(&offset);
-        // 'entries_size' is not used, nor is the 'unused' entry.
-        //  offset += 4; // uint32_t entries_size;
-        //  offset += 4; // uint32_t unused;
-
-        LLDB_LOGF(log,
-                  "LC_NOTE 'all image infos' found version %d with %d images",
-                  version, imgcount);
-        offset = entries_fileoff;
-        for (uint32_t i = 0; i < imgcount; i++) {
-          // Read the struct image_entry.
-          offset_t filepath_offset = m_data.GetU64(&offset);
-          uuid_t uuid;
-          memcpy(&uuid, m_data.GetData(&offset, sizeof(uuid_t)),
-                 sizeof(uuid_t));
-          uint64_t load_address = m_data.GetU64(&offset);
-          offset_t seg_addrs_offset = m_data.GetU64(&offset);
-          uint32_t segment_count = m_data.GetU32(&offset);
-          uint32_t currently_executing = m_data.GetU32(&offset);
-
-          MachOCorefileImageEntry image_entry;
-          image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset);
-          image_entry.uuid = UUID(uuid, sizeof(uuid_t));
-          image_entry.load_address = load_address;
-          image_entry.currently_executing = currently_executing;
-
-          offset_t seg_vmaddrs_offset = seg_addrs_offset;
-          for (uint32_t j = 0; j < segment_count; j++) {
-            char segname[17];
-            m_data.CopyData(seg_vmaddrs_offset, 16, segname);
-            segname[16] = '\0';
-            seg_vmaddrs_offset += 16;
-            uint64_t vmaddr = m_data.GetU64(&seg_vmaddrs_offset);
-            seg_vmaddrs_offset += 8; /* unused */
-
-            std::tuple<ConstString, addr_t> new_seg{ConstString(segname),
-                                                    vmaddr};
-            image_entry.segment_load_addresses.push_back(new_seg);
-          }
-          LLDB_LOGF(
-              log, "  image entry: %s %s 0x%" PRIx64 " %s",
-              image_entry.filename.c_str(),
-              image_entry.uuid.GetAsString().c_str(), image_entry.load_address,
-              image_entry.currently_executing ? "currently executing"
-                                              : "not currently executing");
-          image_infos.all_image_infos.push_back(image_entry);
-        }
-      } else if (strcmp("load binary", data_owner) == 0) {
-        uint32_t version = m_data.GetU32(&fileoff);
-        if (version == 1) {
-          uuid_t uuid;
-          memcpy(&uuid, m_data.GetData(&fileoff, sizeof(uuid_t)),
-                 sizeof(uuid_t));
-          uint64_t load_address = m_data.GetU64(&fileoff);
-          uint64_t slide = m_data.GetU64(&fileoff);
-          std::string filename = m_data.GetCStr(&fileoff);
-
-          MachOCorefileImageEntry image_entry;
-          image_entry.filename = filename;
-          image_entry.uuid = UUID(uuid, sizeof(uuid_t));
-          image_entry.load_address = load_address;
-          image_entry.slide = slide;
-          image_entry.currently_executing = true;
-          image_infos.all_image_infos.push_back(image_entry);
-          LLDB_LOGF(log,
-                    "LC_NOTE 'load binary' found, filename %s uuid %s load "
-                    "address 0x%" PRIx64 " slide 0x%" PRIx64,
-                    filename.c_str(),
-                    image_entry.uuid.IsValid()
-                        ? image_entry.uuid.GetAsString().c_str()
-                        : "00000000-0000-0000-0000-000000000000",
-                    load_address, slide);
-        }
+  Log *log(GetLog(LLDBLog::Object | LLDBLog::Symbols | LLDBLog::Process |
+                  LLDBLog::DynamicLoader));
+
+  auto lc_notes = FindLC_NOTEByName("all image infos");
+  for (auto lc_note : lc_notes) {
+    offset_t payload_offset = std::get<0>(lc_note);
+    // Read the struct all_image_infos_header.
+    uint32_t version = m_data.GetU32(&payload_offset);
+    if (version != 1) {
+      return image_infos;
+    }
+    uint32_t imgcount = m_data.GetU32(&payload_offset);
+    uint64_t entries_fileoff = m_data.GetU64(&payload_offset);
+    // 'entries_size' is not used, nor is the 'unused' entry.
+    //  offset += 4; // uint32_t entries_size;
+    //  offset += 4; // uint32_t unused;
+
+    LLDB_LOGF(log, "LC_NOTE 'all image infos' found version %d with %d images",
+              version, imgcount);
+    payload_offset = entries_fileoff;
+    for (uint32_t i = 0; i < imgcount; i++) {
+      // Read the struct image_entry.
+      offset_t filepath_offset = m_data.GetU64(&payload_offset);
+      uuid_t uuid;
+      memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+             sizeof(uuid_t));
+      uint64_t load_address = m_data.GetU64(&payload_offset);
+      offset_t seg_addrs_offset = m_data.GetU64(&payload_offset);
+      uint32_t segment_count = m_data.GetU32(&payload_offset);
+      uint32_t currently_executing = m_data.GetU32(&payload_offset);
+
+      MachOCorefileImageEntry image_entry;
+      image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset);
+      image_entry.uuid = UUID(uuid, sizeof(uuid_t));
+      image_entry.load_address = load_address;
+      image_entry.currently_executing = currently_executing;
+
+      offset_t seg_vmaddrs_offset = seg_addrs_offset;
+      for (uint32_t j = 0; j < segment_count; j++) {
+        char segname[17];
+        m_data.CopyData(seg_vmaddrs_offset, 16, segname);
+        segname[16] = '\0';
+        seg_vmaddrs_offset += 16;
+        uint64_t vmaddr = m_data.GetU64(&seg_vmaddrs_offset);
+        seg_vmaddrs_offset += 8; /* unused */
+
+        std::tuple<ConstString, addr_t> new_seg{ConstString(segname), vmaddr};
+        image_entry.segment_load_addresses.push_back(new_seg);
       }
+      LLDB_LOGF(log, "  image entry: %s %s 0x%" PRIx64 " %s",
+                image_entry.filename.c_str(),
+                image_entry.uuid.GetAsString().c_str(),
+                image_entry.load_address,
+                image_entry.currently_executing ? "currently executing"
+                                                : "not currently executing");
+      image_infos.all_image_infos.push_back(image_entry);
+    }
+  }
+
+  lc_notes = FindLC_NOTEByName("load binary");
+  for (auto lc_note : lc_notes) {
+    offset_t payload_offset = std::get<0>(lc_note);
+    uint32_t version = m_data.GetU32(&payload_offset);
+    if (version == 1) {
+      uuid_t uuid;
+      memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+             sizeof(uuid_t));
+      uint64_t load_address = m_data.GetU64(&payload_offset);
+      uint64_t slide = m_data.GetU64(&payload_offset);
+      std::string filename = m_data.GetCStr(&payload_offset);
+
+      MachOCorefileImageEntry image_entry;
+      image_entry.filename = filename;
+      image_entry.uuid = UUID(uuid, sizeof(uuid_t));
+      image_entry.load_address = load_address;
+      image_entry.slide = slide;
+      image_entry.currently_executing = true;
+      image_infos.all_image_infos.push_back(image_entry);
+      LLDB_LOGF(log,
+                "LC_NOTE 'load binary' found, filename %s uuid %s load "
+                "address 0x%" PRIx64 " slide 0x%" PRIx64,
+                filename.c_str(),
+                image_entry.uuid.IsValid()
+                    ? image_entry.uuid.GetAsString().c_str()
+                    : "00000000-0000-0000-0000-000000000000",
+                load_address, slide);
     }
-    offset = cmd_offset + lc.cmdsize;
   }
 
   return image_infos;
@@ -6961,7 +7016,7 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
 
 bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
   MachOCorefileAllImageInfos image_infos = GetCorefileAllImageInfos();
-  Log *log = GetLog(LLDBLog::DynamicLoader);
+  Log *log = GetLog(LLDBLog::Object | LLDBLog::DynamicLoader);
   Status error;
 
   bool found_platform_binary = false;

diff  --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index 310dbb4e8c3a3f..0a47f3a7dd1861 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -120,6 +120,9 @@ class ObjectFileMachO : public lldb_private::ObjectFile {
 
   uint32_t GetNumThreadContexts() override;
 
+  std::vector<std::tuple<lldb::offset_t, lldb::offset_t>>
+  FindLC_NOTEByName(std::string name);
+
   std::string GetIdentifierString() override;
 
   lldb_private::AddressableBits GetAddressableBits() override;
@@ -128,6 +131,8 @@ class ObjectFileMachO : public lldb_private::ObjectFile {
                                  lldb_private::UUID &uuid,
                                  ObjectFile::BinaryType &type) override;
 
+  bool GetCorefileThreadExtraInfos(std::vector<lldb::tid_t> &tids) override;
+
   bool LoadCoreFileImages(lldb_private::Process &process) override;
 
   lldb::RegisterContextSP

diff  --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 7b7e80c443041d..b11062a0224abc 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -594,9 +594,34 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list,
     ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
 
     if (core_objfile) {
+      std::set<tid_t> used_tids;
       const uint32_t num_threads = core_objfile->GetNumThreadContexts();
-      for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
-        ThreadSP thread_sp(new ThreadMachCore(*this, tid));
+      std::vector<tid_t> tids;
+      if (core_objfile->GetCorefileThreadExtraInfos(tids)) {
+        assert(tids.size() == num_threads);
+
+        // Find highest tid value.
+        tid_t highest_tid = 0;
+        for (uint32_t i = 0; i < num_threads; i++) {
+          if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid)
+            highest_tid = tids[i];
+        }
+        tid_t current_unused_tid = highest_tid + 1;
+        for (uint32_t i = 0; i < num_threads; i++) {
+          if (tids[i] == LLDB_INVALID_THREAD_ID) {
+            tids[i] = current_unused_tid++;
+          }
+        }
+      } else {
+        // No metadata, insert numbers sequentially from 0.
+        for (uint32_t i = 0; i < num_threads; i++) {
+          tids.push_back(i);
+        }
+      }
+
+      for (uint32_t i = 0; i < num_threads; i++) {
+        ThreadSP thread_sp =
+            std::make_shared<ThreadMachCore>(*this, tids[i], i);
         new_thread_list.AddThread(thread_sp);
       }
     }

diff  --git a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
index 8e31d95a8dab59..003cdd0fcaa570 100644
--- a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
@@ -33,9 +33,11 @@ using namespace lldb_private;
 
 // Thread Registers
 
-ThreadMachCore::ThreadMachCore(Process &process, lldb::tid_t tid)
+ThreadMachCore::ThreadMachCore(Process &process, lldb::tid_t tid,
+                               uint32_t objfile_lc_thread_idx)
     : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(),
-      m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), m_thread_reg_ctx_sp() {}
+      m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), m_thread_reg_ctx_sp(),
+      m_objfile_lc_thread_idx(objfile_lc_thread_idx) {}
 
 ThreadMachCore::~ThreadMachCore() { DestroyThread(); }
 
@@ -81,8 +83,8 @@ ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {
       ObjectFile *core_objfile =
           static_cast<ProcessMachCore *>(process_sp.get())->GetCoreObjectFile();
       if (core_objfile)
-        m_thread_reg_ctx_sp =
-            core_objfile->GetThreadContextAtIndex(GetID(), *this);
+        m_thread_reg_ctx_sp = core_objfile->GetThreadContextAtIndex(
+            m_objfile_lc_thread_idx, *this);
     }
     reg_ctx_sp = m_thread_reg_ctx_sp;
   } else {

diff  --git a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.h b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.h
index da08a7c2fa949e..26c4e567443c14 100644
--- a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.h
+++ b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.h
@@ -17,7 +17,8 @@ class ProcessMachCore;
 
 class ThreadMachCore : public lldb_private::Thread {
 public:
-  ThreadMachCore(lldb_private::Process &process, lldb::tid_t tid);
+  ThreadMachCore(lldb_private::Process &process, lldb::tid_t tid,
+                 uint32_t objfile_lc_thread_idx);
 
   ~ThreadMachCore() override;
 
@@ -57,6 +58,7 @@ class ThreadMachCore : public lldb_private::Thread {
   std::string m_dispatch_queue_name;
   lldb::addr_t m_thread_dispatch_qaddr;
   lldb::RegisterContextSP m_thread_reg_ctx_sp;
+  uint32_t m_objfile_lc_thread_idx;
 
   // Protected member functions.
   bool CalculateStopInfo() override;

diff  --git a/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py b/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
index 8fd0861cbccdf5..58f6c36ccfcc64 100644
--- a/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
+++ b/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
@@ -26,6 +26,11 @@ def test(self):
         self.runCmd("continue")
 
         self.runCmd("process save-core -s stack " + corefile)
+        live_tids = []
+        if self.TraceOn():
+            self.runCmd("thread list")
+        for t in process.threads:
+            live_tids.append(t.GetThreadID())
         process.Kill()
         self.dbg.DeleteTarget(target)
 
@@ -42,3 +47,9 @@ def test(self):
         self.assertEqual(
             thread.GetStopDescription(256), "ESR_EC_DABORT_EL0 (fault address: 0x0)"
         )
+
+        if self.TraceOn():
+            self.runCmd("thread list")
+        for i in range(process.GetNumThreads()):
+            t = process.GetThreadAtIndex(i)
+            self.assertEqual(t.GetThreadID(), live_tids[i])


        


More information about the lldb-commits mailing list