зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
938a635e60
Коммит
ba7d3327fc
|
@ -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)
|
||||
|
||||
|
|
|
@ -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___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче