diff --git a/Userland/Utilities/strace.cpp b/Userland/Utilities/strace.cpp index f9e0bfd4f1..37f62a1923 100644 --- a/Userland/Utilities/strace.cpp +++ b/Userland/Utilities/strace.cpp @@ -249,6 +249,59 @@ static T copy_from_process(const T* source) return value; } +struct BitflagOption { + int value; + StringView name; +}; + +#define BITFLAG(NAME) \ + BitflagOption { NAME, #NAME } + +struct BitflagBase { + int flagset; + // Derivatives must define 'options', like so: + // static constexpr auto options = { BITFLAG(O_CREAT), BITFLAG(O_DIRECTORY) }; +}; + +namespace AK { +template + requires(IsBaseOf) && requires { BitflagDerivative::options; } +struct Formatter : StandardFormatter { + Formatter() = default; + explicit Formatter(StandardFormatter formatter) + : StandardFormatter(formatter) + { + } + + void format(FormatBuilder& format_builder, BitflagDerivative const& value) + { + bool had_any_output = false; + int remaining = value.flagset; + + for (BitflagOption const& option : BitflagDerivative::options) { + if ((remaining & option.value) != option.value) + continue; + remaining &= ~option.value; + if (had_any_output) + format_builder.put_literal(" | "); + format_builder.put_literal(option.name); + had_any_output = true; + } + + if (remaining != 0) { + // No more BitflagOptions are available. Any remaining flags are unrecognized. + if (had_any_output) + format_builder.put_literal(" | "); + format_builder.builder().appendff("0x{:x} (?)", static_cast(remaining)); + had_any_output = true; + } + + if (!had_any_output) + format_builder.put_literal("0"); + } +}; +} + struct PointerArgument { const void* value; }; @@ -377,6 +430,13 @@ static void format_exit(FormattedSyscallBuilder& builder, int status) builder.add_argument(status); } +struct OpenOptions : BitflagBase { + static constexpr auto options = { + BITFLAG(O_RDWR), BITFLAG(O_RDONLY), BITFLAG(O_WRONLY), BITFLAG(O_APPEND), BITFLAG(O_CREAT) + // TODO: etc... + }; +}; + static void format_open(FormattedSyscallBuilder& builder, Syscall::SC_open_params* params_p) { auto params = copy_from_process(params_p); @@ -388,24 +448,7 @@ static void format_open(FormattedSyscallBuilder& builder, Syscall::SC_open_param builder.add_string_argument(params.path); - Vector active_flags; - if (params.options & O_RDWR) - active_flags.append("O_RDWR"); - else if (params.options & O_RDONLY) - active_flags.append("O_RDONLY"); - else if (params.options & O_WRONLY) - active_flags.append("O_WRONLY"); - - if (params.options & O_APPEND) - active_flags.append("O_APPEND"); - if (params.options & O_CREAT) - active_flags.append("O_CREAT"); - // TODO: etc... - - // TODO: add to FormattedSyscallBuilder - StringBuilder sbuilder; - sbuilder.join(" | ", active_flags); - builder.add_argument(sbuilder.to_string()); + builder.add_argument(OpenOptions { params.options }); if (params.options & O_CREAT) builder.add_argument("{:04o}", params.mode);