1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// VerifyLayouts.h
6//
7
8//
9// Make sure that layouts of MD data strucutres doesn't change accidentally
10//
11//*****************************************************************************
12
13// The code in MD\DataSource\TargetTypes.* takes a direct dependency on
14// the layouts of types in MD. This is used by the debugger to read metadata
15// from a seperate process by deserializing the memory for these datastructures.
16//
17// You are probably reading this comment because you changed a layout and
18// one of the static_asserts failed during build. This is what you should
19// do to fix it:
20//
21// a) Go to clr\src\Debug\EE\Debugger.cpp and increment the global version counter
22// m_mdDataStructureVersion set in Debugger::Debugger()
23// Please comment the change there with a new entry in the version table
24//
25// b) If a define is conditionally changing the layout:
26// i) add, if needed, an entry to the list of define bits in
27// clr\src\Debug\EE\debugger.h Debugger::_Target_Defines
28// ii) add code like this that sets the bit in the Debugger::_defines static
29// variable
30// #ifdef MY_DEFINE
31// | DEFINE_MY_DEFINE
32// #endif
33//
34// c) Update the code in MD\DataSource\TargetTypes.h/cpp to deserialize your
35// new layout correctly. The code needs to work for any version of the layouts
36// with or without defines set. Your reader code can access the current version
37// and defines by calling:
38// reader.GetMDStructuresVersion()
39// reader.IsDefined(Define_XYZ)
40//
41// d) If your changes affect what a debugger should be reading in order to fetch
42// metadata then you probably need to change other parts of the debugger
43// implementation as well. In general the debugger cares about the schema,
44// TableDefs, storage signature, table records, and storage pools.
45//
46// e) AFTER you have fixed up the debugger stuff above, now its time to update
47// layout definitions so the static asserts will quiet down. Check out
48// the comments in VerifyLayouts.inc for how to do that.
49//
50// Thanks for helping us keep the debugger working :)
51//
52
53
54
55
56//-------------------------------------------------------------------------------
57// Type layout verification
58//
59//
60// These macros includes VerifyLayouts.inc a few times with different definitions to build up
61// the source. The final result should look something like this:
62// (don't assume specific type names/fields/offsets/sizes are accurate in this example)
63//
64//
65// class VerifyLayoutsMD
66// {
67//
68// static const int expected_offset_of_first_field_in_CMiniMdRW = 208;
69// static const int actual_offset_of_first_field_in_CMiniMdRW =
70// 208;
71// static const int offset_of_field_after_CMiniMdRW_m_Schema =
72// 312;
73// static const int offset_of_field_after_CMiniMdRW_m_Tables =
74// 316;
75// ... many more lines like this covering all fields in all marked up types ...
76//
77//
78// static const int alignment_of_first_field_in_CMiniMdRW =
79// 4;
80// static const int alignment_of_field_after_CMiniMdRW_m_Schema =
81// 8;
82// static const int alignment_of_field_after_CMiniMdRW_m_Tables =
83// 8;
84// ... many more lines like this cover all fields in all marked up types ...
85//
86//
87// static_assert_no_msg(expected_offset_of_first_field_in_CMiniMdRW == actual_offset_of_first_field_in_CMiniMdRW);
88// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Schema ==
89// ALIGN_UP(offsetof(CMiniMdRW, m_Schema) + 104, alignment_of_field_after_CMiniMdRW_m_Schema));
90// static_assert_no_msg(offset_of_field_after_CMiniMdRW_m_Tables ==
91// ALIGN_UP(offsetof(CMiniMdRW, m_Tables) + 4, alignment_of_field_after_CMiniMdRW_m_Tables));
92// ... many more lines like this cover all fields in all marked up types ...
93//
94// };
95//
96//
97//
98//
99
100#ifdef FEATURE_METADATA_VERIFY_LAYOUTS
101
102#include <stddef.h> // offsetof
103#include "static_assert.h"
104#include "metamodel.h"
105#include "WinMDInterfaces.h"
106#include "MDInternalRW.h"
107
108// other types provide friend access to this type so that the
109// offsetof macro can access their private fields
110class VerifyLayoutsMD
111{
112 // we have a bunch of arrays with this fixed size, make sure it doesn't change
113 static_assert_no_msg(TBL_COUNT == 45);
114
115
116
117#define IGNORE_COMMAS(...) __VA_ARGS__ // use this to surround templated types with commas in the name
118
119#define BEGIN_TYPE(typeName, initialFieldOffset) BEGIN_TYPE_ESCAPED(typeName, typeName, initialFieldOffset)
120#define FIELD(typeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldSize)
121#define ALIGN_FIELD(typeName, fieldName, fieldSize, fieldAlign) ALIGN_FIELD_ESCAPED(typeName, typeName, fieldName, fieldSize, fieldAlign)
122#define FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize) ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldSize)
123#define END_TYPE(typeName, typeAlign) END_TYPE_ESCAPED(typeName, typeName, typeAlign)
124
125#define BEGIN_TYPE_ESCAPED(typeName, typeNameEscaped, initialFieldOffset) \
126 static const int expected_offset_of_first_field_in_##typeNameEscaped## = initialFieldOffset; \
127 static const int actual_offset_of_first_field_in_##typeNameEscaped## =
128
129#define ALIGN_FIELD_ESCAPED(typeName, typeNameEscaped, fieldName, fieldSize, fieldAlign) \
130 offsetof(IGNORE_COMMAS(typeName), fieldName); \
131 static const int offset_of_field_after_##typeNameEscaped##_##fieldName =
132
133#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
134 fieldOffset; \
135 static const int offset_of_field_after_##typeName##_##fieldName =
136
137#define END_TYPE_ESCAPED(typeName, typeNameEscaped, typeAlignentSize) \
138 sizeof(typeName);
139
140#include "VerifyLayouts.inc"
141
142#undef BEGIN_TYPE_ESCAPED
143#undef ALIGN_FIELD_ESCAPED
144#undef END_TYPE_ESCAPED
145#undef BITFIELD
146
147#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \
148 static const int alignment_of_first_field_in_##escapedTypeName =
149#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \
150 fieldAlign; \
151 static const int alignment_of_field_after_##escapedTypeName##_##fieldName =
152#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
153 fieldSize; \
154 static const int alignment_of_field_after_##typeName##_##fieldName =
155#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize) \
156 typeAlignmentSize;
157
158#include "VerifyLayouts.inc"
159
160#undef BEGIN_TYPE_ESCAPED
161#undef ALIGN_FIELD_ESCAPED
162#undef END_TYPE_ESCAPED
163#undef BITFIELD
164
165
166#define BEGIN_TYPE_ESCAPED(typeName, escapedTypeName, initialFieldOffset) \
167 static_assert_no_msg(expected_offset_of_first_field_in_##escapedTypeName == actual_offset_of_first_field_in_##escapedTypeName);
168
169
170#define ALIGN_UP(value, alignment) (((value) + (alignment) - 1)&~((alignment) - 1))
171#define ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign) \
172 static_assert_no_msg(offset_of_field_after_##escapedTypeName##_##fieldName == \
173 ALIGN_UP(offsetof(IGNORE_COMMAS(typeName), fieldName) + fieldSize, alignment_of_field_after_##escapedTypeName##_##fieldName));
174#define BITFIELD(typeName, fieldName, fieldOffset, fieldSize) \
175 static_assert_no_msg(offset_of_field_after_##typeName##_##fieldName == \
176 ALIGN_UP(fieldOffset + fieldSize, alignment_of_field_after_##typeName##_##fieldName));
177
178#define END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignmentSize)
179#include "VerifyLayouts.inc"
180
181};
182
183
184
185
186#endif //FEATURE_METADATA_VERIFY_LAYOUTS
187