Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- HexagonDYLDRendezvous.cpp -----------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lldb/Core/Module.h"
10
#include "lldb/Symbol/Symbol.h"
11
#include "lldb/Symbol/SymbolContext.h"
12
#include "lldb/Target/Process.h"
13
#include "lldb/Target/Target.h"
14
#include "lldb/Utility/Log.h"
15
#include "lldb/Utility/Status.h"
16
17
#include "lldb/Symbol/ObjectFile.h"
18
#include "lldb/Target/Process.h"
19
#include "lldb/Target/Target.h"
20
21
#include "HexagonDYLDRendezvous.h"
22
23
using namespace lldb;
24
using namespace lldb_private;
25
26
/// Locates the address of the rendezvous structure.  Returns the address on
27
/// success and LLDB_INVALID_ADDRESS on failure.
28
0
static addr_t ResolveRendezvousAddress(Process *process) {
29
0
  addr_t info_location;
30
0
  addr_t info_addr;
31
0
  Status error;
32
33
0
  info_location = process->GetImageInfoAddress();
34
35
0
  if (info_location == LLDB_INVALID_ADDRESS)
36
0
    return LLDB_INVALID_ADDRESS;
37
38
0
  info_addr = process->ReadPointerFromMemory(info_location, error);
39
0
  if (error.Fail())
40
0
    return LLDB_INVALID_ADDRESS;
41
42
0
  if (info_addr == 0)
43
0
    return LLDB_INVALID_ADDRESS;
44
45
0
  return info_addr;
46
0
}
47
48
HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)
49
    : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
50
0
      m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() {
51
0
  m_thread_info.valid = false;
52
53
  // Cache a copy of the executable path
54
0
  if (m_process) {
55
0
    Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
56
0
    if (exe_mod)
57
0
      exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
58
0
  }
59
0
}
60
61
0
bool HexagonDYLDRendezvous::Resolve() {
62
0
  const size_t word_size = 4;
63
0
  Rendezvous info;
64
0
  size_t address_size;
65
0
  size_t padding;
66
0
  addr_t info_addr;
67
0
  addr_t cursor;
68
69
0
  address_size = m_process->GetAddressByteSize();
70
0
  padding = address_size - word_size;
71
72
0
  if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
73
0
    cursor = info_addr = ResolveRendezvousAddress(m_process);
74
0
  else
75
0
    cursor = info_addr = m_rendezvous_addr;
76
77
0
  if (cursor == LLDB_INVALID_ADDRESS)
78
0
    return false;
79
80
0
  if (!(cursor = ReadWord(cursor, &info.version, word_size)))
81
0
    return false;
82
83
0
  if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
84
0
    return false;
85
86
0
  if (!(cursor = ReadPointer(cursor, &info.brk)))
87
0
    return false;
88
89
0
  if (!(cursor = ReadWord(cursor, &info.state, word_size)))
90
0
    return false;
91
92
0
  if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
93
0
    return false;
94
95
  // The rendezvous was successfully read.  Update our internal state.
96
0
  m_rendezvous_addr = info_addr;
97
0
  m_previous = m_current;
98
0
  m_current = info;
99
100
0
  return UpdateSOEntries();
101
0
}
102
103
0
void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {
104
0
  m_rendezvous_addr = addr;
105
0
}
106
107
0
bool HexagonDYLDRendezvous::IsValid() {
108
0
  return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
109
0
}
110
111
0
bool HexagonDYLDRendezvous::UpdateSOEntries() {
112
0
  SOEntry entry;
113
114
0
  if (m_current.map_addr == 0)
115
0
    return false;
116
117
  // When the previous and current states are consistent this is the first time
118
  // we have been asked to update.  Just take a snapshot of the currently
119
  // loaded modules.
120
0
  if (m_previous.state == eConsistent && m_current.state == eConsistent)
121
0
    return TakeSnapshot(m_soentries);
122
123
  // If we are about to add or remove a shared object clear out the current
124
  // state and take a snapshot of the currently loaded images.
125
0
  if (m_current.state == eAdd || m_current.state == eDelete) {
126
    // this is a fudge so that we can clear the assert below.
127
0
    m_previous.state = eConsistent;
128
    // We hit this assert on the 2nd run of this function after running the
129
    // calc example
130
0
    assert(m_previous.state == eConsistent);
131
0
    m_soentries.clear();
132
0
    m_added_soentries.clear();
133
0
    m_removed_soentries.clear();
134
0
    return TakeSnapshot(m_soentries);
135
0
  }
136
0
  assert(m_current.state == eConsistent);
137
138
  // Otherwise check the previous state to determine what to expect and update
139
  // accordingly.
140
0
  if (m_previous.state == eAdd)
141
0
    return UpdateSOEntriesForAddition();
142
0
  else if (m_previous.state == eDelete)
143
0
    return UpdateSOEntriesForDeletion();
144
145
0
  return false;
146
0
}
147
148
0
bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() {
149
0
  SOEntry entry;
150
0
  iterator pos;
151
152
0
  assert(m_previous.state == eAdd);
153
154
0
  if (m_current.map_addr == 0)
155
0
    return false;
156
157
0
  for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
158
0
    if (!ReadSOEntryFromMemory(cursor, entry))
159
0
      return false;
160
161
    // Only add shared libraries and not the executable. On Linux this is
162
    // indicated by an empty path in the entry. On FreeBSD it is the name of
163
    // the executable.
164
0
    if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
165
0
      continue;
166
167
0
    pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
168
0
    if (pos == m_soentries.end()) {
169
0
      m_soentries.push_back(entry);
170
0
      m_added_soentries.push_back(entry);
171
0
    }
172
0
  }
