webassembly.cc
Go to the documentation of this file.
1 // Copyright 2018 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "bloaty.h"
16 #include "util.h"
17 
18 #include "absl/strings/substitute.h"
19 
20 using absl::string_view;
21 
22 namespace bloaty {
23 namespace wasm {
24 
25 uint64_t ReadLEB128Internal(bool is_signed, size_t size, string_view* data) {
26  uint64_t ret = 0;
27  int shift = 0;
28  int maxshift = 70;
29  const char* ptr = data->data();
30  const char* limit = ptr + data->size();
31 
32  while (ptr < limit && shift < maxshift) {
33  char byte = *(ptr++);
34  ret |= static_cast<uint64_t>(byte & 0x7f) << shift;
35  shift += 7;
36  if ((byte & 0x80) == 0) {
37  data->remove_prefix(ptr - data->data());
38  if (is_signed && shift < size && (byte & 0x40)) {
39  ret |= -(1ULL << shift);
40  }
41  return ret;
42  }
43  }
44 
45  THROW("corrupt wasm data, unterminated LEB128");
46 }
47 
49  return static_cast<bool>(ReadLEB128Internal(false, 1, data));
50 }
51 
53  return static_cast<char>(ReadLEB128Internal(false, 7, data));
54 }
55 
57  return static_cast<uint32_t>(ReadLEB128Internal(false, 32, data));
58 }
59 
61  return static_cast<int8_t>(ReadLEB128Internal(true, 7, data));
62 }
63 
65  if(data->size() < bytes) {
66  THROW("premature EOF reading variable-length DWARF data");
67  }
68  string_view ret = data->substr(0, bytes);
69  data->remove_prefix(bytes);
70  return ret;
71 }
72 
74  const uint32_t wasm_magic = 0x6d736100;
75  auto magic = ReadFixed<uint32_t>(data);
76 
77  if (magic != wasm_magic) {
78  return false;
79  }
80 
81  // TODO(haberman): do we need to fail if this is >1?
82  auto version = ReadFixed<uint32_t>(data);
83  (void)version;
84 
85  return true;
86 }
87 
88 class Section {
89  public:
94 
95  static Section Read(string_view* data_param) {
96  Section ret;
97  string_view data = *data_param;
98  string_view section_data = data;
99 
100  ret.id = ReadVarUInt7(&data);
102  ret.contents = ReadPiece(size, &data);
103  size_t header_size = ret.contents.data() - section_data.data();
104  ret.data = ReadPiece(size + header_size, &section_data);
105 
106  if (ret.id == 0) {
107  uint32_t name_len = ReadVarUInt32(&ret.contents);
108  ret.name = std::string(ReadPiece(name_len, &ret.contents));
109  } else if (ret.id <= 13) {
110  ret.name = names[ret.id];
111  } else {
112  THROWF("Unknown section id: $0", ret.id);
113  }
114 
115  *data_param = data;
116  return ret;
117  }
118 
119  enum Name {
120  kType = 1,
121  kImport = 2,
123  kTable = 4,
124  kMemory = 5,
125  kGlobal = 6,
126  kExport = 7,
127  kStart = 8,
128  kElement = 9,
129  kCode = 10,
130  kData = 11,
132  kEvent = 13,
133  };
134 
135  static const char* names[];
136 };
137 
138 const char* Section::names[] = {
139  "<none>", // 0
140  "Type", // 1
141  "Import", // 2
142  "Function", // 3
143  "Table", // 4
144  "Memory", // 5
145  "Global", // 6
146  "Export", // 7
147  "Start", // 8
148  "Element", // 9
149  "Code", // 10
150  "Data", // 11
151  "DataCount", // 12
152  "Event", // 13
153 };
154 
155 struct ExternalKind {
156  enum Kind {
158  kTable = 1,
159  kMemory = 2,
160  kGlobal = 3,
161  };
162 };
163 
164 template <class Func>
165 void ForEachSection(string_view file, Func&& section_func) {
167  ReadMagic(&data);
168 
169  while (!data.empty()) {
171  section_func(section);
172  }
173 }
174 
176  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
177  sink->AddFileRange("wasm_sections", section.name, section.data);
178  });
179 }
180 
181 typedef std::unordered_map<int, std::string> FuncNames;
182 
184  RangeSink* sink) {
185  enum class NameType {
186  kModule = 0,
187  kFunction = 1,
188  kLocal = 2,
189  };
190 
191  string_view data = section.contents;
192 
193  while (!data.empty()) {
194  char type = ReadVarUInt7(&data);
197 
198  if (static_cast<NameType>(type) == NameType::kFunction) {
200  for (uint32_t i = 0; i < count; i++) {
201  string_view entry = section;
203  uint32_t name_len = ReadVarUInt32(&section);
204  string_view name = ReadPiece(name_len, &section);
205  entry = StrictSubstr(entry, 0, name.data() - entry.data() + name.size());
206  sink->AddFileRange("wasm_funcname", name, entry);
207  (*names)[index] = std::string(name);
208  }
209  }
210  }
211 }
212 
214  return ReadVarint7(data);
215 }
216 
218  return ReadVarint7(data);
219 }
220 
222  auto flags = ReadVarUInt1(data);
224  if (flags) {
226  }
227 }
228 
232 }
233 
237 }
238 
241 }
242 
244  assert(section.id == Section::kImport);
245  string_view data = section.contents;
246 
248  uint32_t func_count = 0;
249 
250  for (uint32_t i = 0; i < count; i++) {
251  uint32_t module_len = ReadVarUInt32(&data);
252  ReadPiece(module_len, &data);
253  uint32_t field_len = ReadVarUInt32(&data);
254  ReadPiece(field_len, &data);
255  auto kind = ReadFixed<uint8_t>(&data);
256 
257  switch (kind) {
259  func_count++;
261  break;
264  break;
267  break;
270  break;
271  default:
272  THROWF("Unrecognized import kind: $0", kind);
273  }
274  }
275 
276  return func_count;
277 }
278 
280  uint32_t num_imports, RangeSink* sink) {
281  string_view data = section.contents;
282 
284 
285  for (uint32_t i = 0; i < count; i++) {
288  uint32_t total_size = size + (data.data() - func.data());
289 
290  func = StrictSubstr(func, 0, total_size);
292 
293  auto iter = names.find(num_imports + i);
294 
295  if (iter == names.end()) {
296  std::string name = "func[" + std::to_string(i) + "]";
297  sink->AddFileRange("wasm_function", name, func);
298  } else {
299  sink->AddFileRange("wasm_function", ItaniumDemangle(iter->second, sink->data_source()), func);
300  }
301  }
302 }
303 
305  // First pass: read the custom naming section to get function names.
306  std::unordered_map<int, std::string> func_names;
307  uint32_t num_imports = 0;
308 
309  ForEachSection(sink->input_file().data(),
310  [&func_names, sink](const Section& section) {
311  if (section.name == "name") {
312  ReadFunctionNames(section, &func_names, sink);
313  }
314  });
315 
316  // Second pass: read the function/code sections.
317  ForEachSection(sink->input_file().data(),
318  [&func_names, &num_imports, sink](const Section& section) {
319  if (section.id == Section::kImport) {
320  num_imports = GetNumFunctionImports(section);
321  } else if (section.id == Section::kCode) {
322  ReadCodeSection(section, func_names, num_imports, sink);
323  }
324  });
325 }
326 
328  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
329  std::string name2 =
330  std::string("[section ") + std::string(section.name) + std::string("]");
331  sink->AddFileRange("wasm_overhead", name2, section.data);
332  });
333  sink->AddFileRange("wasm_overhead", "[WASM Header]",
334  StrictSubstr(sink->input_file().data(), 0, 8));
335 }
336 
338  public:
339  WebAssemblyObjectFile(std::unique_ptr<InputFile> file_data)
340  : ObjectFile(std::move(file_data)) {}
341 
342  std::string GetBuildId() const override {
343  // TODO(haberman): does WebAssembly support this?
344  return std::string();
345  }
346 
347  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
348  for (auto sink : sinks) {
349  switch (sink->data_source()) {
350  case DataSource::kSegments:
351  case DataSource::kSections:
353  break;
354  case DataSource::kSymbols:
355  case DataSource::kRawSymbols:
356  case DataSource::kShortSymbols:
357  case DataSource::kFullSymbols:
359  break;
360  case DataSource::kArchiveMembers:
361  case DataSource::kCompileUnits:
362  case DataSource::kInlines:
363  default:
364  THROW("WebAssembly doesn't support this data source");
365  }
367  }
368  }
369 
371  DataSource /*symbol_source*/,
372  DisassemblyInfo* /*info*/) const override {
373  WARN("WebAssembly files do not support disassembly yet");
374  return false;
375  }
376 };
377 
378 } // namespace wasm
379 
380 std::unique_ptr<ObjectFile> TryOpenWebAssemblyFile(
381  std::unique_ptr<InputFile>& file) {
382  string_view data = file->data();
383  if (wasm::ReadMagic(&data)) {
384  return std::unique_ptr<ObjectFile>(
386  }
387 
388  return nullptr;
389 }
390 
391 } // namespace bloaty
bloaty::wasm::ExternalKind::kFunction
@ kFunction
Definition: webassembly.cc:157
bloaty::wasm::ForEachSection
void ForEachSection(string_view file, Func &&section_func)
Definition: webassembly.cc:165
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
bloaty::wasm::ReadValueType
int ReadValueType(string_view *data)
Definition: webassembly.cc:213
bloaty::wasm::ReadMagic
bool ReadMagic(string_view *data)
Definition: webassembly.cc:73
bloaty::wasm::ReadVarUInt1
bool ReadVarUInt1(string_view *data)
Definition: webassembly.cc:48
bloaty::wasm::ReadPiece
string_view ReadPiece(size_t bytes, string_view *data)
Definition: webassembly.cc:64
bloaty
Definition: bloaty.cc:69
bloaty::wasm::ExternalKind::Kind
Kind
Definition: webassembly.cc:156
bloaty::wasm::ReadFunctionNames
void ReadFunctionNames(const Section &section, FuncNames *names, RangeSink *sink)
Definition: webassembly.cc:183
section
OPENSSL_EXPORT const char * section
Definition: conf.h:114
file
const grpc_generator::File * file
Definition: python_private_generator.h:38
bloaty::wasm::ReadCodeSection
void ReadCodeSection(const Section &section, const FuncNames &names, uint32_t num_imports, RangeSink *sink)
Definition: webassembly.cc:279
magic
uintptr_t magic
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:83
bloaty::wasm::Section::id
uint32_t id
Definition: webassembly.cc:90
bloaty::ObjectFile
Definition: bloaty.h:257
bloaty::wasm::AddWebAssemblyFallback
void AddWebAssemblyFallback(RangeSink *sink)
Definition: webassembly.cc:327
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
names
sub_type names
Definition: cxa_demangle.cpp:4905
bloaty::wasm::Section::kDataCount
@ kDataCount
Definition: webassembly.cc:131
bloaty.h
bloaty::wasm::WebAssemblyObjectFile::GetBuildId
std::string GetBuildId() const override
Definition: webassembly.cc:342
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
bloaty::wasm::ReadElemType
int ReadElemType(string_view *data)
Definition: webassembly.cc:217
bloaty::wasm::WebAssemblyObjectFile::ProcessFile
void ProcessFile(const std::vector< RangeSink * > &sinks) const override
Definition: webassembly.cc:347
bloaty::wasm::ReadMemoryType
void ReadMemoryType(string_view *data)
Definition: webassembly.cc:239
bloaty::wasm::ParseSymbols
void ParseSymbols(RangeSink *sink)
Definition: webassembly.cc:304
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
bloaty::wasm::Section::kGlobal
@ kGlobal
Definition: webassembly.cc:125
bloaty::wasm::ReadVarUInt7
uint8_t ReadVarUInt7(string_view *data)
Definition: webassembly.cc:52
bloaty::wasm::Section::kTable
@ kTable
Definition: webassembly.cc:123
setup.name
name
Definition: setup.py:542
version
Definition: version.py:1
bloaty::wasm::Section::names
static const char * names[]
Definition: webassembly.cc:135
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
bloaty::wasm::Section::Name
Name
Definition: webassembly.cc:119
bloaty::wasm::ExternalKind::kTable
@ kTable
Definition: webassembly.cc:158
versiongenerate.file_data
string file_data
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/xcode/Scripts/versiongenerate.py:84
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
ULL
#define ULL(x)
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:57
bloaty::ItaniumDemangle
std::string ItaniumDemangle(string_view symbol, DataSource source)
Definition: bloaty.cc:169
bloaty::wasm::Section::kMemory
@ kMemory
Definition: webassembly.cc:124
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
THROW
#define THROW(msg)
Definition: bloaty/src/util.h:45
absl::random_internal_nanobenchmark::Func
FuncOutput(*)(const void *, FuncInput) Func
Definition: abseil-cpp/absl/random/internal/nanobenchmark.h:68
bloaty::wasm::GetNumFunctionImports
uint32_t GetNumFunctionImports(const Section &section)
Definition: webassembly.cc:243
bloaty::wasm::WebAssemblyObjectFile
Definition: webassembly.cc:337
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
bloaty::wasm::ReadResizableLimits
void ReadResizableLimits(string_view *data)
Definition: webassembly.cc:221
bloaty::RangeSink
Definition: bloaty.h:110
bloaty::wasm::ExternalKind::kMemory
@ kMemory
Definition: webassembly.cc:159
bloaty::wasm::Section::contents
string_view contents
Definition: webassembly.cc:93
bloaty::wasm::ExternalKind
Definition: webassembly.cc:155
bloaty::wasm::ReadTableType
void ReadTableType(string_view *data)
Definition: webassembly.cc:234
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
bloaty::DataSource
DataSource
Definition: bloaty.h:52
bloaty::wasm::Section::kElement
@ kElement
Definition: webassembly.cc:128
bloaty::wasm::Section::kImport
@ kImport
Definition: webassembly.cc:121
bloaty::wasm::Section::kData
@ kData
Definition: webassembly.cc:130
section
Definition: loader.h:337
bloaty::wasm::Section::data
string_view data
Definition: webassembly.cc:92
bloaty::TryOpenWebAssemblyFile
std::unique_ptr< ObjectFile > TryOpenWebAssemblyFile(std::unique_ptr< InputFile > &file)
Definition: webassembly.cc:380
bloaty::wasm::Section::kFunction
@ kFunction
Definition: webassembly.cc:122
bloaty::wasm::WebAssemblyObjectFile::GetDisassemblyInfo
bool GetDisassemblyInfo(absl::string_view, DataSource, DisassemblyInfo *) const override
Definition: webassembly.cc:370
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
bloaty::wasm::Section
Definition: webassembly.cc:88
bloaty::wasm::Section::kStart
@ kStart
Definition: webassembly.cc:127
bytes
uint8 bytes[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:153
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
bloaty::wasm::ExternalKind::kGlobal
@ kGlobal
Definition: webassembly.cc:160
bloaty::wasm::Section::kCode
@ kCode
Definition: webassembly.cc:129
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
string_view
absl::string_view string_view
Definition: attr.cc:22
bloaty::wasm::ParseSections
void ParseSections(RangeSink *sink)
Definition: webassembly.cc:175
bloaty::wasm::FuncNames
std::unordered_map< int, std::string > FuncNames
Definition: webassembly.cc:181
bloaty::DisassemblyInfo
Definition: bloaty.h:317
bloaty::wasm::Section::Read
static Section Read(string_view *data_param)
Definition: webassembly.cc:95
THROWF
#define THROWF(...)
Definition: bloaty/src/util.h:46
bloaty::wasm::ReadVarUInt32
uint32_t ReadVarUInt32(string_view *data)
Definition: webassembly.cc:56
bloaty::wasm::WebAssemblyObjectFile::WebAssemblyObjectFile
WebAssemblyObjectFile(std::unique_ptr< InputFile > file_data)
Definition: webassembly.cc:339
bloaty::wasm::Section::kEvent
@ kEvent
Definition: webassembly.cc:132
iter
Definition: test_winkernel.cpp:47
bloaty::wasm::ReadVarint7
int8_t ReadVarint7(string_view *data)
Definition: webassembly.cc:60
util.h
int8_t
signed char int8_t
Definition: stdint-msvc2008.h:75
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
WARN
#define WARN(...)
Definition: bloaty/src/util.h:47
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
bloaty::wasm::ReadLEB128Internal
uint64_t ReadLEB128Internal(bool is_signed, size_t size, string_view *data)
Definition: webassembly.cc:25
bloaty::wasm::ReadGlobalType
void ReadGlobalType(string_view *data)
Definition: webassembly.cc:229
absl::string_view::data
constexpr const_pointer data() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:336
to_string
static bool to_string(zval *from)
Definition: protobuf/php/ext/google/protobuf/convert.c:333
bloaty::wasm::Section::name
std::string name
Definition: webassembly.cc:91
bloaty::StrictSubstr
absl::string_view StrictSubstr(absl::string_view data, size_t off, size_t n)
Definition: bloaty/src/util.h:89
if
if(p->owned &&p->wrapped !=NULL)
Definition: call.c:42
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
bloaty::wasm::Section::kType
@ kType
Definition: webassembly.cc:120
bloaty::wasm::Section::kExport
@ kExport
Definition: webassembly.cc:126


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:51