win: get tools/crashpad_database_util mostly working

- Add public domain getopt implementation to third_party.
- Add timegm to compat/win.
- Add stub of strptime to compat/win.

Requires https://codereview.chromium.org/1119173003/ and
https://codereview.chromium.org/1117013006/.

Rather than working in wchar_t everywhere on Windows, convert
UTF16 command line arguments in wmain to UTF8, work primarily
in UTF8, and convert back when necessary to UTF16 for base::FilePath.
This avoids the need to genericize over all the standard C string
functions, getopt, etc. while still handling non-ASCII properly.

R=mark@chromium.org
BUG=crashpad:1

Review URL: https://codereview.chromium.org/1119783005
This commit is contained in:
Scott Graham 2015-05-06 10:28:07 -07:00
parent 720882cc14
commit 17b770ece4
15 changed files with 746 additions and 62 deletions

2
DEPS
View File

@ -28,7 +28,7 @@ deps = {
'32ca1cd8e010d013a606a752fb49a603a3598071', # svn r2015
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'91ea4908ffd74d9c886bd2f8ccbfae6d31c499af',
'bf64e609259be3faf24e32aa899491f22fa1fb90',
}
hooks = [

View File

@ -563,6 +563,9 @@ bool CrashReportDatabaseWin::Initialize() {
// TODO(scottmg): When are completed reports pruned from disk? Delete here or
// maybe on AcquireMetadata().
if (!settings_.Initialize())
return false;
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}

View File

@ -35,7 +35,10 @@
'non_win/verrsrc.h',
'non_win/windows.h',
'non_win/winnt.h',
'win/getopt.h',
'win/sys/types.h',
'win/time.cc',
'win/time.h',
'win/winnt.h',
],
'conditions': [
@ -61,6 +64,9 @@
'win',
],
},
'dependencies': [
'../third_party/getopt/getopt.gyp:getopt',
],
}, {
'include_dirs': [
'non_win',

20
compat/win/getopt.h Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_COMPAT_WIN_GETOPT_H_
#define CRASHPAD_COMPAT_WIN_GETOPT_H_
#include "third_party/getopt/getopt.h"
#endif // CRASHPAD_COMPAT_WIN_GETOPT_H_

40
compat/win/time.cc Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <time.h>
extern "C" {
struct tm* gmtime_r(const time_t* timep, struct tm* result) {
if (gmtime_s(result, timep) != 0)
return nullptr;
return result;
}
struct tm* localtime_r(const time_t* timep, struct tm* result) {
if (localtime_s(result, timep) != 0)
return nullptr;
return result;
}
const char* strptime(const char* buf, const char* format, struct tm* tm) {
// TODO(scottmg): strptime implementation.
return nullptr;
}
time_t timegm(struct tm* tm) {
return _mkgmtime(tm);
}
} // extern "C"

36
compat/win/time.h Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_COMPAT_WIN_TIME_H_
#define CRASHPAD_COMPAT_WIN_TIME_H_
#include <../include/time.h>
#ifdef __cplusplus
extern "C" {
#endif
struct tm* gmtime_r(const time_t* timep, struct tm* result);
struct tm* localtime_r(const time_t* timep, struct tm* result);
const char* strptime(const char* buf, const char* format, struct tm* tm);
time_t timegm(struct tm* tm);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // CRASHPAD_COMPAT_WIN_TIME_H_

5
third_party/getopt/LICENSE vendored Normal file
View File

@ -0,0 +1,5 @@
Copyright (C) 1997 Gregory Pietsch
[These files] are hereby placed in the public domain without restrictions. Just
give the author credit, don't claim you wrote it or prevent anyone else from
using it.

12
third_party/getopt/README.crashpad vendored Normal file
View File

@ -0,0 +1,12 @@
Name: Gregory Pietsch getopt
Short Name: getop
URL: https://sourceware.org/ml/newlib/2005/msg00758.html
License: Public domain
License File: LICENSE
Security Critical: no
Description:
A public domain implementation of getopt.
Local Modifications:
Minor compilation fixes applied for Windows.

410
third_party/getopt/getopt.c vendored Normal file
View File

@ -0,0 +1,410 @@
/****************************************************************************
getopt.c - Read command line options
AUTHOR: Gregory Pietsch
CREATED Fri Jan 10 21:13:05 1997
DESCRIPTION:
The getopt() function parses the command line arguments. Its arguments argc
and argv are the argument count and array as passed to the main() function
on program invocation. The argument optstring is a list of available option
characters. If such a character is followed by a colon (`:'), the option
takes an argument, which is placed in optarg. If such a character is
followed by two colons, the option takes an optional argument, which is
placed in optarg. If the option does not take an argument, optarg is NULL.
The external variable optind is the index of the next array element of argv
to be processed; it communicates from one call to the next which element to
process.
The getopt_long() function works like getopt() except that it also accepts
long options started by two dashes `--'. If these take values, it is either
in the form
--arg=value
or
--arg value
It takes the additional arguments longopts which is a pointer to the first
element of an array of type GETOPT_LONG_OPTION_T. The last element of the
array has to be filled with NULL for the name field.
The longind pointer points to the index of the current long option relative
to longopts if it is non-NULL.
The getopt() function returns the option character if the option was found
successfully, `:' if there was a missing parameter for one of the options,
`?' for an unknown option character, and EOF for the end of the option list.
The getopt_long() function's return value is described in the header file.
The function getopt_long_only() is identical to getopt_long(), except that a
plus sign `+' can introduce long options as well as `--'.
The following describes how to deal with options that follow non-option
argv-elements.
If the caller did not specify anything, the default is REQUIRE_ORDER if the
environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options; stop option processing
when the first non-option is seen. This is what Unix does. This mode of
operation is selected by either setting the environment variable
POSIXLY_CORRECT, or using `+' as the first character of the optstring
parameter.
PERMUTE is the default. We permute the contents of ARGV as we scan, so that
eventually all the non-options are at the end. This allows options to be
given in any order, even with programs that were not written to expect this.
RETURN_IN_ORDER is an option available to programs that were written to
expect options and other argv-elements in any order and that care about the
ordering of the two. We describe each non-option argv-element as if it were
the argument of an option with character code 1. Using `-' as the first
character of the optstring parameter selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless of the
value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
getopt() and friends to return EOF with optind != argc.
COPYRIGHT NOTICE AND DISCLAIMER:
Copyright (C) 1997 Gregory Pietsch
This file and the accompanying getopt.h header file are hereby placed in the
public domain without restrictions. Just give the author credit, don't
claim you wrote it or prevent anyone else from using it.
Gregory Pietsch's current e-mail address:
gpietsch@comcast.net
****************************************************************************/
/* include files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef GETOPT_H
#include "getopt.h"
#endif
/* macros */
/* types */
typedef enum GETOPT_ORDERING_T
{
PERMUTE,
RETURN_IN_ORDER,
REQUIRE_ORDER
} GETOPT_ORDERING_T;
/* globally-defined variables */
char *optarg = NULL;
int optind = 0;
int opterr = 1;
int optopt = '?';
/* functions */
/* reverse_argv_elements: reverses num elements starting at argv */
static void
reverse_argv_elements (char **argv, int num)
{
int i;
char *tmp;
for (i = 0; i < (num >> 1); i++)
{
tmp = argv[i];
argv[i] = argv[num - i - 1];
argv[num - i - 1] = tmp;
}
}
/* permute: swap two blocks of argv-elements given their lengths */
static void
permute (char **argv, int len1, int len2)
{
reverse_argv_elements (argv, len1);
reverse_argv_elements (argv, len1 + len2);
reverse_argv_elements (argv, len2);
}
/* is_option: is this argv-element an option or the end of the option list? */
static int
is_option (char *argv_element, int only)
{
return ((argv_element == NULL)
|| (argv_element[0] == '-') || (only && argv_element[0] == '+'));
}
/* getopt_internal: the function that does all the dirty work */
static int
getopt_internal (int argc, char **argv, char *shortopts,
GETOPT_LONG_OPTION_T * longopts, int *longind, int only)
{
GETOPT_ORDERING_T ordering = PERMUTE;
static size_t optwhere = 0;
size_t permute_from = 0;
int num_nonopts = 0;
int optindex = 0;
size_t match_chars = 0;
char *possible_arg = NULL;
int longopt_match = -1;
int has_arg = -1;
char *cp = NULL;
int arg_next = 0;
/* first, deal with silly parameters and easy stuff */
if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
return (optopt = '?');
if (optind >= argc || argv[optind] == NULL)
return EOF;
if (strcmp (argv[optind], "--") == 0)
{
optind++;
return EOF;
}
/* if this is our first time through */
if (optind == 0) {
optind = 1;
optwhere = 1;
}
/* define ordering */
if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+'))
{
ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
shortopts++;
}
else
ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
/*
* based on ordering, find our next option, if we're at the beginning of
* one
*/
if (optwhere == 1)
{
switch (ordering)
{
case PERMUTE:
permute_from = optind;
num_nonopts = 0;
while (!is_option (argv[optind], only))
{
optind++;
num_nonopts++;
}
if (argv[optind] == NULL)
{
/* no more options */
optind = (int)permute_from;
return EOF;
}
else if (strcmp (argv[optind], "--") == 0)
{
/* no more options, but have to get `--' out of the way */
permute (argv + permute_from, num_nonopts, 1);
optind = (int)(permute_from + 1);
return EOF;
}
break;
case RETURN_IN_ORDER:
if (!is_option (argv[optind], only))
{
optarg = argv[optind++];
return (optopt = 1);
}
break;
case REQUIRE_ORDER:
if (!is_option (argv[optind], only))
return EOF;
break;
}
}
/* we've got an option, so parse it */
/* first, is it a long option? */
if (longopts != NULL
&& (memcmp (argv[optind], "--", 2) == 0
|| (only && argv[optind][0] == '+')) && optwhere == 1)
{
/* handle long options */
if (memcmp (argv[optind], "--", 2) == 0)
optwhere = 2;
longopt_match = -1;
possible_arg = strchr (argv[optind] + optwhere, '=');
if (possible_arg == NULL)
{
/* no =, so next argv might be arg */
match_chars = strlen (argv[optind]);
possible_arg = argv[optind] + match_chars;
match_chars = match_chars - optwhere;
}
else
match_chars = (possible_arg - argv[optind]) - optwhere;
for (optindex = 0; longopts[optindex].name != NULL; optindex++)
{
if (memcmp (argv[optind] + optwhere,
longopts[optindex].name, match_chars) == 0)
{
/* do we have an exact match? */
if (match_chars == strlen (longopts[optindex].name))
{
longopt_match = optindex;
break;
}
/* do any characters match? */
else
{
if (longopt_match < 0)
longopt_match = optindex;
else
{
/* we have ambiguous options */
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous "
"(could be `--%s' or `--%s')\n",
argv[0],
argv[optind],
longopts[longopt_match].name,
longopts[optindex].name);
return (optopt = '?');
}
}
}
}
if (longopt_match >= 0)
has_arg = longopts[longopt_match].has_arg;
}
/* if we didn't find a long option, is it a short option? */
if (longopt_match < 0 && shortopts != NULL)
{
cp = strchr (shortopts, argv[optind][optwhere]);
if (cp == NULL)
{
/* couldn't find option in shortopts */
if (opterr)
fprintf (stderr,
"%s: invalid option -- `-%c'\n",
argv[0], argv[optind][optwhere]);
optwhere++;
if (argv[optind][optwhere] == '\0')
{
optind++;
optwhere = 1;
}
return (optopt = '?');
}
has_arg = ((cp[1] == ':')
? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argument);
possible_arg = argv[optind] + optwhere + 1;
optopt = *cp;
}
/* get argument and reset optwhere */
arg_next = 0;
switch (has_arg)
{
case OPTIONAL_ARG:
if (*possible_arg == '=')
possible_arg++;
if (*possible_arg != '\0')
{
optarg = possible_arg;
optwhere = 1;
}
else
optarg = NULL;
break;
case required_argument:
if (*possible_arg == '=')
possible_arg++;
if (*possible_arg != '\0')
{
optarg = possible_arg;
optwhere = 1;
}
else if (optind + 1 >= argc)
{
if (opterr)
{
fprintf (stderr, "%s: argument required for option `", argv[0]);
if (longopt_match >= 0)
fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
else
fprintf (stderr, "-%c'\n", *cp);
}
optind++;
return (optopt = ':');
}
else
{
optarg = argv[optind + 1];
arg_next = 1;
optwhere = 1;
}
break;
case no_argument:
if (longopt_match < 0)
{
optwhere++;
if (argv[optind][optwhere] == '\0')
optwhere = 1;
}
else
optwhere = 1;
optarg = NULL;
break;
}
/* do we have to permute or otherwise modify optind? */
if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0)
{
permute (argv + permute_from, num_nonopts, 1 + arg_next);
optind = (int)(permute_from + 1 + arg_next);
}
else if (optwhere == 1)
optind = optind + 1 + arg_next;
/* finally return */
if (longopt_match >= 0)
{
if (longind != NULL)
*longind = longopt_match;
if (longopts[longopt_match].flag != NULL)
{
*(longopts[longopt_match].flag) = longopts[longopt_match].val;
return 0;
}
else
return longopts[longopt_match].val;
}
else
return optopt;
}
int
getopt (int argc, char **argv, char *optstring)
{
return getopt_internal (argc, argv, optstring, NULL, NULL, 0);
}
int
getopt_long (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind)
{
return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 0);
}
int
getopt_long_only (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind)
{
return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 1);
}
/* end of file GETOPT.C */

35
third_party/getopt/getopt.gyp vendored Normal file
View File

@ -0,0 +1,35 @@
# Copyright 2015 The Crashpad Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
{
'includes': [
'../../build/crashpad.gypi',
],
'conditions': [
['OS=="win"', {
'targets': [
{
'target_name': 'getopt',
'type': 'static_library',
'sources': [
'getopt.c',
'getopt.h',
],
},
],
}, {
'targets': []
}]
],
}

55
third_party/getopt/getopt.h vendored Normal file
View File

@ -0,0 +1,55 @@
#ifndef GETOPT_H
#define GETOPT_H
/* include files needed by this include file */
/* macros defined by this include file */
#define no_argument 0
#define required_argument 1
#define OPTIONAL_ARG 2
/* types defined by this include file */
/* GETOPT_LONG_OPTION_T: The type of long option */
typedef struct GETOPT_LONG_OPTION_T
{
const char *name; /* the name of the long option */
int has_arg; /* one of the above macros */
int *flag; /* determines if getopt_long() returns a
* value for a long option; if it is
* non-NULL, 0 is returned as a function
* value and the value of val is stored in
* the area pointed to by flag. Otherwise,
* val is returned. */
int val; /* determines the value to return if flag is
* NULL. */
} GETOPT_LONG_OPTION_T;
typedef GETOPT_LONG_OPTION_T option;
#ifdef __cplusplus
extern "C"
{
#endif
/* externally-defined variables */
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
/* function prototypes */
int getopt (int argc, char **argv, char *optstring);
int getopt_long (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind);
int getopt_long_only (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind);
#ifdef __cplusplus
};
#endif
#endif /* GETOPT_H */
/* END OF FILE getopt.h */

