예제 #1
0
/// Parse Thread context from PT_NOTE segment and store it in the thread list
/// Notes:
/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
/// 2) NOTE Entry contains a standard header followed by variable size data.
///   (see ELFNote structure)
/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
///    a) NT_PRSTATUS - Register context
///    b) NT_PRPSINFO - Process info(pid..)
///    c) NT_FPREGSET - Floating point registers
/// 4) The NOTE entries can be in any order
/// 5) If a core file contains multiple thread contexts then there is two data forms
///    a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
///    b) All thread context is stored in a single segment(PT_NOTE).
///        This case is little tricker since while parsing we have to find where the
///        new thread starts. The current implementation marks beginning of 
///        new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
///    For case (b) there may be either one NT_PRPSINFO per thread, or a single
///    one that applies to all threads (depending on the platform type).
void
ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, 
                                                   DataExtractor segment_data)
{
    assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);

    lldb::offset_t offset = 0;
    ThreadData *thread_data = new ThreadData();
    bool have_prstatus = false;
    bool have_prpsinfo = false;

    ArchSpec arch = GetArchitecture();
    ELFLinuxPrPsInfo prpsinfo;
    ELFLinuxPrStatus prstatus;
    size_t header_size;
    size_t len;

    // Loop through the NOTE entires in the segment
    while (offset < segment_header->p_filesz)
    {
        ELFNote note = ELFNote();
        note.Parse(segment_data, &offset);

        // Beginning of new thread
        if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
            (note.n_type == NT_PRPSINFO && have_prpsinfo))
        {
            assert(thread_data->gpregset.GetByteSize() > 0);
            // Add the new thread to thread list
            m_thread_data.push_back(*thread_data);
            thread_data = new ThreadData();
            have_prstatus = false;
            have_prpsinfo = false;
        }

        size_t note_start, note_size;
        note_start = offset;
        note_size = llvm::RoundUpToAlignment(note.n_descsz, 4);

        // Store the NOTE information in the current thread
        DataExtractor note_data (segment_data, note_start, note_size);
        if (note.n_name == "FreeBSD")
        {
            switch (note.n_type)
            {
                case NT_FREEBSD_PRSTATUS:
                    have_prstatus = true;
                    ParseFreeBSDPrStatus(thread_data, note_data, arch);
                    break;
                case NT_FREEBSD_FPREGSET:
                    thread_data->fpregset = note_data;
                    break;
                case NT_FREEBSD_PRPSINFO:
                    have_prpsinfo = true;
                    break;
                case NT_FREEBSD_THRMISC:
                    ParseFreeBSDThrMisc(thread_data, note_data);
                    break;
                case NT_FREEBSD_PROCSTAT_AUXV:
                    // FIXME: FreeBSD sticks an int at the beginning of the note
                    m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
                    break;
                default:
                    break;
            }
        }
        else
        {
            switch (note.n_type)
            {
                case NT_PRSTATUS:
                    have_prstatus = true;
                    prstatus.Parse(note_data, arch);
                    thread_data->signo = prstatus.pr_cursig;
                    header_size = ELFLinuxPrStatus::GetSize(arch);
                    len = note_data.GetByteSize() - header_size;
                    thread_data->gpregset = DataExtractor(note_data, header_size, len);
                    break;
                case NT_FPREGSET:
                    thread_data->fpregset = note_data;
                    break;
                case NT_PRPSINFO:
                    have_prpsinfo = true;
                    prpsinfo.Parse(note_data, arch);
                    thread_data->name = prpsinfo.pr_fname;
                    break;
                case NT_AUXV:
                    m_auxv = DataExtractor(note_data);
                    break;
                default:
                    break;
            }
        }

        offset += note_size;
    }
    // Add last entry in the note section
    if (thread_data && thread_data->gpregset.GetByteSize() > 0)
    {
        m_thread_data.push_back(*thread_data);
    }
}
예제 #2
0
/// Parse Thread context from PT_NOTE segment and store it in the thread list
/// Notes:
/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
/// 2) NOTE Entry contains a standard header followed by variable size data.
///   (see ELFNote structure)
/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
///    a) NT_PRSTATUS - Register context
///    b) NT_PRPSINFO - Process info(pid..)
///    c) NT_FPREGSET - Floating point registers
/// 4) The NOTE entries can be in any order
/// 5) If a core file contains multiple thread contexts then there is two data forms
///    a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
///    b) All thread context is stored in a single segment(PT_NOTE).
///        This case is little tricker since while parsing we have to find where the
///        new thread starts. The current implementation marks beginning of
///        new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
///    For case (b) there may be either one NT_PRPSINFO per thread, or a single
///    one that applies to all threads (depending on the platform type).
void
ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,
                                                   DataExtractor segment_data)
{
    assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);

    lldb::offset_t offset = 0;
    std::unique_ptr<ThreadData> thread_data(new ThreadData);
    bool have_prstatus = false;
    bool have_prpsinfo = false;

    ArchSpec arch = GetArchitecture();
    ELFLinuxPrPsInfo prpsinfo;
    ELFLinuxPrStatus prstatus;
    size_t header_size;
    size_t len;

    // Loop through the NOTE entires in the segment
    while (offset < segment_header->p_filesz)
    {
        ELFNote note = ELFNote();
        note.Parse(segment_data, &offset);

        // Beginning of new thread
        if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
            (note.n_type == NT_PRPSINFO && have_prpsinfo))
        {
            assert(thread_data->gpregset.GetByteSize() > 0);
            // Add the new thread to thread list
            m_thread_data.push_back(*thread_data);
            *thread_data = ThreadData();
            have_prstatus = false;
            have_prpsinfo = false;
        }

        size_t note_start, note_size;
        note_start = offset;
        note_size = llvm::alignTo(note.n_descsz, 4);

        // Store the NOTE information in the current thread
        DataExtractor note_data (segment_data, note_start, note_size);
        note_data.SetAddressByteSize(m_core_module_sp->GetArchitecture().GetAddressByteSize());
        if (note.n_name == "FreeBSD")
        {
            m_os = llvm::Triple::FreeBSD;
            switch (note.n_type)
            {
                case FREEBSD::NT_PRSTATUS:
                    have_prstatus = true;
                    ParseFreeBSDPrStatus(*thread_data, note_data, arch);
                    break;
                case FREEBSD::NT_FPREGSET:
                    thread_data->fpregset = note_data;
                    break;
                case FREEBSD::NT_PRPSINFO:
                    have_prpsinfo = true;
                    break;
                case FREEBSD::NT_THRMISC:
                    ParseFreeBSDThrMisc(*thread_data, note_data);
                    break;
                case FREEBSD::NT_PROCSTAT_AUXV:
                    // FIXME: FreeBSD sticks an int at the beginning of the note
                    m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
                    break;
                case FREEBSD::NT_PPC_VMX:
                    thread_data->vregset = note_data;
                    break;
                default:
                    break;
            }
        }
        else if (note.n_name == "CORE")
        {
            switch (note.n_type)
            {
                case NT_PRSTATUS:
                    have_prstatus = true;
                    prstatus.Parse(note_data, arch);
                    thread_data->signo = prstatus.pr_cursig;
                    thread_data->tid = prstatus.pr_pid;
                    header_size = ELFLinuxPrStatus::GetSize(arch);
                    len = note_data.GetByteSize() - header_size;
                    thread_data->gpregset = DataExtractor(note_data, header_size, len);
                    break;
                case NT_FPREGSET:
                    thread_data->fpregset = note_data;
                    break;
                case NT_PRPSINFO:
                    have_prpsinfo = true;
                    prpsinfo.Parse(note_data, arch);
                    thread_data->name = prpsinfo.pr_fname;
                    SetID(prpsinfo.pr_pid);
                    break;
                case NT_AUXV:
                    m_auxv = DataExtractor(note_data);
                    break;
                case NT_FILE:
                    {
                        m_nt_file_entries.clear();
                        lldb::offset_t offset = 0;
                        const uint64_t count = note_data.GetAddress(&offset);
                        note_data.GetAddress(&offset); // Skip page size
                        for (uint64_t i = 0; i<count; ++i)
                        {
                            NT_FILE_Entry entry;
                            entry.start = note_data.GetAddress(&offset);
                            entry.end = note_data.GetAddress(&offset);
                            entry.file_ofs = note_data.GetAddress(&offset);
                            m_nt_file_entries.push_back(entry);
                        }
                        for (uint64_t i = 0; i<count; ++i)
                        {
                            const char *path = note_data.GetCStr(&offset);
                            if (path && path[0])
                                m_nt_file_entries[i].path.SetCString(path);
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        offset += note_size;
    }
    // Add last entry in the note section
    if (thread_data && thread_data->gpregset.GetByteSize() > 0)
    {
        m_thread_data.push_back(*thread_data);
    }
}