-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
request_common.h
250 lines (211 loc) · 9.63 KB
/
request_common.h
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// This file contains functions used by both request.cpp and request_svr.cpp
// to communicate with the debuggee's GC.
#ifndef _REQUEST_COMMON_H_
#define _REQUEST_COMMON_H_
// Indexes into an array of elements of type T, where the size of type
// T is not (or may not be) known at compile-time.
// Returns a DPTR to the requested element (the element at the given index).
template<typename T>
DPTR(T) TableIndex(DPTR(T) base, size_t index, size_t t_size)
{
TADDR base_addr = base.GetAddr();
TADDR element_addr = DacTAddrOffset(base_addr, index, t_size);
return __DPtr<T>(element_addr);
}
// Dereferences a DPTR(T*), yielding a DPTR(T).
template<typename T>
DPTR(T) Dereference(DPTR(T*) ptr)
{
TADDR ptr_base = (TADDR)*ptr;
return __DPtr<T>(ptr_base);
}
// Indexes into the global heap table, returning a TADDR to the requested
// heap instance.
inline TADDR
HeapTableIndex(DPTR(unused_gc_heap**) heaps, size_t index)
{
DPTR(unused_gc_heap*) heap_table = Dereference(heaps);
DPTR(unused_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(void*));
return Dereference(ptr).GetAddr();
}
// Starting .NET 6, it is possible for the gc_heap and generation object to have different
// layouts for coreclr.dll and clrgc.dll. Instead of using assuming dac_gc_heap and gc_heap
// have identical layout, we have the gc exported arrays of field offsets instead.
// These offsets could be -1, indicating the field does not exist in the current
// gc_heap or generation being used.
// field_offset = g_gcDacGlobals->gc_heap_field_offsets
// p_field_offset = field_offset[field_index]
// p_field = BASE + p_field_offset
// field_index++
#define LOAD_BASE(field_name, field_type) \
DPTR(int) p_##field_name##_offset = TableIndex(field_offsets, field_index, sizeof(int)); \
int field_name##_offset = *p_##field_name##_offset; \
DPTR(field_type) p_##field_name = BASE + field_name##_offset; \
field_index++;
// if (field_offset != -1)
// result.field = *p_field
#define LOAD(field_name, field_type) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
field_type field_name = *p_##field_name; \
result.field_name = field_name; \
}
// if (field_offset != -1)
// p_field.EnumMem();
#define ENUM(field_name, field_type) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
p_##field_name.EnumMem(); \
}
// if (field_offset != -1)
// result.field = DPTR(field_type)field_name
#define LOAD_DPTR(field_name, field_type) \
LOAD_BASE(field_name, field_type*) \
if (field_name##_offset != -1) \
{ \
field_type* field_name = *p_##field_name; \
result.field_name = DPTR(field_type)((TADDR)field_name); \
}
// if (field_offset != -1)
// for i from 0 to array_length - 1
// result.field[i] = *p_field
// p_field = p_field + 1
#define LOAD_ARRAY(field_name, field_type, array_length) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
for (int i = 0; i < array_length; i++) \
{ \
result.field_name[i] = *p_##field_name; \
p_##field_name = p_##field_name + 1; \
} \
}
#define ENUM_ARRAY(field_name, field_type, array_length) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
DacEnumMemoryRegion(p_##field_name.GetAddr(), sizeof(field_type) * array_length); \
}
inline bool IsRegionGCEnabled()
{
return (g_gcDacGlobals->minor_version_number & 1) != 0;
}
inline bool IsBackgroundGCEnabled()
{
return (g_gcDacGlobals->minor_version_number & 2) == 0;
}
// Load an instance of dac_gc_heap for the heap pointed by heap.
// Fields that does not exist in the current gc_heap instance is zero initialized.
// Return the dac_gc_heap object.
inline dac_gc_heap
LoadGcHeapData(TADDR heap)
{
dac_gc_heap result = {};
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = 0;
#define BASE heap
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) LOAD(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) LOAD_DPTR(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) LOAD_ARRAY(field_name, field_type, array_length);
#include "../../gc/dac_gcheap_fields.h"
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
return result;
}
inline void EnumGcHeap(TADDR heap)
{
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = 0;
#define BASE heap
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) ENUM_ARRAY(field_name, field_type, array_length)
#include "../../gc/dac_gcheap_fields.h"
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
}
// Load an instance of dac_generation for the generation pointed by generation.
// Fields that does not exist in the current generation instance is zero initialized.
// Return the dac_generation object.
inline dac_generation
LoadGeneration(TADDR generation)
{
dac_generation result = {};
DPTR(int) field_offsets = g_gcDacGlobals->generation_field_offsets;
int field_index = 0;
#define BASE generation
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) LOAD(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) LOAD_DPTR(field_name, field_type)
#include "../../gc/dac_generation_fields.h"
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
return result;
}
inline void EnumGeneration(TADDR generation)
{
DPTR(int) field_offsets = g_gcDacGlobals->generation_field_offsets;
int field_index = 0;
#define BASE generation
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) ENUM_ARRAY(field_name, field_type, array_length)
#include "../../gc/dac_generation_fields.h"
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
}
// Indexes into a given generation table, returning a dac_generation
inline dac_generation
GenerationTableIndex(DPTR(unused_generation) base, size_t index)
{
return LoadGeneration(TableIndex(base, index, g_gcDacGlobals->generation_size).GetAddr());
}
inline TADDR ServerGenerationTableAddress(TADDR heap)
{
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = GENERATION_TABLE_FIELD_INDEX;
#define BASE heap
LOAD_BASE (generation_table, unused_generation);
#undef BASE
assert (generation_table_offset != -1);
return p_generation_table.GetAddr();
}
// Indexes into a heap's generation table, given the heap instance
// and the desired index. Returns a dac_generation
inline dac_generation
ServerGenerationTableIndex(TADDR heap, size_t index)
{
DPTR(unused_generation) p_generation_table = ServerGenerationTableAddress(heap);
return LoadGeneration(TableIndex(p_generation_table, index, g_gcDacGlobals->generation_size).GetAddr());
}
inline void EnumGenerationTable(TADDR generation_table)
{
DPTR(unused_generation) p_generation_table = generation_table;
for (unsigned int i = 0; i < *g_gcDacGlobals->max_gen + 2; i++)
{
EnumGeneration(TableIndex(p_generation_table, i, g_gcDacGlobals->generation_size).GetAddr());
}
}
#undef LOAD_ARRAY
#undef LOAD_DPTR
#undef LOAD
#undef LOAD_BASE
#endif // _REQUEST_COMMON_H_