Add JSC_functionOverrides=<overrides file> debugging tool.
https://bugs.webkit.org/show_bug.cgi?id=143717
Reviewed by Geoffrey Garen.
This tool allows us to do runtime replacement of function bodies with alternatives
for debugging purposes. For example, this is useful when we need to debug VM bugs
which manifest in scripts executing in webpages downloaded from remote servers
that we don't control. The tool allows us to augment those scripts with logging
or test code to help isolate the bugs.
This tool works by substituting the SourceCode at FunctionExecutable creation
time. It identifies which SourceCode to substitute by comparing the source
string against keys in a set of key value pairs.
The keys are function body strings defined by 'override' clauses in the overrides
file specified by in the JSC_functionOverrides option. The values are function
body strings defines by 'with' clauses in the overrides file.
See comment blob at top of FunctionOverrides.cpp on the formatting
of the overrides file.
At FunctionExecutable creation time, if the SourceCode string matches one of the
'override' keys from the overrides file, the tool will replace the SourceCode with
a new one based on the corresponding 'with' value string. The FunctionExecutable
will then be created with the new SourceCode instead.
Some design decisions:
1. We opted to require that the 'with' clause appear on a separate line than the
'override' clause because this makes it easier to read and write when the
'override' clause's function body is single lined and long.
2. The user can use any sequence of characters for the delimiter (except for '{',
'}' and white space characters) because this ensures that there can always be
some delimiter pattern that does not appear in the function body in the clause
e.g. in the body of strings in the JS code.
'{' and '}' are disallowed because they are used to mark the boundaries of the
function body string. White space characters are disallowed because they can
be error prone (the user may not be able to tell between spaces and tabs).
3. The start and end delimiter must be an identical sequence of characters.
I had considered allowing the use of complementary characters like <>, [], and
() for making delimiter pairs like:
[[[[ ... ]]]]
<[([( ... )])]>
But in the end, decided against it because:
a. These sequences of complementary characters can exists in JS code.
In contrast, a repeating delimiter like %%%% is unlikely to appear in JS
code.
b. It can be error prone for the user to have to type the exact complement
character for the end delimiter in reverse order.
In contrast, a repeating delimiter like %%%% is much easier to type and
less error prone. Even a sequence like @#$%^ is less error prone than
a complementary sequence because it can be copy-pasted, and need not be
typed in reverse order.
c. It is easier to parse for the same delimiter string for both start and end.
4. The tool does a lot of checks for syntax errors in the overrides file because
we don't want any overrides to fail silently. If a syntax error is detected,
the tool will print an error message and call exit(). This avoids the user
wasting time doing debugging only to be surprised later that their specified
overrides did not take effect because of some unnoticed typo.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::link):
* runtime/Executable.h:
* runtime/Options.h:
* tools/FunctionOverrides.cpp: Added.
(JSC::FunctionOverrides::overrides):
(JSC::FunctionOverrides::FunctionOverrides):
(JSC::initializeOverrideInfo):
(JSC::FunctionOverrides::initializeOverrideFor):
(JSC::hasDisallowedCharacters):
(JSC::parseClause):
(JSC::FunctionOverrides::parseOverridesInFile):
* tools/FunctionOverrides.h: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@182903 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.h b/Source/JavaScriptCore/tools/FunctionOverrides.h
new file mode 100644
index 0000000..a0d8ad4
--- /dev/null
+++ b/Source/JavaScriptCore/tools/FunctionOverrides.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FunctionOverrides_h
+#define FunctionOverrides_h
+
+#include "Options.h"
+#include "SourceCode.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class ScriptExecutable;
+
+class FunctionOverrides {
+public:
+ struct OverrideInfo {
+ SourceCode sourceCode;
+ unsigned firstLine;
+ unsigned lineCount;
+ unsigned startColumn;
+ unsigned endColumn;
+ unsigned parametersStartOffset;
+ unsigned typeProfilingStartOffset;
+ unsigned typeProfilingEndOffset;
+ };
+
+ static FunctionOverrides& overrides();
+ FunctionOverrides(const char* functionOverridesFileName);
+
+ static bool initializeOverrideFor(const SourceCode& origCode, OverrideInfo& result);
+
+private:
+ void parseOverridesInFile(const char* fileName);
+
+ HashMap<String, String> m_entries;
+};
+
+} // namespace JSC
+
+#endif // FunctionOverrides_h