View File

@ -14,7 +14,6 @@
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -25,10 +24,13 @@
#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "client/crash_report_database.h"
#include "client/settings.h"
#include "tools/tool_support.h"
@ -36,12 +38,22 @@
#include "util/file/file_reader.h"
#include "util/misc/uuid.h"
#if defined(OS_POSIX)
base::FilePath::StringType UTF8ToFilePathStringType(const char* path) {
return path;
}
#elif defined(OS_WIN)
base::FilePath::StringType UTF8ToFilePathStringType(const char* path) {
return base::UTF8ToUTF16(path);
}
#endif
namespace crashpad {
namespace {
void Usage(const std::string& me) {
void Usage(const base::FilePath& me) {
fprintf(stderr,
"Usage: %s [OPTION]... PID\n"
"Usage: %" PRFilePath " [OPTION]... PID\n"
"Operate on Crashpad crash report databases.\n"
"\n"
" -d, --database=PATH operate on the crash report database at PATH\n"
@ -60,7 +72,7 @@ void Usage(const std::string& me) {
" --utc show and set UTC times instead of local\n"
" --help display this help and exit\n"
" --version output version information and exit\n",
me.c_str());
me.value().c_str());
ToolSupport::UsageTail(me);
}
@ -104,14 +116,14 @@ bool StringToBool(const char* string, bool* boolean) {
};
for (size_t index = 0; index < arraysize(kFalseWords); ++index) {
if (strcasecmp(string, kFalseWords[index]) == 0) {
if (base::strcasecmp(string, kFalseWords[index]) == 0) {
*boolean = false;
return true;
}
}
for (size_t index = 0; index < arraysize(kTrueWords); ++index) {
if (strcasecmp(string, kTrueWords[index]) == 0) {
if (base::strcasecmp(string, kTrueWords[index]) == 0) {
*boolean = true;
return true;
}
@ -133,7 +145,7 @@ std::string BoolToString(bool boolean) {
// when true, causes |string| to be interpreted as a UTC time rather than a
// local time when the time zone is ambiguous.
bool StringToTime(const char* string, time_t* time, bool utc) {
if (strcasecmp(string, "never") == 0) {
if (base::strcasecmp(string, "never") == 0) {
*time = 0;
return true;
}
@ -153,7 +165,7 @@ bool StringToTime(const char* string, time_t* time, bool utc) {
if (utc) {
*time = timegm(&time_tm);
} else {
*time = timelocal(&time_tm);
*time = mktime(&time_tm);
}
return true;
@ -172,7 +184,7 @@ bool StringToTime(const char* string, time_t* time, bool utc) {
return false;
}
// Converst |time_tt| to a string, and returns it. |utc| determines whether the
// Converts |time_tt| to a string, and returns it. |utc| determines whether the
// converted time will reference local time or UTC. If |time_tt| is 0, the
// string "never" will be returned as a special case.
std::string TimeToString(time_t time_tt, bool utc) {
@ -203,7 +215,9 @@ void ShowReport(const CrashReportDatabase::Report& report,
bool utc) {
std::string spaces(space_count, ' ');
printf("%sPath: %s\n", spaces.c_str(), report.file_path.value().c_str());
printf("%sPath: %" PRFilePath "\n",
spaces.c_str(),
report.file_path.value().c_str());
if (!report.id.empty()) {
printf("%sRemote ID: %s\n", spaces.c_str(), report.id.c_str());
}
@ -239,7 +253,8 @@ void ShowReports(const std::vector<CrashReportDatabase::Report>& reports,
}
int DatabaseUtilMain(int argc, char* argv[]) {
const std::string me(basename(argv[0]));
const base::FilePath me(
base::FilePath(UTF8ToFilePathStringType(argv[0])).BaseName());
enum OptionFlags {
// “Short” (single-character) options.
@ -349,7 +364,8 @@ int DatabaseUtilMain(int argc, char* argv[]) {
break;
}
case kOptionNewReport: {
options.new_report_paths.push_back(base::FilePath(optarg));
options.new_report_paths.push_back(
base::FilePath(UTF8ToFilePathStringType(optarg)));
break;
}
case kOptionUTC: {
@ -408,8 +424,8 @@ int DatabaseUtilMain(int argc, char* argv[]) {
return EXIT_FAILURE;
}
scoped_ptr<CrashReportDatabase> database(
CrashReportDatabase::Initialize(base::FilePath(options.database)));
scoped_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize(
base::FilePath(UTF8ToFilePathStringType(options.database))));
if (!database) {
return EXIT_FAILURE;
}
@ -453,7 +469,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
printf("%s%s (%ld)\n",
prefix,
TimeToString(last_upload_attempt_time, options.utc).c_str(),
implicit_cast<long>(last_upload_attempt_time));
static_cast<long>(last_upload_attempt_time));
}
if (options.show_pending_reports) {
@ -497,7 +513,8 @@ int DatabaseUtilMain(int argc, char* argv[]) {
// If only asked to do one thing, a failure to find the single requested
// report should result in a failure exit status.
if (show_operations + set_operations == 1) {
fprintf(stderr, "%s: Report not found\n", me.c_str());
fprintf(
stderr, "%" PRFilePath ": Report not found\n", me.value().c_str());
return EXIT_FAILURE;
}
printf("Report %s not found\n", uuid.ToString().c_str());
@ -562,6 +579,19 @@ int DatabaseUtilMain(int argc, char* argv[]) {
} // namespace
} // namespace crashpad
#if defined(OS_POSIX)
int main(int argc, char* argv[]) {
return crashpad::DatabaseUtilMain(argc, argv);
}
#elif defined(OS_WIN)
int wmain(int argc, wchar_t* argv[]) {
scoped_ptr<char*[]> argv_as_utf8(new char*[argc]);
std::vector<std::string> storage;
storage.reserve(argc);
for (int i = 0; i < argc; ++i) {
storage.push_back(base::UTF16ToUTF8(argv[i]));
argv_as_utf8[i] = &storage[i][0];
}
return crashpad::DatabaseUtilMain(argc, argv_as_utf8.get());
}
#endif // OS_POSIX

View File

@ -21,31 +21,50 @@
namespace crashpad {
// static
void ToolSupport::Version(const std::string& me) {
void ToolSupport::Version(const base::FilePath& me) {
fprintf(stderr,
"%s (%s) %s\n%s\n",
me.c_str(),
"%s" PRFilePath " (%s) %s\n%s\n",
me.value().c_str(),
PACKAGE_NAME,
PACKAGE_VERSION,
PACKAGE_COPYRIGHT);
}
// static
void ToolSupport::UsageTail(const std::string& me) {
void ToolSupport::UsageTail(const base::FilePath& me) {
fprintf(stderr,
"\nReport %s bugs to\n%s\n%s home page: <%s>\n",
me.c_str(),
"\nReport %" PRFilePath " bugs to\n%s\n%s home page: <%s>\n",
me.value().c_str(),
PACKAGE_BUGREPORT,
PACKAGE_NAME,
PACKAGE_URL);
}
// static
void ToolSupport::UsageHint(const std::string& me, const char* hint) {
void ToolSupport::UsageHint(const base::FilePath& me, const char* hint) {
if (hint) {
fprintf(stderr, "%s: %s\n", me.c_str(), hint);
fprintf(stderr, "%" PRFilePath ": %s\n", me.value().c_str(), hint);
}
fprintf(stderr, "Try '%s --help' for more information.\n", me.c_str());
fprintf(stderr,
"Try '%" PRFilePath " --help' for more information.\n",
me.value().c_str());
}
#if defined(OS_POSIX)
// static
void ToolSupport::Version(const std::string& me) {
Version(base::FilePath(me));
}
// static
void ToolSupport::UsageTail(const std::string& me) {
UsageTail(base::FilePath(me));
}
// static
void ToolSupport::UsageHint(const std::string& me, const char* hint) {
UsageHint(base::FilePath(me), hint);
}
#endif // OS_POSIX
} // namespace crashpad

View File

@ -18,6 +18,8 @@
#include <string>
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "build/build_config.h"
namespace crashpad {
@ -27,18 +29,29 @@ class ToolSupport {
//! \brief Handles `--version`.
//!
//! \param[in] me The tools name, the basename of `argv[0]`.
static void Version(const std::string& me);
static void Version(const base::FilePath& me);
//! \brief Prints the footer for `--help`.
//!
//! \param[in] me The tools name, the basename of `argv[0]`.
static void UsageTail(const std::string& me);
static void UsageTail(const base::FilePath& me);
//! \brief Suggests using `--help` when a command line tool cant make sense
//! of its arguments.
//!
//! \param[in] me The tools name, the basename of `argv[0]`.
static void UsageHint(const base::FilePath& me, const char* hint);
#if defined(OS_POSIX) || DOXYGEN
//! \copydoc Version
static void Version(const std::string& me);
//! \copydoc UsageTail
static void UsageTail(const std::string& me);
//! \copydoc UsageHint
static void UsageHint(const std::string& me, const char* hint);
#endif // OS_POSIX
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ToolSupport);

View File

@ -16,34 +16,6 @@
'includes': [
'../build/crashpad.gypi',
],
'conditions': [
['OS=="mac"', {
'variables': {
# Programs that use task_for_pid() can indicate to taskgated(8) in their
# Info.plist that they are allowed to call that function. In order for
# this to work, the programs in question must be signed by an authority
# trusted by the system. Signing is beyond the scope of the build, but
# the key to make this work is placed in Info.plist to enable the
# desired behavior once the tools that require this access are signed.
#
# The tools built here are flat-file executables, and are not bundled.
# To have an Info.plist, they must have a special __TEXT,__info_plist
# section. This section is created at link time.
#
# The Info.plist for this purpose is mac/sectaskaccess_info.plist and is
# referenced by OTHER_LDFLAGS. ninja runs the link step from the output
# directory such as out/Release, and requires a relative path from that
# directory. Xcode runs the link step from the directory of the
# .xcodeproj, which is the directory of the .gyp file.
'conditions': [
['GENERATOR=="ninja"', {
'sectaskaccess_info_plist': '<!(pwd)/mac/sectaskaccess_info.plist',
}, { # else: GENERATOR!="ninja"
'sectaskaccess_info_plist': 'mac/sectaskaccess_info.plist',
}],
],
},
'targets': [
{
'target_name': 'crashpad_tool_support',
@ -76,6 +48,36 @@
'crashpad_database_util.cc',
],
},
],
'conditions': [
['OS=="mac"', {
'variables': {
# Programs that use task_for_pid() can indicate to taskgated(8) in their
# Info.plist that they are allowed to call that function. In order for
# this to work, the programs in question must be signed by an authority
# trusted by the system. Signing is beyond the scope of the build, but
# the key to make this work is placed in Info.plist to enable the
# desired behavior once the tools that require this access are signed.
#
# The tools built here are flat-file executables, and are not bundled.
# To have an Info.plist, they must have a special __TEXT,__info_plist
# section. This section is created at link time.
#
# The Info.plist for this purpose is mac/sectaskaccess_info.plist and is
# referenced by OTHER_LDFLAGS. ninja runs the link step from the output
# directory such as out/Release, and requires a relative path from that
# directory. Xcode runs the link step from the directory of the
# .xcodeproj, which is the directory of the .gyp file.
'conditions': [
['GENERATOR=="ninja"', {
'sectaskaccess_info_plist': '<!(pwd)/mac/sectaskaccess_info.plist',
}, { # else: GENERATOR!="ninja"
'sectaskaccess_info_plist': 'mac/sectaskaccess_info.plist',
}],
],
},
'targets': [
{
'target_name': 'catch_exception_tool',
'type': 'executable',
@ -182,8 +184,6 @@
],
},
],
}, {
'targets': [],
}],
],
}