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 |
110 | class 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 | |