ProcessElfCore.cpp revision 314564
1//===-- ProcessElfCore.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// C Includes
11#include <stdlib.h>
12
13// C++ Includes
14#include <mutex>
15
16// Other libraries and framework includes
17#include "lldb/Core/DataBufferHeap.h"
18#include "lldb/Core/Log.h"
19#include "lldb/Core/Module.h"
20#include "lldb/Core/ModuleSpec.h"
21#include "lldb/Core/PluginManager.h"
22#include "lldb/Core/Section.h"
23#include "lldb/Core/State.h"
24#include "lldb/Target/DynamicLoader.h"
25#include "lldb/Target/MemoryRegionInfo.h"
26#include "lldb/Target/Target.h"
27#include "lldb/Target/UnixSignals.h"
28
29#include "llvm/Support/ELF.h"
30
31#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
32#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
33
34// Project includes
35#include "ProcessElfCore.h"
36#include "ThreadElfCore.h"
37
38using namespace lldb_private;
39
40ConstString ProcessElfCore::GetPluginNameStatic() {
41  static ConstString g_name("elf-core");
42  return g_name;
43}
44
45const char *ProcessElfCore::GetPluginDescriptionStatic() {
46  return "ELF core dump plug-in.";
47}
48
49void ProcessElfCore::Terminate() {
50  PluginManager::UnregisterPlugin(ProcessElfCore::CreateInstance);
51}
52
53lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
54                                               lldb::ListenerSP listener_sp,
55                                               const FileSpec *crash_file) {
56  lldb::ProcessSP process_sp;
57  if (crash_file) {
58    // Read enough data for a ELF32 header or ELF64 header
59    const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
60
61    lldb::DataBufferSP data_sp(crash_file->ReadFileContents(0, header_size));
62    if (data_sp && data_sp->GetByteSize() == header_size &&
63        elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) {
64      elf::ELFHeader elf_header;
65      DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
66      lldb::offset_t data_offset = 0;
67      if (elf_header.Parse(data, &data_offset)) {
68        if (elf_header.e_type == llvm::ELF::ET_CORE)
69          process_sp.reset(
70              new ProcessElfCore(target_sp, listener_sp, *crash_file));
71      }
72    }
73  }
74  return process_sp;
75}
76
77bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
78                              bool plugin_specified_by_name) {
79  // For now we are just making sure the file exists for a given module
80  if (!m_core_module_sp && m_core_file.Exists()) {
81    ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
82    Error error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
83                                            NULL, NULL, NULL));
84    if (m_core_module_sp) {
85      ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
86      if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
87        return true;
88    }
89  }
90  return false;
91}
92
93//----------------------------------------------------------------------
94// ProcessElfCore constructor
95//----------------------------------------------------------------------
96ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
97                               lldb::ListenerSP listener_sp,
98                               const FileSpec &core_file)
99    : Process(target_sp, listener_sp), m_core_module_sp(),
100      m_core_file(core_file), m_dyld_plugin_name(),
101      m_os(llvm::Triple::UnknownOS), m_thread_data_valid(false),
102      m_thread_data(), m_core_aranges() {}
103
104//----------------------------------------------------------------------
105// Destructor
106//----------------------------------------------------------------------
107ProcessElfCore::~ProcessElfCore() {
108  Clear();
109  // We need to call finalize on the process before destroying ourselves
110  // to make sure all of the broadcaster cleanup goes as planned. If we
111  // destruct this class, then Process::~Process() might have problems
112  // trying to fully destroy the broadcaster.
113  Finalize();
114}
115
116//----------------------------------------------------------------------
117// PluginInterface
118//----------------------------------------------------------------------
119ConstString ProcessElfCore::GetPluginName() { return GetPluginNameStatic(); }
120
121uint32_t ProcessElfCore::GetPluginVersion() { return 1; }
122
123lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
124    const elf::ELFProgramHeader *header) {
125  const lldb::addr_t addr = header->p_vaddr;
126  FileRange file_range(header->p_offset, header->p_filesz);
127  VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range);
128
129  VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
130  if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
131      last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() &&
132      last_entry->GetByteSize() == last_entry->data.GetByteSize()) {
133    last_entry->SetRangeEnd(range_entry.GetRangeEnd());
134    last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd());
135  } else {
136    m_core_aranges.Append(range_entry);
137  }
138
139  // Keep a separate map of permissions that that isn't coalesced so all ranges
140  // are maintained.
141  const uint32_t permissions =
142      ((header->p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) |
143      ((header->p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) |
144      ((header->p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u);
145
146  m_core_range_infos.Append(
147      VMRangeToPermissions::Entry(addr, header->p_memsz, permissions));
148
149  return addr;
150}
151
152//----------------------------------------------------------------------
153// Process Control
154//----------------------------------------------------------------------
155Error ProcessElfCore::DoLoadCore() {
156  Error error;
157  if (!m_core_module_sp) {
158    error.SetErrorString("invalid core module");
159    return error;
160  }
161
162  ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
163  if (core == NULL) {
164    error.SetErrorString("invalid core object file");
165    return error;
166  }
167
168  const uint32_t num_segments = core->GetProgramHeaderCount();
169  if (num_segments == 0) {
170    error.SetErrorString("core file has no segments");
171    return error;
172  }
173
174  SetCanJIT(false);
175
176  m_thread_data_valid = true;
177
178  bool ranges_are_sorted = true;
179  lldb::addr_t vm_addr = 0;
180  /// Walk through segments and Thread and Address Map information.
181  /// PT_NOTE - Contains Thread and Register information
182  /// PT_LOAD - Contains a contiguous range of Process Address Space
183  for (uint32_t i = 1; i <= num_segments; i++) {
184    const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i);
185    assert(header != NULL);
186
187    DataExtractor data = core->GetSegmentDataByIndex(i);
188
189    // Parse thread contexts and auxv structure
190    if (header->p_type == llvm::ELF::PT_NOTE) {
191      error = ParseThreadContextsFromNoteSegment(header, data);
192      if (error.Fail())
193        return error;
194    }
195    // PT_LOAD segments contains address map
196    if (header->p_type == llvm::ELF::PT_LOAD) {
197      lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header);
198      if (vm_addr > last_addr)
199        ranges_are_sorted = false;
200      vm_addr = last_addr;
201    }
202  }
203
204  if (!ranges_are_sorted) {
205    m_core_aranges.Sort();
206    m_core_range_infos.Sort();
207  }
208
209  // Even if the architecture is set in the target, we need to override
210  // it to match the core file which is always single arch.
211  ArchSpec arch(m_core_module_sp->GetArchitecture());
212  if (arch.IsValid())
213    GetTarget().SetArchitecture(arch);
214
215  SetUnixSignals(UnixSignals::Create(GetArchitecture()));
216
217  // Ensure we found at least one thread that was stopped on a signal.
218  bool siginfo_signal_found = false;
219  bool prstatus_signal_found = false;
220  // Check we found a signal in a SIGINFO note.
221  for (const auto &thread_data: m_thread_data) {
222    if (thread_data.signo != 0)
223      siginfo_signal_found = true;
224    if (thread_data.prstatus_sig != 0)
225      prstatus_signal_found = true;
226  }
227  if (!siginfo_signal_found) {
228    // If we don't have signal from SIGINFO use the signal from each threads
229    // PRSTATUS note.
230    if (prstatus_signal_found) {
231      for (auto &thread_data: m_thread_data)
232        thread_data.signo = thread_data.prstatus_sig;
233    } else if (m_thread_data.size() > 0) {
234      // If all else fails force the first thread to be SIGSTOP
235      m_thread_data.begin()->signo =
236          GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
237    }
238  }
239
240  // Core files are useless without the main executable. See if we can locate
241  // the main
242  // executable using data we found in the core file notes.
243  lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
244  if (!exe_module_sp) {
245    // The first entry in the NT_FILE might be our executable
246    if (!m_nt_file_entries.empty()) {
247      ModuleSpec exe_module_spec;
248      exe_module_spec.GetArchitecture() = arch;
249      exe_module_spec.GetFileSpec().SetFile(
250          m_nt_file_entries[0].path.GetCString(), false);
251      if (exe_module_spec.GetFileSpec()) {
252        exe_module_sp = GetTarget().GetSharedModule(exe_module_spec);
253        if (exe_module_sp)
254          GetTarget().SetExecutableModule(exe_module_sp, false);
255      }
256    }
257  }
258  return error;
259}
260
261lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
262  if (m_dyld_ap.get() == NULL)
263    m_dyld_ap.reset(DynamicLoader::FindPlugin(
264        this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic().GetCString()));
265  return m_dyld_ap.get();
266}
267
268bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list,
269                                      ThreadList &new_thread_list) {
270  const uint32_t num_threads = GetNumThreadContexts();
271  if (!m_thread_data_valid)
272    return false;
273
274  for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
275    const ThreadData &td = m_thread_data[tid];
276    lldb::ThreadSP thread_sp(new ThreadElfCore(*this, td));
277    new_thread_list.AddThread(thread_sp);
278  }
279  return new_thread_list.GetSize(false) > 0;
280}
281
282void ProcessElfCore::RefreshStateAfterStop() {}
283
284Error ProcessElfCore::DoDestroy() { return Error(); }
285
286//------------------------------------------------------------------
287// Process Queries
288//------------------------------------------------------------------
289
290bool ProcessElfCore::IsAlive() { return true; }
291
292//------------------------------------------------------------------
293// Process Memory
294//------------------------------------------------------------------
295size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
296                                  Error &error) {
297  // Don't allow the caching that lldb_private::Process::ReadMemory does
298  // since in core files we have it all cached our our core file anyway.
299  return DoReadMemory(addr, buf, size, error);
300}
301
302Error ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr,
303                                          MemoryRegionInfo &region_info) {
304  region_info.Clear();
305  const VMRangeToPermissions::Entry *permission_entry =
306      m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
307  if (permission_entry) {
308    if (permission_entry->Contains(load_addr)) {
309      region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());
310      region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());
311      const Flags permissions(permission_entry->data);
312      region_info.SetReadable(permissions.Test(lldb::ePermissionsReadable)
313                                  ? MemoryRegionInfo::eYes
314                                  : MemoryRegionInfo::eNo);
315      region_info.SetWritable(permissions.Test(lldb::ePermissionsWritable)
316                                  ? MemoryRegionInfo::eYes
317                                  : MemoryRegionInfo::eNo);
318      region_info.SetExecutable(permissions.Test(lldb::ePermissionsExecutable)
319                                    ? MemoryRegionInfo::eYes
320                                    : MemoryRegionInfo::eNo);
321      region_info.SetMapped(MemoryRegionInfo::eYes);
322    } else if (load_addr < permission_entry->GetRangeBase()) {
323      region_info.GetRange().SetRangeBase(load_addr);
324      region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
325      region_info.SetReadable(MemoryRegionInfo::eNo);
326      region_info.SetWritable(MemoryRegionInfo::eNo);
327      region_info.SetExecutable(MemoryRegionInfo::eNo);
328      region_info.SetMapped(MemoryRegionInfo::eNo);
329    }
330    return Error();
331  }
332
333  region_info.GetRange().SetRangeBase(load_addr);
334  region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
335  region_info.SetReadable(MemoryRegionInfo::eNo);
336  region_info.SetWritable(MemoryRegionInfo::eNo);
337  region_info.SetExecutable(MemoryRegionInfo::eNo);
338  region_info.SetMapped(MemoryRegionInfo::eNo);
339  return Error();
340}
341
342size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
343                                    Error &error) {
344  ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
345
346  if (core_objfile == NULL)
347    return 0;
348
349  // Get the address range
350  const VMRangeToFileOffset::Entry *address_range =
351      m_core_aranges.FindEntryThatContains(addr);
352  if (address_range == NULL || address_range->GetRangeEnd() < addr) {
353    error.SetErrorStringWithFormat("core file does not contain 0x%" PRIx64,
354                                   addr);
355    return 0;
356  }
357
358  // Convert the address into core file offset
359  const lldb::addr_t offset = addr - address_range->GetRangeBase();
360  const lldb::addr_t file_start = address_range->data.GetRangeBase();
361  const lldb::addr_t file_end = address_range->data.GetRangeEnd();
362  size_t bytes_to_read = size; // Number of bytes to read from the core file
363  size_t bytes_copied = 0;   // Number of bytes actually read from the core file
364  size_t zero_fill_size = 0; // Padding
365  lldb::addr_t bytes_left =
366      0; // Number of bytes available in the core file from the given address
367
368  // Figure out how many on-disk bytes remain in this segment
369  // starting at the given offset
370  if (file_end > file_start + offset)
371    bytes_left = file_end - (file_start + offset);
372
373  // Figure out how many bytes we need to zero-fill if we are
374  // reading more bytes than available in the on-disk segment
375  if (bytes_to_read > bytes_left) {
376    zero_fill_size = bytes_to_read - bytes_left;
377    bytes_to_read = bytes_left;
378  }
379
380  // If there is data available on the core file read it
381  if (bytes_to_read)
382    bytes_copied =
383        core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
384
385  assert(zero_fill_size <= size);
386  // Pad remaining bytes
387  if (zero_fill_size)
388    memset(((char *)buf) + bytes_copied, 0, zero_fill_size);
389
390  return bytes_copied + zero_fill_size;
391}
392
393void ProcessElfCore::Clear() {
394  m_thread_list.Clear();
395  m_os = llvm::Triple::UnknownOS;
396
397  SetUnixSignals(std::make_shared<UnixSignals>());
398}
399
400void ProcessElfCore::Initialize() {
401  static std::once_flag g_once_flag;
402
403  std::call_once(g_once_flag, []() {
404    PluginManager::RegisterPlugin(GetPluginNameStatic(),
405                                  GetPluginDescriptionStatic(), CreateInstance);
406  });
407}
408
409lldb::addr_t ProcessElfCore::GetImageInfoAddress() {
410  ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile();
411  Address addr = obj_file->GetImageInfoAddress(&GetTarget());
412
413  if (addr.IsValid())
414    return addr.GetLoadAddress(&GetTarget());
415  return LLDB_INVALID_ADDRESS;
416}
417
418/// Core files PT_NOTE segment descriptor types
419enum {
420  NT_PRSTATUS = 1,
421  NT_FPREGSET,
422  NT_PRPSINFO,
423  NT_TASKSTRUCT,
424  NT_PLATFORM,
425  NT_AUXV,
426  NT_FILE = 0x46494c45,
427  NT_PRXFPREG = 0x46e62b7f,
428  NT_SIGINFO = 0x53494749,
429};
430
431namespace FREEBSD {
432
433enum {
434  NT_PRSTATUS = 1,
435  NT_FPREGSET,
436  NT_PRPSINFO,
437  NT_THRMISC = 7,
438  NT_PROCSTAT_AUXV = 16,
439  NT_PPC_VMX = 0x100
440};
441}
442
443// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
444static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
445                                 ArchSpec &arch) {
446  lldb::offset_t offset = 0;
447  bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 ||
448               arch.GetMachine() == llvm::Triple::mips64 ||
449               arch.GetMachine() == llvm::Triple::ppc64 ||
450               arch.GetMachine() == llvm::Triple::x86_64);
451  int pr_version = data.GetU32(&offset);
452
453  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
454  if (log) {
455    if (pr_version > 1)
456      log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version);
457  }
458
459  // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
460  if (lp64)
461    offset += 32;
462  else
463    offset += 16;
464
465  thread_data.signo = data.GetU32(&offset); // pr_cursig
466  thread_data.tid = data.GetU32(&offset);   // pr_pid
467  if (lp64)
468    offset += 4;
469
470  size_t len = data.GetByteSize() - offset;
471  thread_data.gpregset = DataExtractor(data, offset, len);
472}
473
474static void ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) {
475  lldb::offset_t offset = 0;
476  thread_data.name = data.GetCStr(&offset, 20);
477}
478
479/// Parse Thread context from PT_NOTE segment and store it in the thread list
480/// Notes:
481/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
482/// 2) NOTE Entry contains a standard header followed by variable size data.
483///   (see ELFNote structure)
484/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
485///    a) NT_PRSTATUS - Register context
486///    b) NT_PRPSINFO - Process info(pid..)
487///    c) NT_FPREGSET - Floating point registers
488/// 4) The NOTE entries can be in any order
489/// 5) If a core file contains multiple thread contexts then there is two data
490/// forms
491///    a) Each thread context(2 or more NOTE entries) contained in its own
492///    segment (PT_NOTE)
493///    b) All thread context is stored in a single segment(PT_NOTE).
494///        This case is little tricker since while parsing we have to find where
495///        the
496///        new thread starts. The current implementation marks beginning of
497///        new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
498///    For case (b) there may be either one NT_PRPSINFO per thread, or a single
499///    one that applies to all threads (depending on the platform type).
500Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
501    const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) {
502  assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
503
504  lldb::offset_t offset = 0;
505  std::unique_ptr<ThreadData> thread_data(new ThreadData);
506  bool have_prstatus = false;
507  bool have_prpsinfo = false;
508
509  ArchSpec arch = GetArchitecture();
510  ELFLinuxPrPsInfo prpsinfo;
511  ELFLinuxPrStatus prstatus;
512  ELFLinuxSigInfo siginfo;
513  size_t header_size;
514  size_t len;
515  Error error;
516
517  // Loop through the NOTE entires in the segment
518  while (offset < segment_header->p_filesz) {
519    ELFNote note = ELFNote();
520    note.Parse(segment_data, &offset);
521
522    // Beginning of new thread
523    if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
524        (note.n_type == NT_PRPSINFO && have_prpsinfo)) {
525      assert(thread_data->gpregset.GetByteSize() > 0);
526      // Add the new thread to thread list
527      m_thread_data.push_back(*thread_data);
528      *thread_data = ThreadData();
529      have_prstatus = false;
530      have_prpsinfo = false;
531    }
532
533    size_t note_start, note_size;
534    note_start = offset;
535    note_size = llvm::alignTo(note.n_descsz, 4);
536
537    // Store the NOTE information in the current thread
538    DataExtractor note_data(segment_data, note_start, note_size);
539    note_data.SetAddressByteSize(
540        m_core_module_sp->GetArchitecture().GetAddressByteSize());
541    if (note.n_name == "FreeBSD") {
542      m_os = llvm::Triple::FreeBSD;
543      switch (note.n_type) {
544      case FREEBSD::NT_PRSTATUS:
545        have_prstatus = true;
546        ParseFreeBSDPrStatus(*thread_data, note_data, arch);
547        break;
548      case FREEBSD::NT_FPREGSET:
549        thread_data->fpregset = note_data;
550        break;
551      case FREEBSD::NT_PRPSINFO:
552        have_prpsinfo = true;
553        break;
554      case FREEBSD::NT_THRMISC:
555        ParseFreeBSDThrMisc(*thread_data, note_data);
556        break;
557      case FREEBSD::NT_PROCSTAT_AUXV:
558        // FIXME: FreeBSD sticks an int at the beginning of the note
559        m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
560        break;
561      case FREEBSD::NT_PPC_VMX:
562        thread_data->vregset = note_data;
563        break;
564      default:
565        break;
566      }
567    } else if (note.n_name == "CORE") {
568      switch (note.n_type) {
569      case NT_PRSTATUS:
570        have_prstatus = true;
571        error = prstatus.Parse(note_data, arch);
572        if (error.Fail())
573          return error;
574        thread_data->prstatus_sig = prstatus.pr_cursig;
575        thread_data->tid = prstatus.pr_pid;
576        header_size = ELFLinuxPrStatus::GetSize(arch);
577        len = note_data.GetByteSize() - header_size;
578        thread_data->gpregset = DataExtractor(note_data, header_size, len);
579        break;
580      case NT_FPREGSET:
581        // In a i386 core file NT_FPREGSET is present, but it's not the result
582        // of the FXSAVE instruction like in 64 bit files.
583        // The result from FXSAVE is in NT_PRXFPREG for i386 core files
584        if (arch.GetCore() == ArchSpec::eCore_x86_64_x86_64)
585          thread_data->fpregset = note_data;
586        break;
587      case NT_PRPSINFO:
588        have_prpsinfo = true;
589        error = prpsinfo.Parse(note_data, arch);
590        if (error.Fail())
591          return error;
592        thread_data->name = prpsinfo.pr_fname;
593        SetID(prpsinfo.pr_pid);
594        break;
595      case NT_AUXV:
596        m_auxv = DataExtractor(note_data);
597        break;
598      case NT_FILE: {
599        m_nt_file_entries.clear();
600        lldb::offset_t offset = 0;
601        const uint64_t count = note_data.GetAddress(&offset);
602        note_data.GetAddress(&offset); // Skip page size
603        for (uint64_t i = 0; i < count; ++i) {
604          NT_FILE_Entry entry;
605          entry.start = note_data.GetAddress(&offset);
606          entry.end = note_data.GetAddress(&offset);
607          entry.file_ofs = note_data.GetAddress(&offset);
608          m_nt_file_entries.push_back(entry);
609        }
610        for (uint64_t i = 0; i < count; ++i) {
611          const char *path = note_data.GetCStr(&offset);
612          if (path && path[0])
613            m_nt_file_entries[i].path.SetCString(path);
614        }
615      } break;
616      case NT_SIGINFO: {
617        error = siginfo.Parse(note_data, arch);
618        if (error.Fail())
619          return error;
620        thread_data->signo = siginfo.si_signo;
621      } break;
622      default:
623        break;
624      }
625    } else if (note.n_name == "LINUX") {
626      switch (note.n_type) {
627      case NT_PRXFPREG:
628        thread_data->fpregset = note_data;
629      }
630    }
631
632    offset += note_size;
633  }
634  // Add last entry in the note section
635  if (thread_data && thread_data->gpregset.GetByteSize() > 0) {
636    m_thread_data.push_back(*thread_data);
637  }
638
639  return error;
640}
641
642uint32_t ProcessElfCore::GetNumThreadContexts() {
643  if (!m_thread_data_valid)
644    DoLoadCore();
645  return m_thread_data.size();
646}
647
648ArchSpec ProcessElfCore::GetArchitecture() {
649  ObjectFileELF *core_file =
650      (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
651  ArchSpec arch;
652  core_file->GetArchitecture(arch);
653  return arch;
654}
655
656const lldb::DataBufferSP ProcessElfCore::GetAuxvData() {
657  const uint8_t *start = m_auxv.GetDataStart();
658  size_t len = m_auxv.GetByteSize();
659  lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
660  return buffer;
661}
662
663bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
664  info.Clear();
665  info.SetProcessID(GetID());
666  info.SetArchitecture(GetArchitecture());
667  lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
668  if (module_sp) {
669    const bool add_exe_file_as_first_arg = false;
670    info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
671                           add_exe_file_as_first_arg);
672  }
673  return true;
674}
675