Bug 1790873 - Move printf_stderr() to mozglue so it can be used within js/src r=glandium,nika

Differential Revision: https://phabricator.services.mozilla.com/D157354
This commit is contained in:
Steve Fink 2024-01-11 02:09:30 +00:00
Родитель 938a635e60
Коммит ba7d3327fc
7 изменённых файлов: 176 добавлений и 201 удалений

Просмотреть файл

@ -69,6 +69,7 @@ included_inclnames_to_ignore = set(
"jit/LIROpsGenerated.h", # generated in $OBJDIR
"jit/MIROpsGenerated.h", # generated in $OBJDIR
"js/ProfilingCategoryList.h", # comes from mozglue/baseprofiler
"mozilla/glue/Debug.h", # comes from mozglue/misc, shadowed by <mozilla/Debug.h>
"jscustomallocator.h", # provided by embedders; allowed to be missing
"js-config.h", # generated in $OBJDIR
"fdlibm.h", # fdlibm

Просмотреть файл

@ -147,6 +147,10 @@ def main():
"Decimal.o",
# Ignore use of std::string in regexp AST debug output.
"regexp-ast.o",
# mozglue/misc/Debug.cpp contains a call to `printf_stderr("%s", aStr.str().c_str())`
# where `aStr` is a `std::stringstream`. In inlined opt builds, this calls
# `operator new()` and `operator delete` for a temporary.
"Debug.o",
]
all_ignored_files = set((f, 1) for f in ignored_files)

123
mozglue/misc/Debug.cpp Normal file
Просмотреть файл

@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/glue/Debug.h"
#include "mozilla/Fuzzing.h"
#include "mozilla/Sprintf.h"
#include <stdarg.h>
#include <stdio.h>
#ifdef XP_WIN
# include <io.h>
# include <windows.h>
#endif
#ifdef ANDROID
# include <android/log.h>
#endif
#ifndef ANDROID
static void vprintf_stderr_buffered(const char* aFmt, va_list aArgs) {
// Avoid interleaving by writing to an on-stack buffer and then writing in one
// go with fputs, as long as the output fits into the buffer.
char buffer[1024];
va_list argsCpy;
va_copy(argsCpy, aArgs);
int n = VsprintfLiteral(buffer, aFmt, aArgs);
if (n < int(sizeof(buffer))) {
fputs(buffer, stderr);
} else {
// Message too long for buffer. Just print it, not worrying about
// interleaving. (We could malloc, but the underlying write() syscall could
// get interleaved if the output is too big anyway.)
vfprintf(stderr, aFmt, argsCpy);
}
va_end(argsCpy);
fflush(stderr);
}
#endif
#if defined(XP_WIN)
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
if (IsDebuggerPresent()) {
int lengthNeeded = _vscprintf(aFmt, aArgs);
if (lengthNeeded) {
lengthNeeded++;
auto buf = mozilla::MakeUnique<char[]>(lengthNeeded);
if (buf) {
va_list argsCpy;
va_copy(argsCpy, aArgs);
vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy);
buf[lengthNeeded - 1] = '\0';
va_end(argsCpy);
OutputDebugStringA(buf.get());
}
}
}
vprintf_stderr_buffered(aFmt, aArgs);
}
#elif defined(ANDROID)
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
__android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs);
}
#elif defined(FUZZING_SNAPSHOT)
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
if (nyx_puts) {
auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs);
nyx_puts(msgbuf.get());
} else {
vprintf_stderr_buffered(aFmt, aArgs);
}
}
#else
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
vprintf_stderr_buffered(aFmt, aArgs);
}
#endif
MFBT_API void printf_stderr(const char* aFmt, ...) {
va_list args;
va_start(args, aFmt);
vprintf_stderr(aFmt, args);
va_end(args);
}
MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...) {
va_list args;
va_start(args, aFmt);
if (aFile == stderr) {
vprintf_stderr(aFmt, args);
} else {
vfprintf(aFile, aFmt, args);
}
va_end(args);
}
MFBT_API void print_stderr(std::stringstream& aStr) {
#if defined(ANDROID)
// On Android logcat output is truncated to 1024 chars per line, and
// we usually use std::stringstream to build up giant multi-line gobs
// of output. So to avoid the truncation we find the newlines and
// print the lines individually.
std::string line;
while (std::getline(aStr, line)) {
printf_stderr("%s\n", line.c_str());
}
#else
printf_stderr("%s", aStr.str().c_str());
#endif
}
MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr) {
if (aFile == stderr) {
print_stderr(aStr);
} else {
fprintf_stderr(aFile, "%s", aStr.str().c_str());
}
}

Просмотреть файл

