1//===- tools/dsymutil/SwiftModule.cpp -------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Bitcode/BitcodeReader.h"
10#include "llvm/Bitcode/LLVMBitCodes.h"
11#include "llvm/Bitstream/BitCodes.h"
12#include "llvm/Bitstream/BitstreamReader.h"
13
14namespace {
15// Copied from swift/lib/Serialization/ModuleFormat.h
16constexpr unsigned char SWIFTMODULE_SIGNATURE[] = {0xE2, 0x9C, 0xA8, 0x0E};
17constexpr uint16_t expectedMajorVersion = 0;
18constexpr unsigned MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID;
19constexpr unsigned CONTROL_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + 1;
20constexpr unsigned METADATA = 1;
21constexpr unsigned OPTIONS_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + 8;
22constexpr unsigned IS_BUILT_FROM_INTERFACE = 11;
23
24llvm::Error checkModuleSignature(llvm::BitstreamCursor &cursor,
25 llvm::ArrayRef<unsigned char> signature) {
26 for (unsigned char byte : signature) {
27 if (cursor.AtEndOfStream())
28 return llvm::createStringError(Fmt: "malformed bitstream");
29 llvm::Expected<llvm::SimpleBitstreamCursor::word_t> maybeRead =
30 cursor.Read(NumBits: 8);
31 if (!maybeRead)
32 return maybeRead.takeError();
33 if (maybeRead.get() != byte)
34 return llvm::createStringError(Fmt: "malformed bitstream");
35 }
36 return llvm::Error::success();
37}
38
39llvm::Error enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor,
40 unsigned ID) {
41 llvm::Expected<llvm::BitstreamEntry> maybeNext = cursor.advance();
42 if (!maybeNext)
43 return maybeNext.takeError();
44 llvm::BitstreamEntry next = maybeNext.get();
45
46 if (next.Kind != llvm::BitstreamEntry::SubBlock)
47 return llvm::createStringError(Fmt: "malformed bitstream");
48
49 if (next.ID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
50 if (cursor.SkipBlock())
51 return llvm::createStringError(Fmt: "malformed bitstream");
52 return enterTopLevelModuleBlock(cursor, ID);
53 }
54
55 if (next.ID != ID)
56 return llvm::createStringError(Fmt: "malformed bitstream");
57
58 if (llvm::Error Err = cursor.EnterSubBlock(BlockID: ID))
59 return Err;
60
61 return llvm::Error::success();
62}
63
64llvm::Expected<bool>
65readOptionsBlock(llvm::BitstreamCursor &cursor,
66 llvm::SmallVectorImpl<uint64_t> &scratch) {
67 bool is_built_from_interface = false;
68 while (!cursor.AtEndOfStream()) {
69 llvm::Expected<llvm::BitstreamEntry> maybeEntry = cursor.advance();
70 if (!maybeEntry)
71 return maybeEntry.takeError();
72
73 llvm::BitstreamEntry entry = maybeEntry.get();
74 if (entry.Kind == llvm::BitstreamEntry::EndBlock)
75 break;
76
77 if (entry.Kind == llvm::BitstreamEntry::Error)
78 return llvm::createStringError(Fmt: "malformed bitstream");
79
80 if (entry.Kind == llvm::BitstreamEntry::SubBlock) {
81 if (cursor.SkipBlock())
82 return llvm::createStringError(Fmt: "malformed bitstream");
83 continue;
84 }
85
86 scratch.clear();
87 llvm::StringRef blobData;
88 llvm::Expected<unsigned> maybeKind =
89 cursor.readRecord(AbbrevID: entry.ID, Vals&: scratch, Blob: &blobData);
90 if (!maybeKind)
91 return maybeKind.takeError();
92 unsigned kind = maybeKind.get();
93 switch (kind) {
94 case IS_BUILT_FROM_INTERFACE:
95 is_built_from_interface = true;
96 continue;
97 default:
98 continue;
99 }
100 }
101 return is_built_from_interface;
102}
103
104llvm::Expected<bool>
105parseControlBlock(llvm::BitstreamCursor &cursor,
106 llvm::SmallVectorImpl<uint64_t> &scratch) {
107 // The control block is malformed until we've at least read a major version
108 // number.
109 bool versionSeen = false;
110
111 while (!cursor.AtEndOfStream()) {
112 llvm::Expected<llvm::BitstreamEntry> maybeEntry = cursor.advance();
113 if (!maybeEntry)
114 return maybeEntry.takeError();
115
116 llvm::BitstreamEntry entry = maybeEntry.get();
117 if (entry.Kind == llvm::BitstreamEntry::EndBlock)
118 break;
119
120 if (entry.Kind == llvm::BitstreamEntry::Error)
121 return llvm::createStringError(Fmt: "malformed bitstream");
122
123 if (entry.Kind == llvm::BitstreamEntry::SubBlock) {
124 if (entry.ID == OPTIONS_BLOCK_ID) {
125 if (llvm::Error Err = cursor.EnterSubBlock(BlockID: OPTIONS_BLOCK_ID))
126 return Err;
127
128 return readOptionsBlock(cursor, scratch);
129 } else {
130 // Unknown metadata sub-block, possibly for use by a future version of
131 // the module format.
132 if (cursor.SkipBlock())
133 return llvm::createStringError(Fmt: "malformed bitstream");
134 }
135 continue;
136 }
137
138 scratch.clear();
139 llvm::StringRef blobData;
140 llvm::Expected<unsigned> maybeKind =
141 cursor.readRecord(AbbrevID: entry.ID, Vals&: scratch, Blob: &blobData);
142 if (!maybeKind)
143 return maybeKind.takeError();
144
145 unsigned kind = maybeKind.get();
146 if (kind == METADATA) {
147 if (versionSeen)
148 return llvm::createStringError(Fmt: "multiple metadata blocks");
149
150 uint16_t versionMajor = scratch[0];
151 if (versionMajor != expectedMajorVersion)
152 return llvm::createStringError(Fmt: "unsupported module version");
153
154 versionSeen = true;
155 }
156 }
157 return llvm::createStringError(Fmt: "could not find control block");
158}
159
160} // namespace
161
162llvm::Expected<bool> IsBuiltFromSwiftInterface(llvm::StringRef data) {
163 llvm::BitstreamCursor cursor(data);
164 if (llvm::Error Err = checkModuleSignature(cursor, signature: SWIFTMODULE_SIGNATURE))
165 return llvm::joinErrors(
166 E1: llvm::createStringError(Fmt: "could not check signature"), E2: std::move(Err));
167 if (llvm::Error Err = enterTopLevelModuleBlock(cursor, ID: MODULE_BLOCK_ID))
168 return llvm::joinErrors(
169 E1: llvm::createStringError(Fmt: "could not enter top level block"),
170 E2: std::move(Err));
171
172 llvm::BitstreamEntry topLevelEntry;
173 llvm::SmallVector<uint64_t, 32> scratch;
174
175 while (!cursor.AtEndOfStream()) {
176 llvm::Expected<llvm::BitstreamEntry> maybeEntry =
177 cursor.advance(Flags: llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
178 if (!maybeEntry)
179 return maybeEntry.takeError();
180
181 topLevelEntry = maybeEntry.get();
182 if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock)
183 break;
184
185 if (topLevelEntry.ID == CONTROL_BLOCK_ID) {
186 if (llvm::Error Err = cursor.EnterSubBlock(BlockID: CONTROL_BLOCK_ID))
187 return Err;
188 return parseControlBlock(cursor, scratch);
189 }
190 }
191 return llvm::createStringError(Fmt: "no control block found");
192}
193