173
174
0
  return true;
175
0
}
176
177
0
bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {
178
0
  SOEntryList entry_list;
179
0
  iterator pos;
180
181
0
  assert(m_previous.state == eDelete);
182
183
0
  if (!TakeSnapshot(entry_list))
184
0
    return false;
185
186
0
  for (iterator I = begin(); I != end(); ++I) {
187
0
    pos = std::find(entry_list.begin(), entry_list.end(), *I);
188
0
    if (pos == entry_list.end())
189
0
      m_removed_soentries.push_back(*I);
190
0
  }
191
192
0
  m_soentries = entry_list;
193
0
  return true;
194
0
}
195
196
0
bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
197
0
  SOEntry entry;
198
199
0
  if (m_current.map_addr == 0)
200
0
    return false;
201
202
0
  for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
203
0
    if (!ReadSOEntryFromMemory(cursor, entry))
204
0
      return false;
205
206
    // Only add shared libraries and not the executable. On Linux this is
207
    // indicated by an empty path in the entry. On FreeBSD it is the name of
208
    // the executable.
209
0
    if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
210
0
      continue;
211
212
0
    entry_list.push_back(entry);
213
0
  }
214
215
0
  return true;
216
0
}
217
218
addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
219
0
                                       size_t size) {
220
0
  Status error;
221
222
0
  *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
223
0
  if (error.Fail())
224
0
    return 0;
225
226
0
  return addr + size;
227
0
}
228
229
0
addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
230
0
  Status error;
231
232
0
  *dst = m_process->ReadPointerFromMemory(addr, error);
233
0
  if (error.Fail())
234
0
    return 0;
235
236
0
  return addr + m_process->GetAddressByteSize();
237
0
}
238
239
0
std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
240
0
  std::string str;
241
0
  Status error;
242
0
  size_t size;
243
0
  char c;
244
245
0
  if (addr == LLDB_INVALID_ADDRESS)
246
0
    return std::string();
247
248
0
  for (;;) {
249
0
    size = m_process->ReadMemory(addr, &c, 1, error);
250
0
    if (size != 1 || error.Fail())
251
0
      return std::string();
252
0
    if (c == 0)
253
0
      break;
254
0
    else {
255
0
      str.push_back(c);
256
0
      addr++;
257
0
    }
258
0
  }
259
260
0
  return str;
