-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exporting/importing debug location information from .wast/.asm.js/.s formats #1017
Conversation
See also WebAssembly/wabt#432 |
src/passes/Print.cpp
Outdated
@@ -599,6 +603,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> { | |||
} | |||
void visitFunction(Function *curr) { | |||
currFunction = curr; | |||
lastPrintedLocation = {0, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think space after {
and before }
is what we have more commonly in the codebase.
src/tools/asm2wasm.cpp
Outdated
.add("--binarymap-file", "-bm", "Emit binary map (if using binary output) to the specified file", | ||
Options::Arguments::One, | ||
[&binaryMapFile](Options *o, const std::string &argument) { binaryMapFile = argument; }) | ||
.add("--binarymap-url", "-bu", "Use specified string as binary map URL", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameter defines the sourceMappingURL property that will be written in the .wasm custom section.
src/tools/asm2wasm.cpp
Outdated
@@ -132,8 +140,7 @@ int main(int argc, const char *argv[]) { | |||
} | |||
|
|||
Asm2WasmPreProcessor pre; | |||
// wasm binaries can contain a names section, but not full debug info | |||
pre.debugInfo = passOptions.debugInfo && !emitBinary; | |||
pre.debugInfo = passOptions.debugInfo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we are emitting binary, and not emitting a binary map, we can drop the debug info, I think? I.e. replace !emitBinary
with something like (!emitBinary || !binaryMapFile)
src/tools/asm2wasm.cpp
Outdated
@@ -200,7 +207,11 @@ int main(int argc, const char *argv[]) { | |||
writer.setDebugInfo(passOptions.debugInfo); | |||
writer.setSymbolMap(symbolMap); | |||
writer.setBinary(emitBinary); | |||
writer.write(wasm, options.extra["output"]); | |||
if (emitBinary && binaryMapFile.size()) { | |||
writer.writeBinary(wasm, options.extra["output"], binaryMapFile, binaryMapUrl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think a more consistent api might be to have, like we have setBinary
now (used a few lines above), setBinaryMapFile
and setBinaryMapURL
methods that we call. then we can avoid calling writeBinary
here.
src/tools/wasm-as.cpp
Outdated
@@ -86,13 +94,24 @@ int main(int argc, const char *argv[]) { | |||
if (options.debug) std::cerr << "binarification..." << std::endl; | |||
BufferWithRandomAccess buffer(options.debug); | |||
WasmBinaryWriter writer(&wasm, buffer, options.debug); | |||
writer.setDebugInfo(debugInfo); | |||
writer.setNamesSection(debugInfo); | |||
std::ofstream* binaryMapStream = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::unique_ptr
src/wasm-binary.h
Outdated
if (iter != debugLocations.end() && iter->second != lastDebugLocation) { | ||
lastDebugLocation = iter->second; | ||
auto fileName = wasm->debugInfoFileNames[iter->second.fileIndex]; | ||
*binaryMap << o.size() << ":" << fileName << ":" <<iter->second.lineNumber << ":" <<iter->second.columnNumber << '\n'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spaces before and after each <<
src/wasm.h
Outdated
uint32_t fileIndex, lineNumber; | ||
uint32_t fileIndex, lineNumber, columnNumber; | ||
bool operator==(const DebugLocation& other) { return fileIndex == other.fileIndex && lineNumber == other.lineNumber && columnNumber == other.columnNumber; } | ||
bool operator!=(const DebugLocation& other) { return !this->operator==(other); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about using the operator, i.e. !(other == *this)
?
General questions, maybe I don't understand how debug info is meant to work yet:
|
The URL is the final JavaScript JSON source maps resource (as defined in the WebAssembly/design#1051) and intended to be read (URL and then source maps) by devtools.
At the moment .txtmap is used to store debug information, but final "destination" is JSON map file. The .wasm and .txtmap (later .map) file go side-by-side (similar to JS source maps). The .wasm binary file does not contain any debug location information, only the sourceMappingURL (which points to .map). To import the location information, the .txtmap (later .map) must be read at the same time as .wasm by wasm-dis to place that in AST. |
Thanks, but what does "later map" mean in all those cases? Is that an expected spec change, or something happening now in the toolchain? |
For emscripten, there is emscripten-core/emscripten@e8dd1c8 which is planning to use regular tools/source-maps/sourcemapper.js, however the design PR recommends to use columns instead of lines. We can further modify https://github.com/kripken/emscripten/blob/master/tools/source-maps/sourcemapper.js#L130 to use byteoffset as a column. For prototyping, I'm using txt2map4wasm package (https://github.com/yurydelendik/txt2map4wasm). |
@kripken Would you recommend to add JavaScript source map generation to this PR? |
Ok, I think I see, so this emits some map file that is later translated to a full source map by the sourcemapper tool in emscripten? And you're asking if we should do the full translation here? If that translation is trivial, it might make sense to duplicate that functionality here, since then the code here would be useful by itself. But I'm not sure how simple it is, what do you think? |
About 200 SLOC, I'll submit that shortly |
Now asm2wasm and friends are exporting valid JS source map directly. For sake of simplicity of this PR and sake of re-import (for wasm-dis), I limited it to the following format:
notice that the "sources" field must precede the "mappings" field in the JSON. |
check.py
Outdated
# verify debug info | ||
if 'debugInfo' in asm: | ||
jsmap = 'a.wasm.map' | ||
cmd += ['--binarymap-file', jsmap, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since the tools now emit the source map directly, do we need binarymap
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the file is still a standalone file, I just changed its output format -- binary wasm just contains the reference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so --binarymap-file
emits a source map? what i am asking is, should we change the parameter names to --source-map
or something similar, if they just emit a source map?
or am I missing something here? is there still a binary file, with a "reference"? if so where is that documented, i don't think i see it in t he design pr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there still a binary file, with a "reference"? if so where is that documented, i don't think i see it in t he design pr?
https://github.com/WebAssembly/design/pull/1051/files#diff-8e85308ab5cc1e83e91ef59233648be2R219
"For wasm, a custom section named "sourceMappingURL"
contains the URL."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what i am asking is, should we change the parameter names to --source-map or something similar
I can change that, yes. For JSON file name it will be --source-map
, and for url (embedded in the wasm) --source-map-url
. Is it correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, those names sound good.
to make sure i understand, the current state is now that we emit just 2 files, the wasm binary (which has a section that has the URL) and the JSON source map file (which that URL should point to)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is correct. If --source-map is specified, asm2wasm and wasm-as emit additional JSON source map file. If --source-map-url is specified, the optional custom section section "sourceMappingURL" will be added to the wasm file.
If --source-map is specified for wasm-dis, this JSON source map file is used to read location information and to add these to the wast output.
9facd16
to
a2203ec
Compare
run_command(cmd) | ||
if not os.path.isfile(jsmap): | ||
fail_with_error('Debug info map not created: %s' % jsmap) | ||
with open(wasm + '.map', 'rb') as expected: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this uses some new test output files in the test dir. please also update auto_update_tests.py
which should generate all the test output files in the test folder
src/s2wasm.h
Outdated
@@ -665,22 +668,31 @@ class S2WasmBuilder { | |||
|
|||
mustMatch(":"); | |||
|
|||
Function::DebugLocation debugLocation = {0,0,0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here and in a few more places, spaces after {
and before }
would be more consistent with the rest of the code
[&sourceMapFilename](Options *o, const std::string &argument) { sourceMapFilename = argument; }) | ||
.add("--source-map-url", "-su", "Use specified string as source map URL", | ||
Options::Arguments::One, | ||
[&sourceMapUrl](Options *o, const std::string &argument) { sourceMapUrl = argument; }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are duplicated in two files. i am currently getting rid of most of the existing duplication in #1023. it would be good to do the same thing for these options, however, i understand if you want to land this first and leave the refactoring to followup work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather move this out of scope this PR -- --source-map
and --source-map-url
are not really optimization options and have different meaning in some cases, e.g. for asm2wasm --source-map
means output file, but for wasm-dis -- input file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good point, we'll need more refactoring here. Definitely let's leave for later.
src/tools/wasm-as.cpp
Outdated
@@ -86,13 +94,22 @@ int main(int argc, const char *argv[]) { | |||
if (options.debug) std::cerr << "binarification..." << std::endl; | |||
BufferWithRandomAccess buffer(options.debug); | |||
WasmBinaryWriter writer(&wasm, buffer, options.debug); | |||
writer.setDebugInfo(debugInfo); | |||
writer.setNamesSection(debugInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks weird, it used to be the same name, but now it is different. perhaps add a comment, "if debug info is used, then we want to emit the names section" (is that correct?)
src/wasm/wasm-binary.cpp
Outdated
|
||
if (!findField("sources", strlen("sources"))) | ||
throw MapParseException("cannot find the sources field in map"); | ||
mustReadChar('['); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation looks wrong here?
src/wasm/wasm-binary.cpp
Outdated
str = std::string(vec.begin(), vec.end()); | ||
}; | ||
|
||
if (!findField("sources", strlen("sources"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if body of if is on another line, please use {,}
src/wasm/wasm-binary.cpp
Outdated
@@ -1627,6 +1818,15 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { | |||
throw ParseException("Reached function end without seeing End opcode"); | |||
} | |||
if (debug) std::cerr << "zz recurse into " << ++depth << " at " << pos << std::endl; | |||
if (nextDebugLocation.first) { | |||
while (nextDebugLocation.first && nextDebugLocation.first <= pos) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation looks larger than the 2 it should be
src/wasm/wasm-binary.cpp
Outdated
@@ -1661,6 +1861,8 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { | |||
throw ParseException("bad node code " + std::to_string(code)); | |||
} | |||
} | |||
if (useDebugLocation && curr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if identation is too big, and need { }
src/wasm/wasm-s-parser.cpp
Outdated
while (debugLocEnd[0] && debugLocEnd[0] != '\n') debugLocEnd++; | ||
char* pos = debugLoc; | ||
while (pos < debugLocEnd && pos[0] != ':') pos++; | ||
if (pos >= debugLocEnd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here and later down, need {}
2dcf466
to
8062530
Compare
@@ -41,6 +41,10 @@ | |||
print ' '.join(cmd) | |||
actual = run_command(cmd) | |||
with open(os.path.join('test', wasm), 'w') as o: o.write(actual) | |||
if 'debugInfo' in asm: | |||
cmd += ['--source-map', os.path.join('test', wasm + '.map'), '-o', 'a.wasm'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is a.wasm
the right place for this? it should be stored where check.py
looks for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the code above generates proper data for test;a.wasm
is just a file we can delete -- we only need source map from this run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks. Sorry for my confusion.
Ok, this lgtm. Did anyone else want to take a look? |
Looks like no concerns, so merging. Thanks! |
This change allows (based on @dschuff 's debuginfo branch):
.txtmap.map file along with .wasm binary file export.txtmap.map file (when .wasm read) information into AST;; file.ext:line
to;;@ file.ext:line:column