@ -7,6 +7,12 @@
#ifndef mozilla_glue_Debug_h
#define mozilla_glue_Debug_h
#include "mozilla/Attributes.h" // For MOZ_FORMAT_PRINTF
#include "mozilla/Types.h" // For MFBT_API
#include <cstdarg>
#include <sstream>
/* This header file intends to supply debugging utilities for use in code
* that cannot use XPCOM debugging facilities like nsDebug.h.
* e.g. mozglue, browser/app
@ -15,52 +21,53 @@
* care; avoid including from header files.
*/
#include <io.h>
#if defined(XP_WIN)
# include <windows.h>
#endif // defined(XP_WIN)
#include "mozilla/Attributes.h"
#include "mozilla/Sprintf.h"
#if defined(MOZILLA_INTERNAL_API)
# error Do not include this file from XUL sources.
#endif
// Though this is a separate implementation than nsDebug's, we want to make the
// declarations compatible to avoid confusing the linker if both headers are
// included.
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void printf_stderr(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2);
inline void printf_stderr(const char* fmt, ...) {
#if defined(XP_WIN)
if (IsDebuggerPresent()) {
char buf[2048];
va_list args;
va_start(args, fmt);
VsprintfLiteral(buf, fmt, args);
va_end(args);
OutputDebugStringA(buf);
}
#endif // defined(XP_WIN)
/**
* printf_stderr(...) is much like fprintf(stderr, ...), except that:
* - on Android and Firefox OS, *instead* of printing to stderr, it
* prints to logcat. (Newlines in the string lead to multiple lines
* of logcat, but each function call implicitly completes a line even
* if the string does not end with a newline.)
* - on Windows, if a debugger is present, it calls OutputDebugString
* in *addition* to writing to stderr
*/
MFBT_API void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2);
// stderr is unbuffered by default so we open a new FILE (which is buffered)
// so that calls to printf_stderr are not as likely to get mixed together.
int fd = _fileno(stderr);
if (fd == -2) return;
/**
* Same as printf_stderr, but taking va_list instead of varargs
*/
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs)
MOZ_FORMAT_PRINTF(1, 0);
FILE* fp = _fdopen(_dup(fd), "a");
if (!fp) return;
/**
* fprintf_stderr is like fprintf, except that if its file argument
* is stderr, it invokes printf_stderr instead.
*
* This is useful for general debugging code that logs information to a
* file, but that you would like to be useful on Android and Firefox OS.
* If you use fprintf_stderr instead of fprintf in such debugging code,
* then callers can pass stderr to get logging that works on Android and
* Firefox OS (and also the other side-effects of using printf_stderr).
*
* Code that is structured this way needs to be careful not to split a
* line of output across multiple calls to fprintf_stderr, since doing
* so will cause it to appear in multiple lines in logcat output.
* (Producing multiple lines at once is fine.)
*/
MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...)
MOZ_FORMAT_PRINTF(2, 3);
va_list args;
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fclose(fp);
}
/*
* print_stderr and fprint_stderr are like printf_stderr and fprintf_stderr,
* except they deal with Android logcat line length limitations. They do this
* by printing individual lines out of the provided stringstream using separate
* calls to logcat.
*/
MFBT_API void print_stderr(std::stringstream& aStr);
MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr);
#ifdef __cplusplus
}

Просмотреть файл

