Skip to content

Commit 19b2ea5

Browse files
dschuffyurydelendik
authored andcommitted
Exports .txtmap file when .wasm is exported from asm2wasm.
1 parent c977ef7 commit 19b2ea5

15 files changed

+126
-7
lines changed

auto_update_tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
print ' '.join(cmd)
4242
actual = run_command(cmd)
4343
with open(os.path.join('test', wasm), 'w') as o: o.write(actual)
44+
if 'debugInfo' in asm:
45+
cmd += ['--binarymap-file', os.path.join('test', wasm + '.map'), '-o', 'a.wasm']
46+
run_command(cmd)
47+
4448

4549
for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
4650
for s in sorted(os.listdir(os.path.join('test', dot_s_dir))):

check.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,31 @@ def do_asm2wasm_test():
189189
fail_with_error('wasm interpreter error: ' + err) # failed to pretty-print
190190
fail_with_error('wasm interpreter error')
191191

192+
# verify debug info
193+
if 'debugInfo' in asm:
194+
txtmap = 'a.wasm.txtmap'
195+
cmd += ['--binarymap-file', txtmap,
196+
'--binarymap-url', txtmap + '.map',
197+
'-o', 'a.wasm']
198+
run_command(cmd)
199+
if not os.path.isfile(txtmap):
200+
fail_with_error('Debug info map not created: %s' % txtmap)
201+
with open(wasm + '.txtmap', 'rb') as expected:
202+
with open(txtmap, 'rb') as actual:
203+
fail_if_not_identical(actual.read(), expected.read())
204+
with open('a.wasm', 'rb') as binary:
205+
url_section_name = bytearray([16]) + bytearray('sourceMappingURL')
206+
payload = txtmap + '.map'
207+
assert len(payload) < 256, 'name too long'
208+
url_section_contents = bytearray([len(payload)]) + bytearray(payload)
209+
print url_section_name
210+
binary_contents = bytearray(binary.read())
211+
if url_section_name not in binary_contents:
212+
fail_with_error('source map url section not found in binary')
213+
if url_section_contents not in binary_contents[binary_contents.index(url_section_name):]:
214+
fail_with_error('source map url not found in url section')
215+
216+
192217
print '\n[ checking asm2wasm binary reading/writing... ]\n'
193218

194219
asmjs = os.path.join(options.binaryen_test, 'hello_world.asm.js')

