mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Ladybird+LibWeb: Add optional IDL call tracing
When launched with the new --enable-idl-tracing option, we now log every call to web platform APIs declared via IDL, along with the arguments passed. This can be very helpful when trying to figure out what a site is doing, especially if it's not doing what you'd expect.
This commit is contained in:
parent
5f9a905793
commit
f4f4f7781d
Notes:
sideshowbarker
2024-07-17 17:06:59 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f4f4f7781d Pull-request: https://github.com/SerenityOS/serenity/pull/23980
8 changed files with 110 additions and 1 deletions
|
@ -67,6 +67,8 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
arguments.append("--wait-for-debugger"sv);
|
||||
if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes)
|
||||
arguments.append("--log-all-js-exceptions"sv);
|
||||
if (web_content_options.enable_idl_tracing == Ladybird::EnableIDLTracing::Yes)
|
||||
arguments.append("--enable-idl-tracing"sv);
|
||||
if (auto server = mach_server_name(); server.has_value()) {
|
||||
arguments.append("--mach-server-name"sv);
|
||||
arguments.append(server.value());
|
||||
|
|
|
@ -117,6 +117,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
bool use_gpu_painting = false;
|
||||
bool debug_web_content = false;
|
||||
bool log_all_js_exceptions = false;
|
||||
bool enable_idl_tracing = false;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.set_general_help("The Ladybird web browser :^)");
|
||||
|
@ -129,6 +130,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content", 0);
|
||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions", 0);
|
||||
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing", 0);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
WebView::ProcessManager::initialize();
|
||||
|
@ -173,6 +175,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
.use_lagom_networking = enable_qt_networking ? Ladybird::UseLagomNetworking::No : Ladybird::UseLagomNetworking::Yes,
|
||||
.wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No,
|
||||
.log_all_js_exceptions = log_all_js_exceptions ? Ladybird::LogAllJSExceptions::Yes : Ladybird::LogAllJSExceptions::No,
|
||||
.enable_idl_tracing = enable_idl_tracing ? Ladybird::EnableIDLTracing::Yes : Ladybird::EnableIDLTracing::No,
|
||||
};
|
||||
|
||||
Ladybird::BrowserWindow window(initial_urls, cookie_jar, web_content_options, webdriver_content_ipc_path);
|
||||
|
|
|
@ -40,6 +40,11 @@ enum class LogAllJSExceptions {
|
|||
Yes
|
||||
};
|
||||
|
||||
enum class EnableIDLTracing {
|
||||
No,
|
||||
Yes
|
||||
};
|
||||
|
||||
struct WebContentOptions {
|
||||
String command_line;
|
||||
String executable_path;
|
||||
|
@ -50,6 +55,7 @@ struct WebContentOptions {
|
|||
UseLagomNetworking use_lagom_networking { UseLagomNetworking::No };
|
||||
WaitForDebugger wait_for_debugger { WaitForDebugger::No };
|
||||
LogAllJSExceptions log_all_js_exceptions { LogAllJSExceptions::No };
|
||||
EnableIDLTracing enable_idl_tracing { EnableIDLTracing::No };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ namespace JS {
|
|||
extern bool g_log_all_js_exceptions;
|
||||
}
|
||||
|
||||
namespace Web::WebIDL {
|
||||
extern bool g_enable_idl_tracing;
|
||||
}
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
AK::set_rich_debug_enabled(true);
|
||||
|
@ -94,6 +98,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
bool use_gpu_painting = false;
|
||||
bool wait_for_debugger = false;
|
||||
bool log_all_js_exceptions = false;
|
||||
bool enable_idl_tracing = false;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(command_line, "Chrome process command line", "command-line", 0, "command_line");
|
||||
|
@ -106,6 +111,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
args_parser.add_option(wait_for_debugger, "Wait for debugger", "wait-for-debugger", 0);
|
||||
args_parser.add_option(mach_server_name, "Mach server name", "mach-server-name", 0, "mach_server_name");
|
||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions", 0);
|
||||
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing", 0);
|
||||
|
||||
args_parser.parse(arguments);
|
||||
|
||||
|
@ -144,6 +150,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
JS::g_log_all_js_exceptions = true;
|
||||
}
|
||||
|
||||
if (enable_idl_tracing) {
|
||||
Web::WebIDL::g_enable_idl_tracing = true;
|
||||
}
|
||||
|
||||
auto maybe_content_filter_error = load_content_filters();
|
||||
if (maybe_content_filter_error.is_error())
|
||||
dbgln("Failed to load content filters: {}", maybe_content_filter_error.error());
|
||||
|
|
|
@ -1909,6 +1909,7 @@ static void generate_function(SourceGenerator& generator, IDL::Function const& f
|
|||
function_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffix@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@function.name:snakecase@@overload_suffix@");
|
||||
[[maybe_unused]] auto& realm = *vm.current_realm();
|
||||
)~~~");
|
||||
|
||||
|
@ -2185,11 +2186,13 @@ static void generate_overload_arbiter(SourceGenerator& generator, auto const& ov
|
|||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::construct(JS::FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
WebIDL::log_trace(vm, "@constructor_class@::construct");
|
||||
)~~~");
|
||||
} else {
|
||||
function_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@function.name:snakecase@");
|
||||
)~~~");
|
||||
}
|
||||
|
||||
|
@ -2463,6 +2466,7 @@ static void generate_constructor(SourceGenerator& generator, IDL::Constructor co
|
|||
constructor_generator.append(R"~~~(
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::construct@overload_suffix@([[maybe_unused]] FunctionObject& new_target)
|
||||
{
|
||||
WebIDL::log_trace(vm(), "@constructor_class@::construct@overload_suffix@");
|
||||
)~~~");
|
||||
|
||||
generator.append(R"~~~(
|
||||
|
@ -2522,6 +2526,7 @@ static void generate_constructors(SourceGenerator& generator, IDL::Interface con
|
|||
generator.append(R"~~~(
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::construct([[maybe_unused]] FunctionObject& new_target)
|
||||
{
|
||||
WebIDL::log_trace(vm(), "@constructor_class@::construct");
|
||||
)~~~");
|
||||
generator.set("constructor.length", "0");
|
||||
generator.append(R"~~~(
|
||||
|
@ -2769,6 +2774,7 @@ static void generate_default_to_json_function(SourceGenerator& generator, ByteSt
|
|||
function_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_json)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::to_json");
|
||||
auto& realm = *vm.current_realm();
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
|
@ -3220,6 +3226,7 @@ static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@attribute.getter_callback@");
|
||||
[[maybe_unused]] auto& realm = *vm.current_realm();
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
)~~~");
|
||||
|
@ -3424,6 +3431,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
|
||||
[[maybe_unused]] auto& realm = *vm.current_realm();
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
|
@ -3508,6 +3516,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
|
||||
auto this_value = vm.this_value();
|
||||
JS::GCPtr<Window> window;
|
||||
if (this_value.is_object()) {
|
||||
|
@ -3532,6 +3541,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
|
||||
auto this_value = vm.this_value();
|
||||
if (!this_value.is_object() || !is<@fully_qualified_name@>(this_value.as_object()))
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@namespaced_name@");
|
||||
|
@ -3546,6 +3556,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
auto value = vm.argument(0);
|
||||
|
||||
|
@ -3588,6 +3599,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
|||
stringifier_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::to_string");
|
||||
[[maybe_unused]] auto& realm = *vm.current_realm();
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
|
@ -3613,6 +3625,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
|
|||
iterator_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::entries)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::entries");
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::KeyAndValue); }));
|
||||
|
@ -3620,6 +3633,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::entries)
|
|||
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::for_each)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::for_each");
|
||||
[[maybe_unused]] auto& realm = *vm.current_realm();
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
|
@ -3642,6 +3656,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::for_each)
|
|||
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::keys)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::keys");
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::Key); }));
|
||||
|
@ -3649,6 +3664,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::keys)
|
|||
|
||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::values)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@class_name@::values");
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
|
||||
return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::Value); }));
|
||||
|
@ -3735,6 +3751,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
|
|||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/Buffers.h>
|
||||
#include <LibWeb/WebIDL/OverloadResolution.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
)~~~");
|
||||
|
@ -3976,8 +3993,9 @@ void generate_constructor_implementation(IDL::Interface const& interface, String
|
|||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/Buffers.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
#include <LibWeb/WebIDL/OverloadResolution.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
)~~~");
|
||||
|
||||
|
@ -4123,6 +4141,7 @@ void @constructor_class@::initialize(JS::Realm& realm)
|
|||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@constructor_class@::@attribute.getter_callback@)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@constructor_class@::@attribute.getter_callback@");
|
||||
auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::@attribute.cpp_name@(vm); }));
|
||||
)~~~");
|
||||
|
||||
|
@ -4225,6 +4244,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
|
|||
#include <LibWeb/HTML/WindowProxy.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/Buffers.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
#include <LibWeb/WebIDL/OverloadResolution.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
|
@ -4417,6 +4437,7 @@ void generate_iterator_prototype_implementation(IDL::Interface const& interface,
|
|||
#include <LibWeb/Bindings/@prototype_class@.h>
|
||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
|
||||
#if __has_include(<LibWeb/@possible_include_path@.h>)
|
||||
# include <LibWeb/@possible_include_path@.h>
|
||||
|
@ -4483,6 +4504,7 @@ static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
|
|||
|
||||
JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::next)
|
||||
{
|
||||
WebIDL::log_trace(vm, "@prototype_class@::next");
|
||||
auto* impl = TRY(impl_from(vm));
|
||||
return TRY(throw_dom_exception_if_needed(vm, [&] { return impl->next(); }));
|
||||
}
|
||||
|
@ -4552,6 +4574,7 @@ void generate_global_mixin_implementation(IDL::Interface const& interface, Strin
|
|||
#include <LibWeb/HTML/WindowProxy.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/OverloadResolution.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
)~~~");
|
||||
|
|
|
@ -675,6 +675,7 @@ set(SOURCES
|
|||
WebIDL/ObservableArray.cpp
|
||||
WebIDL/OverloadResolution.cpp
|
||||
WebIDL/Promise.cpp
|
||||
WebIDL/Tracing.cpp
|
||||
WebSockets/WebSocket.cpp
|
||||
XHR/EventNames.cpp
|
||||
XHR/FormData.cpp
|
||||
|
|
42
Userland/Libraries/LibWeb/WebIDL/Tracing.cpp
Normal file
42
Userland/Libraries/LibWeb/WebIDL/Tracing.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/WebIDL/Tracing.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
bool g_enable_idl_tracing = false;
|
||||
|
||||
void log_trace_impl(JS::VM& vm, char const* function)
|
||||
{
|
||||
if (!g_enable_idl_tracing)
|
||||
return;
|
||||
|
||||
StringBuilder builder;
|
||||
for (size_t i = 0; i < vm.argument_count(); ++i) {
|
||||
if (i != 0)
|
||||
builder.append(", "sv);
|
||||
auto argument = vm.argument(i);
|
||||
if (argument.is_string())
|
||||
builder.append_code_point('"');
|
||||
auto string = argument.to_string_without_side_effects();
|
||||
for (auto code_point : string.code_points()) {
|
||||
if (code_point < 0x20) {
|
||||
builder.appendff("\\u{:04x}", code_point);
|
||||
continue;
|
||||
}
|
||||
builder.append_code_point(code_point);
|
||||
}
|
||||
if (argument.is_string())
|
||||
builder.append_code_point('"');
|
||||
}
|
||||
dbgln("{}({})", function, builder.string_view());
|
||||
}
|
||||
|
||||
}
|
22
Userland/Libraries/LibWeb/WebIDL/Tracing.h
Normal file
22
Userland/Libraries/LibWeb/WebIDL/Tracing.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
extern bool g_enable_idl_tracing;
|
||||
|
||||
inline void log_trace(JS::VM& vm, char const* function)
|
||||
{
|
||||
void log_trace_impl(JS::VM&, char const*);
|
||||
if (g_enable_idl_tracing)
|
||||
log_trace_impl(vm, function);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue