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
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- MSFCommon.h - Common types and functions for MSF files ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_MSF_MSFCOMMON_H
#define LLVM_DEBUGINFO_MSF_MSFCOMMON_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include <cstdint>
#include <vector>
namespace llvm {
namespace msf {
static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
't', ' ', 'C', '/', 'C', '+', '+', ' ',
'M', 'S', 'F', ' ', '7', '.', '0', '0',
'\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'};
// The superblock is overlaid at the beginning of the file (offset 0).
// It starts with a magic header and is followed by information which
// describes the layout of the file system.
struct SuperBlock {
char MagicBytes[sizeof(Magic)];
// The file system is split into a variable number of fixed size elements.
// These elements are referred to as blocks. The size of a block may vary
// from system to system.
support::ulittle32_t BlockSize;
// The index of the free block map.
support::ulittle32_t FreeBlockMapBlock;
// This contains the number of blocks resident in the file system. In
// practice, NumBlocks * BlockSize is equivalent to the size of the MSF
// file.
support::ulittle32_t NumBlocks;
// This contains the number of bytes which make up the directory.
support::ulittle32_t NumDirectoryBytes;
// This field's purpose is not yet known.
support::ulittle32_t Unknown1;
// This contains the block # of the block map.
support::ulittle32_t BlockMapAddr;
};
struct MSFLayout {
MSFLayout() = default;
uint32_t mainFpmBlock() const {
assert(SB->FreeBlockMapBlock == 1 || SB->FreeBlockMapBlock == 2);
return SB->FreeBlockMapBlock;
}
uint32_t alternateFpmBlock() const {
// If mainFpmBlock is 1, this is 2. If mainFpmBlock is 2, this is 1.
return 3U - mainFpmBlock();
}
const SuperBlock *SB = nullptr;
BitVector FreePageMap;
ArrayRef<support::ulittle32_t> DirectoryBlocks;
ArrayRef<support::ulittle32_t> StreamSizes;
std::vector<ArrayRef<support::ulittle32_t>> StreamMap;
};
/// Describes the layout of a stream in an MSF layout. A "stream" here
/// is defined as any logical unit of data which may be arranged inside the MSF
/// file as a sequence of (possibly discontiguous) blocks. When we want to read
/// from a particular MSF Stream, we fill out a stream layout structure and the
/// reader uses it to determine which blocks in the underlying MSF file contain
/// the data, so that it can be pieced together in the right order.
class MSFStreamLayout {
public:
uint32_t Length;
std::vector<support::ulittle32_t> Blocks;
};
/// Determine the layout of the FPM stream, given the MSF layout. An FPM
/// stream spans 1 or more blocks, each at equally spaced intervals throughout
/// the file.
MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf,
bool IncludeUnusedFpmData = false,
bool AltFpm = false);
inline bool isValidBlockSize(uint32_t Size) {
switch (Size) {
case 512:
case 1024:
case 2048:
case 4096:
case 8192:
case 16384:
case 32768:
return true;
}
return false;
}
/// Given the specified block size, returns the maximum possible file size.
/// Block Size | Max File Size
/// <= 4096 | 4GB
/// 8192 | 8GB
/// 16384 | 16GB
/// 32768 | 32GB
/// \p Size - the block size of the MSF
inline uint64_t getMaxFileSizeFromBlockSize(uint32_t Size) {
switch (Size) {
case 8192:
return (uint64_t)UINT32_MAX * 2ULL;
case 16384:
return (uint64_t)UINT32_MAX * 3ULL;
case 32768:
return (uint64_t)UINT32_MAX * 4ULL;
default:
return (uint64_t)UINT32_MAX;
}
}
// Super Block, Fpm0, Fpm1, and Block Map
inline uint32_t getMinimumBlockCount() { return 4; }
// Super Block, Fpm0, and Fpm1 are reserved. The Block Map, although required
// need not be at block 3.
inline uint32_t getFirstUnreservedBlock() { return 3; }
inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
return divideCeil(NumBytes, BlockSize);
}
inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
return BlockNumber * BlockSize;
}
inline uint32_t getFpmIntervalLength(const MSFLayout &L) {
return L.SB->BlockSize;
}
/// Given an MSF with the specified block size and number of blocks, determine
/// how many pieces the specified Fpm is split into.
/// \p BlockSize - the block size of the MSF
/// \p NumBlocks - the total number of blocks in the MSF
/// \p IncludeUnusedFpmData - When true, this will count every block that is
/// both in the file and matches the form of an FPM block, even if some of
/// those FPM blocks are unused (a single FPM block can describe the
/// allocation status of up to 32,767 blocks, although one appears only
/// every 4,096 blocks). So there are 8x as many blocks that match the
/// form as there are blocks that are necessary to describe the allocation
/// status of the file. When this parameter is false, these extraneous
/// trailing blocks are not counted.
inline uint32_t getNumFpmIntervals(uint32_t BlockSize, uint32_t NumBlocks,
bool IncludeUnusedFpmData, int FpmNumber) {
assert(FpmNumber == 1 || FpmNumber == 2);
if (IncludeUnusedFpmData) {
// This calculation determines how many times a number of the form
// BlockSize * k + N appears in the range [0, NumBlocks). We only need to
// do this when unused data is included, since the number of blocks dwarfs
// the number of fpm blocks.
return divideCeil(NumBlocks - FpmNumber, BlockSize);
}
// We want the minimum number of intervals required, where each interval can
// represent BlockSize * 8 blocks.
return divideCeil(NumBlocks, 8 * BlockSize);
}
inline uint32_t getNumFpmIntervals(const MSFLayout &L,
bool IncludeUnusedFpmData = false,
bool AltFpm = false) {
return getNumFpmIntervals(L.SB->BlockSize, L.SB->NumBlocks,
IncludeUnusedFpmData,
AltFpm ? L.alternateFpmBlock() : L.mainFpmBlock());
}
Error validateSuperBlock(const SuperBlock &SB);
} // end namespace msf
} // end namespace llvm
#endif // LLVM_DEBUGINFO_MSF_MSFCOMMON_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|