Welcome to mirror list, hosted at ThFree Co, Russian Federation.

liteweightstgdb.cpp « runtime « md « coreclr « src - github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5e110ddde6b1fc15b2fc6eac462c57e826017a16 (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
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
251
252
253
254
255
256
257
258
259
260
261
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//*****************************************************************************
// LiteWeightStgdb.cpp
//

//
// This contains definition of class CLiteWeightStgDB. This is light weight
// read-only implementation for accessing compressed meta data format.
//
//*****************************************************************************
#include "stdafx.h"                     // Precompiled header.
#include "mdfileformat.h"
#include "metamodelro.h"
#include "liteweightstgdb.h"
#include "metadatatracker.h"

#include "../hotdata/export.h"

__checkReturn
HRESULT _CallInitOnMemHelper(CLiteWeightStgdb<CMiniMd> *pStgdb, ULONG cbData, LPCVOID pData)
{
    return pStgdb->InitOnMem(cbData,pData);
}

//*****************************************************************************
// Open an in-memory metadata section for read
//*****************************************************************************
template <class MiniMd>
__checkReturn
HRESULT
CLiteWeightStgdb<MiniMd>::InitOnMem(
    ULONG   cbData,     // count of bytes in pData
    LPCVOID pData)      // points to meta data section in memory
{
    STORAGEHEADER  sHdr;                // Header for the storage.
    PSTORAGESTREAM pStream;             // Pointer to each stream.
    int            bFoundMd = false;    // true when compressed data found.
    int            i;                   // Loop control.
    HRESULT        hr = S_OK;
    ULONG          cbStreamBuffer;

    // Don't double open.
    _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0));

    // Validate the signature of the format, or it isn't ours.
    IfFailGo(MDFormat::VerifySignature((PSTORAGESIGNATURE)pData, cbData));

#ifdef FEATURE_PREJIT
    m_MiniMd.m_pHotTablesDirectory = NULL;
#endif //FEATURE_PREJIT

    // Remaining buffer size behind the stream header (pStream).
    cbStreamBuffer = cbData;
    // Get back the first stream.
    pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer);
    if (pStream == NULL)
    {
        Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header.");
        IfFailGo(CLDB_E_FILE_CORRUPT);
    }

    // Loop through each stream and pick off the ones we need.
    for (i = 0; i < sHdr.GetiStreams(); i++)
    {
        // Do we have enough buffer to read stream header?
        if (cbStreamBuffer < sizeof(*pStream))
        {
            Debug_ReportError("Stream header is not within MetaData block.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }
        // Pick off the location and size of the data.
        if (pStream->GetOffset() >= cbData)
        {   // Stream data are not in the buffer. Stream header is corrupted.
            Debug_ReportError("Stream data are not within MetaData block.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }
        void *pvCurrentData = (void *)((BYTE *)pData + pStream->GetOffset());
        ULONG cbCurrentData = pStream->GetSize();

        // Get next stream.
        PSTORAGESTREAM pNext = pStream->NextStream_Verify();
        if (pNext == NULL)
        {   // Stream header is corrupted.
            Debug_ReportError("Invalid stream header - cannot get next stream header.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }

        // Range check
        if ((LPBYTE)pNext > ((LPBYTE)pData + cbData))
        {
            Debug_ReportError("Stream header is not within MetaData block.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }

        // Stream end must fit into the buffer and we have to check integer overflow (stream start is already checked)
        if ((((LPBYTE)pvCurrentData + cbCurrentData) < (LPBYTE)pvCurrentData)  ||
            (((LPBYTE)pvCurrentData + cbCurrentData) > ((LPBYTE)pData + cbData)))
        {
            Debug_ReportError("Stream data are not within MetaData block.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }

        // String pool.
        if (strcmp(pStream->GetName(), STRING_POOL_STREAM_A) == 0)
        {
            METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolStrings, pvCurrentData, cbCurrentData, 1));
            // String pool has to end with a null-terminator, therefore we don't have to check string pool content on access.
            // Shrink size of the pool to the last null-terminator found.
            while (cbCurrentData != 0)
            {
                if (((LPBYTE)pvCurrentData)[cbCurrentData - 1] == 0)
                {   // We have found last null terminator
                    break;
                }
                // Shrink size of the pool
                cbCurrentData--;
                Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap.");
            }
            // Initialize string heap with null-terminated block of data
            IfFailGo(m_MiniMd.m_StringHeap.Initialize(
                MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData),
                FALSE));        // fCopyData
        }

        // Literal String Blob pool.
        else if (strcmp(pStream->GetName(), US_BLOB_POOL_STREAM_A) == 0)
        {
            METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolUSBlobs, pvCurrentData, cbCurrentData, 1));
            // Initialize user string heap with block of data
            IfFailGo(m_MiniMd.m_UserStringHeap.Initialize(
                MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData),
                FALSE));        // fCopyData
        }

        // GUID pool.
        else if (strcmp(pStream->GetName(), GUID_POOL_STREAM_A) == 0)
        {
            METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolGuids, pvCurrentData, cbCurrentData, 1));
            // Initialize guid heap with block of data
            IfFailGo(m_MiniMd.m_GuidHeap.Initialize(
                MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData),
                FALSE));        // fCopyData
        }

        // Blob pool.
        else if (strcmp(pStream->GetName(), BLOB_POOL_STREAM_A) == 0)
        {
            METADATATRACKER_ONLY(MetaDataTracker::NoteSection(TBL_COUNT + MDPoolBlobs, pvCurrentData, cbCurrentData, 1));
            // Initialize blob heap with block of data
            IfFailGo(m_MiniMd.m_BlobHeap.Initialize(
                MetaData::DataBlob((BYTE *)pvCurrentData, cbCurrentData),
                FALSE));        // fCopyData
        }

        // Found the compressed meta data stream.
        else if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0)
        {
            IfFailGo( m_MiniMd.InitOnMem(pvCurrentData, cbCurrentData) );
            bFoundMd = true;
        }

        // Found the hot meta data stream
        else if (strcmp(pStream->GetName(), HOT_MODEL_STREAM_A) == 0)
        {
#ifdef FEATURE_PREJIT
            BYTE * hotStreamEnd = reinterpret_cast< BYTE * >( pvCurrentData ) + cbCurrentData;
            ULONG * hotMetadataDir = reinterpret_cast< ULONG * >( hotStreamEnd ) - 2;
            ULONG hotPoolsSize = *hotMetadataDir;

            m_MiniMd.m_pHotTablesDirectory = (struct MetaData::HotTablesDirectory *)
                (reinterpret_cast<BYTE *>(hotMetadataDir) - hotPoolsSize - sizeof(struct MetaData::HotTablesDirectory));
            MetaData::HotTable::CheckTables(m_MiniMd.m_pHotTablesDirectory);

            DataBuffer hotMetaData(
                reinterpret_cast<BYTE *>(pvCurrentData),
                cbCurrentData);
            IfFailGo(InitHotPools(hotMetaData));
#else //!FEATURE_PREJIT
            Debug_ReportError("MetaData hot stream is peresent, but ngen is not supported.");
            // Ignore the stream
#endif //!FEATURE_PREJIT
        }
        // Pick off the next stream if there is one.
        pStream = pNext;
        cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext);
    }

    // If the meta data wasn't found, we can't handle this file.
    if (!bFoundMd)
    {
        Debug_ReportError("MetaData compressed model stream #~ not found.");
        IfFailGo(CLDB_E_FILE_CORRUPT);
    }
    else
    {   // Validate sensible heaps.
        IfFailGo(m_MiniMd.PostInit(0));
    }

    // Save off the location.
    m_pvMd = pData;
    m_cbMd = cbData;