261
0
}
262
263
bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,
264
0
                                                  SOEntry &entry) {
265
0
  entry.clear();
266
0
  entry.link_addr = addr;
267
268
0
  if (!(addr = ReadPointer(addr, &entry.base_addr)))
269
0
    return false;
270
271
0
  if (!(addr = ReadPointer(addr, &entry.path_addr)))
272
0
    return false;
273
274
0
  if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
275
0
    return false;
276
277
0
  if (!(addr = ReadPointer(addr, &entry.next)))
278
0
    return false;
279
280
0
  if (!(addr = ReadPointer(addr, &entry.prev)))
281
0
    return false;
282
283
0
  entry.path = ReadStringFromMemory(entry.path_addr);
284
285
0
  return true;
286
0
}
287
288
bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
289
0
                                         uint32_t &value) {
290
0
  Target &target = m_process->GetTarget();
291
292
0
  SymbolContextList list;
293
0
  target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
294
0
                                                eSymbolTypeAny, list);
295
0
  if (list.IsEmpty())
296
0
    return false;
297
298
0
  Address address = list[0].symbol->GetAddress();
299
0
  addr_t addr = address.GetLoadAddress(&target);
300
0
  if (addr == LLDB_INVALID_ADDRESS)
301
0
    return false;
302
303
0
  Status error;
304
0
  value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
305
0
      addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
306
0
  if (error.Fail())
307
0
    return false;
308
309
0
  if (field == eSize)
310
0
    value /= 8; // convert bits to bytes
311
312
0
  return true;
313
0
}
314
315
const HexagonDYLDRendezvous::ThreadInfo &
316
0
HexagonDYLDRendezvous::GetThreadInfo() {
317
0
  if (!m_thread_info.valid) {
318
0
    bool ok = true;
319
320
0
    ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
321
0
                       m_thread_info.dtv_offset);
322
0
    ok &=
323
0
        FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
324
0
    ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
325
0
                       m_thread_info.modid_offset);
326
0
    ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
327
0
                       m_thread_info.tls_offset);
328
329
0
    if (ok)
330
0
      m_thread_info.valid = true;
331
0
  }
332
333
0
  return m_thread_info;
334
0
}
335
336
0
void HexagonDYLDRendezvous::DumpToLog(Log *log) const {
337
0
  int state = GetState();
338
339
0
  if (!log)
340
0
    return;
341
342
0
  log->PutCString("HexagonDYLDRendezvous:");
343
0
  LLDB_LOGF(log, "   Address: %" PRIx64, GetRendezvousAddress());
344
0
  LLDB_LOGF(log, "   Version: %" PRIu64, GetVersion());
345
0
  LLDB_LOGF(log, "   Link   : %" PRIx64, GetLinkMapAddress());
346
0
  LLDB_LOGF(log, "   Break  : %" PRIx64, GetBreakAddress());
347
0
  LLDB_LOGF(log, "   LDBase : %" PRIx64, GetLDBase());
348
0
  LLDB_LOGF(log, "   State  : %s",
349
0
            (state == eConsistent)
350
0
                ? "consistent"
351
0
                : (state == eAdd) ? "add"
352
0
                                  : (state == eDelete) ? "delete" : "unknown");
353
354
0
  iterator I = begin();
355
0
  iterator E = end();
356
357
0
  if (I != E)
358
0
    log->PutCString("HexagonDYLDRendezvous SOEntries:");
359
360
0
  for (int i = 1; I != E; ++I, ++i) {
361
0
    LLDB_LOGF(log, "\n   SOEntry [%d] %s", i, I->path.c_str());
362
0
    LLDB_LOGF(log, "      Base : %" PRIx64, I->base_addr);
363
0
    LLDB_LOGF(log, "      Path : %" PRIx64, I->path_addr);
364
0
    LLDB_LOGF(log, "      Dyn  : %" PRIx64, I->dyn_addr);
365
0
    LLDB_LOGF(log, "      Next : %" PRIx64, I->next);
366
0
    LLDB_LOGF(log, "      Prev : %" PRIx64, I->prev);
367
0
  }
368
0
}