summaryrefslogtreecommitdiff
path: root/Source/Core/Common/SymbolDB.h
blob: 5074b03ad57799e5bab6d843638dc057d9a98991 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

// This file contains a generic symbol map implementation. For CPU-specific
// magic, derive and extend.

#pragma once

#include <map>
#include <mutex>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "Common/Assert.h"
#include "Common/CommonTypes.h"

namespace Core
{
class CPUThreadGuard;
}

namespace Common
{
struct SCall
{
  SCall(u32 a, u32 b) : function(a), call_address(b) {}
  u32 function;
  u32 call_address;
};

struct Note
{
  std::string name;
  u32 address = 0;
  u32 size = 0;
  int layer = 0;

  Note() = default;
};

struct Symbol
{
  enum class Type
  {
    Function,
    Data,
  };

  Symbol() = default;
  explicit Symbol(const std::string& symbol_name) { Rename(symbol_name); }

  void Rename(const std::string& symbol_name);

  bool IsDemangled() const { return !demangled_name.empty(); }

  const std::string& GetDisplayName(bool use_demangled_name) const
  {
    if (use_demangled_name && IsDemangled())
    {
      return demangled_name;
    }
    else
    {
      return name;
    }
  }

  std::string name;
  std::string demangled_name;  // Demangled symbol name
  std::string function_name;   // stripped function name
  std::string object_name;     // name of object/source file symbol belongs to
  std::vector<SCall> callers;  // addresses of functions that call this function
  std::vector<SCall> calls;    // addresses of functions that are called by this function
  u32 hash = 0;                // use for HLE function finding
  u32 address = 0;
  u32 flags = 0;
  u32 size = 0;
  int num_calls = 0;
  Type type = Type::Function;
  int index = 0;  // only used for coloring the disasm view
  bool analyzed = false;
};

enum
{
  FFLAG_TIMERINSTRUCTIONS = (1 << 0),
  FFLAG_LEAF = (1 << 1),
  FFLAG_ONLYCALLSNICELEAFS = (1 << 2),
  FFLAG_EVIL = (1 << 3),
  FFLAG_RFI = (1 << 4),
  FFLAG_STRAIGHT = (1 << 5)
};

class SymbolDB
{
public:
  using XFuncMap = std::map<u32, Symbol>;
  using XNoteMap = std::map<u32, Note>;
  using XFuncPtrMap = std::map<u32, std::set<Symbol*>>;

  SymbolDB();
  virtual ~SymbolDB();

  virtual const Symbol* GetSymbolFromAddr(u32 addr) const { return nullptr; }
  virtual const Symbol* AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr)
  {
    return nullptr;
  }
  void AddCompleteSymbol(const Symbol& symbol);
  bool RenameSymbol(const Symbol& symbol, const std::string& symbol_name);
  bool RenameSymbol(const Symbol& symbol, const std::string& symbol_name,
                    const std::string& object_name);

  const Symbol* GetSymbolFromName(std::string_view name) const;
  std::vector<const Symbol*> GetSymbolsFromName(std::string_view name) const;
  const Symbol* GetSymbolFromHash(u32 hash) const;
  std::vector<const Symbol*> GetSymbolsFromHash(u32 hash) const;

  template <typename F>
  void ForEachSymbol(F f) const
  {
    std::lock_guard lock(m_mutex);
    for (const auto& [addr, symbol] : m_functions)
      f(symbol);
  }

  template <typename F>
  void ForEachSymbolWithMutation(F f)
  {
    std::lock_guard lock(m_mutex);
    for (auto& [addr, symbol] : m_functions)
    {
      f(symbol);
      ASSERT_MSG(COMMON, addr == symbol.address, "Symbol address was unexpectedly changed");
    }
  }

  template <typename F>
  void ForEachNote(F f) const
  {
    std::lock_guard lock(m_mutex);
    for (const auto& [addr, note] : m_notes)
      f(note);
  }

  template <typename F>
  void ForEachNoteWithMutation(F f)
  {
    std::lock_guard lock(m_mutex);
    for (auto& [addr, note] : m_notes)
    {
      f(note);
      ASSERT_MSG(COMMON, addr == note.address, "Note address was unexpectedly changed");
    }
  }

  bool IsEmpty() const;
  bool Clear(const char* prefix = "");
  void List();
  void Index();

protected:
  static void Index(XFuncMap* functions);

  XFuncMap m_functions;
  XNoteMap m_notes;
  XFuncPtrMap m_checksum_to_function;
  std::string m_map_name;
  mutable std::recursive_mutex m_mutex;
};
}  // namespace Common