ErrExit:
    return hr;
} // CLiteWeightStgdb<MiniMd>::InitOnMem


template <class MiniMd>
__checkReturn
HRESULT
CLiteWeightStgdb<MiniMd>::InitHotPools(
    DataBuffer hotMetaDataBuffer)
{
    HRESULT hr;
    MetaData::HotMetaData hotMetaData;
    MetaData::HotHeapsDirectoryIterator heapsIterator;

    IfFailRet(hotMetaData.Initialize(hotMetaDataBuffer));

    IfFailRet(hotMetaData.GetHeapsDirectoryIterator(&heapsIterator));

    for (;;)
    {
        MetaData::HotHeap   hotHeap;
        MetaData::HeapIndex hotHeapIndex;

        hr = heapsIterator.GetNext(&hotHeap, &hotHeapIndex);
        if (hr == S_FALSE)
        {   // End of iteration
            return S_OK;
        }

        switch (hotHeapIndex.Get())
        {
        case MetaData::HeapIndex::StringHeapIndex:
            {
                m_MiniMd.m_StringHeap.InitializeHotData(hotHeap);
                break;
            }
        case MetaData::HeapIndex::GuidHeapIndex:
            {
                m_MiniMd.m_GuidHeap.InitializeHotData(hotHeap);
                break;
            }
        case MetaData::HeapIndex::UserStringHeapIndex:
            {
                m_MiniMd.m_UserStringHeap.InitializeHotData(hotHeap);
                break;
            }
        case MetaData::HeapIndex::BlobHeapIndex:
            {
                m_MiniMd.m_BlobHeap.InitializeHotData(hotHeap);
                break;
            }
        default:
            Debug_ReportInternalError("There's a bug in HotHeapsDirectoryIterator - it should verify the heap index.");
            IfFailRet(METADATA_E_INTERNAL_ERROR);
        }
    }
} // CLiteWeightStgdb<MiniMd>::InitHotPools