src/tools/asm2wasm.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ int main(int argc, const char *argv[]) {
3636
bool legalizeJavaScriptFFI = true;
3737
Asm2WasmBuilder::TrapMode trapMode = Asm2WasmBuilder::TrapMode::JS;
3838
bool wasmOnly = false;
39+
std::string binaryMapFile;
40+
std::string binaryMapUrl;
3941
std::string symbolMap;
4042
bool emitBinary = true;
4143

@@ -99,9 +101,15 @@ int main(int argc, const char *argv[]) {
99101
[&legalizeJavaScriptFFI](Options *o, const std::string &) {
100102
legalizeJavaScriptFFI = false;
101103
})
102-
.add("--debuginfo", "-g", "Emit names section and debug info (for debug info you must emit text, -S, for this to work)",
104+
.add("--debuginfo", "-g", "Emit names section in wasm binary (or full debuginfo in wast)",
103105
Options::Arguments::Zero,
104106
[&](Options *o, const std::string &arguments) { options.passOptions.debugInfo = true; })
107+
.add("--binarymap-file", "-bm", "Emit binary map (if using binary output) to the specified file",
108+
Options::Arguments::One,
109+
[&binaryMapFile](Options *o, const std::string &argument) { binaryMapFile = argument; })
110+
.add("--binarymap-url", "-bu", "Use specified string as binary map URL",
111+
Options::Arguments::One,
112+
[&binaryMapUrl](Options *o, const std::string &argument) { binaryMapUrl = argument; })
105113
.add("--symbolmap", "-s", "Emit a symbol map (indexes => names)",
106114
Options::Arguments::One,
107115
[&](Options *o, const std::string &argument) { symbolMap = argument; })
@@ -136,8 +144,9 @@ int main(int argc, const char *argv[]) {
136144
}
137145

138146
Asm2WasmPreProcessor pre;
139-
// wasm binaries can contain a names section, but not full debug info
140-
pre.debugInfo = options.passOptions.debugInfo && !emitBinary;
147+
// wasm binaries can contain a names section, but not full debug info --
148+
// debug info is disabled if a map file is not specified with wasm binary
149+
pre.debugInfo = options.passOptions.debugInfo && (!emitBinary || binaryMapFile.size());
141150
auto input(
142151
read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
143152
char *start = pre.process(input.data());
@@ -204,6 +213,10 @@ int main(int argc, const char *argv[]) {
204213
writer.setDebugInfo(options.passOptions.debugInfo);
205214
writer.setSymbolMap(symbolMap);
206215
writer.setBinary(emitBinary);
216+
if (emitBinary) {
217+
writer.setBinaryMapFilename(binaryMapFile);
218+
writer.setBinaryMapUrl(binaryMapUrl);
219+
}
207220
writer.write(wasm, options.extra["output"]);
208221

209222
if (options.debug) std::cerr << "done." << std::endl;

src/tools/wasm-as.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ int main(int argc, const char *argv[]) {
8686
if (options.debug) std::cerr << "binarification..." << std::endl;
8787
BufferWithRandomAccess buffer(options.debug);
8888
WasmBinaryWriter writer(&wasm, buffer, options.debug);
89-
writer.setDebugInfo(debugInfo);
89+
// if debug info is used, then we want to emit the names section
90+
writer.setNamesSection(debugInfo);
9091
if (symbolMap.size() > 0) writer.setSymbolMap(symbolMap);
9192
writer.write();
9293

src/wasm-binary.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ enum EncodedType {
308308

309309
namespace UserSections {
310310
extern const char* Name;
311+
extern const char* SourceMapUrl;
311312

312313
enum Subsection {
313314
NameFunction = 1,
@@ -534,8 +535,11 @@ inline S32LEB binaryWasmType(WasmType type) {
534535
class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
535536
Module* wasm;
536537
BufferWithRandomAccess& o;
538+
Function* currFunction = nullptr;
537539
bool debug;
538540
bool debugInfo = true;
541+
std::ostream* binaryMap = nullptr;
542+
std::string binaryMapUrl;
539543
std::string symbolMap;
540544

541545
MixedArena allocator;
@@ -546,7 +550,11 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
546550
prepare();
547551
}
548552

549-
void setDebugInfo(bool set) { debugInfo = set; }
553+
void setNamesSection(bool set) { debugInfo = set; }
554+
void setBinaryMap(std::ostream* set, std::string url) {
555+
binaryMap = set;
556+
binaryMapUrl = url;
557+
}
550558
void setSymbolMap(std::string set) { symbolMap = set; }
551559

552560
void write();
@@ -582,6 +590,7 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
582590
void writeFunctionTableDeclaration();
583591
void writeTableElements();
584592
void writeNames();
593+
void writeSourceMapUrl();
585594
void writeSymbolMap();
586595

587596
// helpers
@@ -607,6 +616,19 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
607616
void recurse(Expression*& curr);
608617
std::vector<Name> breakStack;
609618

619+
void visit(Expression* curr) {
620+
if (binaryMap && currFunction) {
621+
// Dump the binaryMap debug info
622+
auto& debugLocations = currFunction->debugLocations;
623+
auto iter = debugLocations.find(curr);
624+
if (iter != debugLocations.end()) {
625+
auto fileName = wasm->debugInfoFileNames[iter->second.fileIndex];
626+
*binaryMap << o.size() << ":" << fileName << ":" <<iter->second.lineNumber << '\n';
627+
}
628+
}
629+
Visitor<WasmBinaryWriter>::visit(curr);
630+
}
631+
610632
void visitBlock(Block *curr);
611633
// emits a node, but if it is a block with no name, emit a list of its contents
612634
void recursePossibleBlockContents(Expression* curr);

src/wasm-io.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,15 @@ class ModuleWriter : public ModuleIO {
4848
bool binary = true;
4949
bool debugInfo = false;
5050
std::string symbolMap;
51+
std::string binaryMapFilename;
52+
std::string binaryMapUrl;
5153

5254
public:
5355
void setBinary(bool binary_) { binary = binary_; }
5456
void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
5557
void setSymbolMap(std::string symbolMap_) { symbolMap = symbolMap_; }
58+
void setBinaryMapFilename(std::string binaryMapFilename_) { binaryMapFilename = binaryMapFilename_; }
59+
void setBinaryMapUrl(std::string binaryMapUrl_) { binaryMapUrl = binaryMapUrl_; }
5660

5761
// write text
5862
void writeText(Module& wasm, std::string filename);

src/wasm/wasm-binary.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ void WasmBinaryWriter::write() {
4646
writeFunctions();
4747
writeDataSegments();
4848
if (debugInfo) writeNames();
49+
if (binaryMap) writeSourceMapUrl();
4950
if (symbolMap.size() > 0) writeSymbolMap();
5051

5152
finishUp();
@@ -236,6 +237,7 @@ void WasmBinaryWriter::writeFunctions() {
236237
size_t sizePos = writeU32LEBPlaceholder();
237238
size_t start = o.size();
238239
Function* function = wasm->functions[i].get();
240+
currFunction = function;
239241
mappedLocals.clear();
240242
numLocalsByType.clear();
241243
if (debug) std::cerr << "writing" << function->name << std::endl;
@@ -258,6 +260,7 @@ void WasmBinaryWriter::writeFunctions() {
258260
if (debug) std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl;
259261
o.writeAt(sizePos, U32LEB(size));
260262
}
263+
currFunction = nullptr;
261264
finishSection(start);
262265
}
263266

@@ -420,6 +423,14 @@ void WasmBinaryWriter::writeNames() {
420423
finishSection(start);
421424
}
422425

426+
void WasmBinaryWriter::writeSourceMapUrl() {
427+
if (debug) std::cerr << "== writeSourceMapUrl" << std::endl;
428+
auto start = startSection(BinaryConsts::Section::User);
429+
writeInlineString(BinaryConsts::UserSections::SourceMapUrl);
430+
writeInlineString(binaryMapUrl.c_str());
431+
finishSection(start);
432+
}
433+
423434
void WasmBinaryWriter::writeSymbolMap() {
424435
std::ofstream file(symbolMap);
425436
for (auto& import : wasm->imports) {

src/wasm/wasm-io.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,21 @@ void ModuleWriter::writeBinary(Module& wasm, std::string filename) {
7272
if (debug) std::cerr << "writing binary to " << filename << "\n";
7373
BufferWithRandomAccess buffer(debug);
7474
WasmBinaryWriter writer(&wasm, buffer, debug);
75-
writer.setDebugInfo(debugInfo);
75+
// if debug info is used, then we want to emit the names section
76+
writer.setNamesSection(debugInfo);
77+
std::unique_ptr<std::ofstream> binaryMapStream;
78+
if (binaryMapFilename.size()) {
79+
binaryMapStream = make_unique<std::ofstream>();
80+
binaryMapStream->open(binaryMapFilename);
81+
writer.setBinaryMap(binaryMapStream.get(), binaryMapUrl);
82+
}
7683
if (symbolMap.size() > 0) writer.setSymbolMap(symbolMap);
7784
writer.write();
7885
Output output(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release);
7986
buffer.writeTo(output);
87+
if (binaryMapStream) {
88+
binaryMapStream->close();
89+
}
8090
}
8191

8292
void ModuleWriter::write(Module& wasm, std::string filename) {
@@ -88,4 +98,3 @@ void ModuleWriter::write(Module& wasm, std::string filename) {
8898
}
8999

90100
}
91-

src/wasm/wasm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Name WASM("wasm"),
2828
namespace BinaryConsts {
2929
namespace UserSections {
3030
const char* Name = "name";
31+
const char* SourceMapUrl = "sourceMappingURL";
3132
}
3233
}
3334

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
164:tests/hello_world.c:5
2+
168:tests/hello_world.c:6
3+
172:tests/other_file.cpp:314159
4+
194:return.cpp:50
5+
201:return.cpp:100
6+
241:even-opted.cpp:1
7+
248:even-opted.cpp:2
8+
255:even-opted.cpp:3

0 commit comments

Comments
 (0)