summaryrefslogtreecommitdiffstats
path: root/app/perfsymboltable.h
blob: 338724587509778bedc057e800bdaa03a8e96a9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/

#pragma once

#include "perfaddresscache.h"
#include "perfdata.h"
#include "perfelfmap.h"
#include "perfunwind.h"

#include <libdwfl.h>

#include <QObject>

class PerfDwarfDieCache;
class SubProgramDie;
class CuDieRangeMapping;

class PerfSymbolTable
{
public:
    PerfSymbolTable(qint32 pid, Dwfl_Callbacks *callbacks, PerfUnwind *parent);
    ~PerfSymbolTable();

    static QFileInfo findDebugInfoFile(
            const QString& root, const QString& file, const QString& debugLinkString);

    struct PerfMapSymbol {
        PerfMapSymbol(quint64 start = 0, quint64 length = 0, const QByteArray &name = QByteArray()) :
            start(start), length(length), name(name) {}
        quint64 start;
        quint64 length;
        QByteArray name;
    };

    // Announce an mmap. Invalidate the symbol and address cache and clear the dwfl if it overlaps
    // with an existing one.
    void registerElf(const PerfRecordMmap &mmap, const QByteArray &buildId);

    PerfElfMap::ElfInfo findElf(quint64 ip) const;

    // Find the module for the given address and report it if needed
    Dwfl_Module *module(quint64 addr);
    Dwfl_Module *module(quint64 addr, const PerfElfMap::ElfInfo &elf);
    int findDebugInfo(Dwfl_Module *module, const char *moduleName, Dwarf_Addr base,
                      const char *file, const char *debugLink,
                      GElf_Word crc, char **debugInfoFilename);

    // Look up a frame and all its inline parents and append them to the given vector.
    // If the frame hits an elf that hasn't been reported, yet, report it.
    int lookupFrame(Dwarf_Addr ip, bool isKernel, bool *isInterworking);

    void updatePerfMap();
    bool containsAddress(quint64 address) const;

    Dwfl *attachDwfl(const Dwfl_Thread_Callbacks *callbacks, PerfUnwind::UnwindInfo *unwindInfo);
    void clearCache();
    bool cacheIsDirty() const { return m_cacheIsDirty; }

    void initAfterFork(const PerfSymbolTable *parent);

private:
    // Report an mmap to dwfl and parse it for symbols and inlines, or simply return it if dwfl has
    // it already
    Dwfl_Module *reportElf(const PerfElfMap::ElfInfo& elf);
    QFileInfo findFile(const QString& path, const QString& fileName, const QByteArray& buildId = QByteArray()) const;

    class ElfAndFile {
    public:
        ElfAndFile() {}
        explicit ElfAndFile(const QFileInfo &fullPath);
        ElfAndFile(ElfAndFile &&other);
        ElfAndFile &operator=(ElfAndFile &&other);
        ElfAndFile(const ElfAndFile &other) = delete;
        ElfAndFile &operator=(const ElfAndFile &other) = delete;
        ~ElfAndFile();

        Elf *elf() const { return m_elf; }
        QFileInfo fullPath() const { return m_fullPath; }

    private:
        void clear();

        Elf *m_elf = nullptr;
        int m_file = -1;
        QFileInfo m_fullPath;
    };

    QFile m_perfMapFile;
    QVector<PerfMapSymbol> m_perfMap;
    bool m_hasPerfMap;
    bool m_cacheIsDirty;

    PerfUnwind *m_unwind;
    Dwfl *m_dwfl;
    // elf used to detect architecture
    ElfAndFile m_firstElf;

    PerfElfMap m_elfs;
    PerfAddressCache::OffsetAddressCache m_invalidAddressCache;
    QHash<Dwfl_Module*, PerfDwarfDieCache> m_cuDieRanges;
    Dwfl_Callbacks *m_callbacks;
    qint32 m_pid;

    QByteArray symbolFromPerfMap(quint64 ip, GElf_Off *offset) const;
    int parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, quint64 offset, quint64 size, quint64 relAddr, qint32 binaryId, qint32 binaryPathId, qint32 actualPathId, bool isKernel,
                 Dwarf_Files *files, Dwarf_Addr entry, qint32 parentLocationId);
    int insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, Dwarf_Addr entry, quint64 offset, quint64 size, quint64 relAddr, qint32 binaryId, qint32 binaryPathId, qint32 actualPathId,
                         qint32 inlineParent, bool isKernel);
    qint32 parseDwarf(CuDieRangeMapping *cudie, SubProgramDie *subprogram, const QVector<Dwarf_Die> &inlined,
                      Dwarf_Addr bias, quint64 offset, quint64 size, quint64 relAddr, qint32 binaryId, qint32 binaryPathId, qint32 actualPathId, bool isKernel);
};

QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(PerfSymbolTable::PerfMapSymbol, Q_MOVABLE_TYPE);
QT_END_NAMESPACE