@ -43,6 +43,7 @@ if CONFIG["OS_ARCH"] == "WINNT":
SOURCES += [
"AutoProfilerLabel.cpp",
"AwakeTimeStamp.cpp",
"Debug.cpp",
"MmapFaultHandler.cpp",
"Printf.cpp",
"SIMD.cpp",

Просмотреть файл

@ -19,11 +19,6 @@
#ifdef XP_WIN
# include <io.h>
# include <windows.h>
# include "mozilla/UniquePtr.h"
#endif
#ifdef ANDROID
# include <android/log.h>
#endif
#ifdef FUZZING_SNAPSHOT
@ -229,105 +224,3 @@ void NS_MakeRandomString(char* aBuf, int32_t aBufLen) {
}
#endif
#ifndef ANDROID
void vprintf_stderr_buffered(const char* aFmt, va_list aArgs) {
// Avoid interleaving by writing to an on-stack buffer and then writing in one
// go with fputs, as long as the output fits into the buffer.
char buffer[1024];
va_list argsCpy;
va_copy(argsCpy, aArgs);
int n = VsprintfLiteral(buffer, aFmt, aArgs);
if (n < sizeof(buffer)) {
fputs(buffer, stderr);
} else {
// Message too long for buffer. Just print it, not worrying about
// interleaving. (We could malloc, but the underlying write() syscall could
// get interleaved if the output is too big anyway.)
vfprintf(stderr, aFmt, argsCpy);
}
va_end(argsCpy);
fflush(stderr);
}
#endif
#if defined(XP_WIN)
void vprintf_stderr(const char* aFmt, va_list aArgs) {
if (IsDebuggerPresent()) {
int lengthNeeded = _vscprintf(aFmt, aArgs);
if (lengthNeeded) {
lengthNeeded++;
auto buf = MakeUnique<char[]>(lengthNeeded);
if (buf) {
va_list argsCpy;
va_copy(argsCpy, aArgs);
vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy);
buf[lengthNeeded - 1] = '\0';
va_end(argsCpy);
OutputDebugStringA(buf.get());
}
}
}
vprintf_stderr_buffered(aFmt, aArgs);
}
#elif defined(ANDROID)
void vprintf_stderr(const char* aFmt, va_list aArgs) {
__android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs);
}
#elif defined(FUZZING_SNAPSHOT)
void vprintf_stderr(const char* aFmt, va_list aArgs) {
if (nyx_puts) {
auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs);
nyx_puts(msgbuf.get());
} else {
vprintf_stderr_buffered(aFmt, aArgs);
}
}
#else
void vprintf_stderr(const char* aFmt, va_list aArgs) {
vprintf_stderr_buffered(aFmt, aArgs);
}
#endif
void printf_stderr(const char* aFmt, ...) {
va_list args;
va_start(args, aFmt);
vprintf_stderr(aFmt, args);
va_end(args);
}
void fprintf_stderr(FILE* aFile, const char* aFmt, ...) {
va_list args;
va_start(args, aFmt);
if (aFile == stderr) {
vprintf_stderr(aFmt, args);
} else {
vfprintf(aFile, aFmt, args);
}
va_end(args);
}
void print_stderr(std::stringstream& aStr) {
#if defined(ANDROID)
// On Android logcat output is truncated to 1024 chars per line, and
// we usually use std::stringstream to build up giant multi-line gobs
// of output. So to avoid the truncation we find the newlines and
// print the lines individually.
std::string line;
while (std::getline(aStr, line)) {
printf_stderr("%s\n", line.c_str());
}
#else
printf_stderr("%s", aStr.str().c_str());
#endif
}
void fprint_stderr(FILE* aFile, std::stringstream& aStr) {
if (aFile == stderr) {
print_stderr(aStr);
} else {
fprintf_stderr(aFile, "%s", aStr.str().c_str());
}
}

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsXPCOM.h"
#include "mozilla/Assertions.h"
#include "mozilla/glue/Debug.h"
#include "mozilla/DbgMacro.h"
#include "mozilla/Likely.h"
#include <stdarg.h>
@ -326,59 +327,4 @@ void NS_ABORT_OOM(size_t aSize);
inline void NS_ABORT_OOM(size_t) { MOZ_CRASH(); }
#endif
/* When compiling the XPCOM Glue on Windows, we pretend that it's going to
* be linked with a static CRT (-MT) even when it's not. This means that we
* cannot link to data exports from the CRT, only function exports. So,
* instead of referencing "stderr" directly, use fdopen.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* printf_stderr(...) is much like fprintf(stderr, ...), except that:
* - on Android and Firefox OS, *instead* of printing to stderr, it
* prints to logcat. (Newlines in the string lead to multiple lines
* of logcat, but each function call implicitly completes a line even
* if the string does not end with a newline.)
* - on Windows, if a debugger is present, it calls OutputDebugString
* in *addition* to writing to stderr
*/
void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2);
/**
* Same as printf_stderr, but taking va_list instead of varargs
*/
void vprintf_stderr(const char* aFmt, va_list aArgs) MOZ_FORMAT_PRINTF(1, 0);
/**
* fprintf_stderr is like fprintf, except that if its file argument
* is stderr, it invokes printf_stderr instead.
*
* This is useful for general debugging code that logs information to a
* file, but that you would like to be useful on Android and Firefox OS.
* If you use fprintf_stderr instead of fprintf in such debugging code,
* then callers can pass stderr to get logging that works on Android and
* Firefox OS (and also the other side-effects of using printf_stderr).
*
* Code that is structured this way needs to be careful not to split a
* line of output across multiple calls to fprintf_stderr, since doing
* so will cause it to appear in multiple lines in logcat output.
* (Producing multiple lines at once is fine.)
*/
void fprintf_stderr(FILE* aFile, const char* aFmt, ...) MOZ_FORMAT_PRINTF(2, 3);
/*
* print_stderr and fprint_stderr are like printf_stderr and fprintf_stderr,
* except they deal with Android logcat line length limitations. They do this
* by printing individual lines out of the provided stringstream using separate
* calls to logcat.
*/
void print_stderr(std::stringstream& aStr);
void fprint_stderr(FILE* aFile, std::stringstream& aStr);
#ifdef __cplusplus
}
#endif
#endif /* nsDebug_h___ */