From e4cad9e51483c81ae8c5871f48fdbc31912584b7 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 21 Mar 2017 23:25:14 -0400 Subject: [PATCH 1/9] =?UTF-8?q?doc:=20Standardize=20on=20=E2=80=9CmacOS?= =?UTF-8?q?=E2=80=9D=20in=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 952f787f4aab missed two occurrences that should have been updated. Change-Id: I425367689eb19edfd309a2210a79ed400e190673 Reviewed-on: https://chromium-review.googlesource.com/458116 Reviewed-by: Robert Sesek --- snapshot/mac/module_snapshot_mac.h | 2 +- snapshot/mac/system_snapshot_mac.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/snapshot/mac/module_snapshot_mac.h b/snapshot/mac/module_snapshot_mac.h index 23904a5e..16ad7e16 100644 --- a/snapshot/mac/module_snapshot_mac.h +++ b/snapshot/mac/module_snapshot_mac.h @@ -37,7 +37,7 @@ struct UUID; namespace internal { //! \brief A ModuleSnapshot of a code module (binary image) loaded into a -//! running (or crashed) process on a Mac OS X system. +//! running (or crashed) process on a macOS system. class ModuleSnapshotMac final : public ModuleSnapshot { public: ModuleSnapshotMac(); diff --git a/snapshot/mac/system_snapshot_mac.h b/snapshot/mac/system_snapshot_mac.h index 0f18a48d..2ac2ef90 100644 --- a/snapshot/mac/system_snapshot_mac.h +++ b/snapshot/mac/system_snapshot_mac.h @@ -29,8 +29,7 @@ class ProcessReader; namespace internal { -//! \brief A SystemSnapshot of the running system, when the system runs Mac OS -//! X. +//! \brief A SystemSnapshot of the running system, when the system runs macOS. class SystemSnapshotMac final : public SystemSnapshot { public: SystemSnapshotMac(); From c1157e87f164824c2216229a7a971dab349ce4fa Mon Sep 17 00:00:00 2001 From: Sigurdur Asgeirsson Date: Wed, 22 Mar 2017 14:45:11 -0400 Subject: [PATCH 2/9] Crashpad overview design doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4901025443885025bbf77f60b7c787f02eaadf60 Reviewed-on: https://chromium-review.googlesource.com/458259 Commit-Queue: Sigurður Ásgeirsson Reviewed-by: Mark Mentovai --- doc/layering.png | Bin 0 -> 23460 bytes doc/overview-design.md | 505 +++++++++++++++++++++++++++++++++++++++++ doc/overview.png | Bin 0 -> 26517 bytes 3 files changed, 505 insertions(+) create mode 100644 doc/layering.png create mode 100644 doc/overview-design.md create mode 100644 doc/overview.png diff --git a/doc/layering.png b/doc/layering.png new file mode 100644 index 0000000000000000000000000000000000000000..791bea5383d404e3bbfe08b0d1884e0e031e425d GIT binary patch literal 23460 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 literal 0 HcmV?d00001 diff --git a/doc/overview-design.md b/doc/overview-design.md new file mode 100644 index 00000000..ad871c18 --- /dev/null +++ b/doc/overview-design.md @@ -0,0 +1,505 @@ + + +# Crashpad Overview Design + +[TOC] + +## Objective + +Crashpad is a library for capturing, storing and transmitting postmortem crash +reports from a client to an upstream collection server. Crashpad aims to make it +possible for clients to capture process state at the time of crash with the best +possible fidelity and coverage, with the minimum of fuss. + +Crashpad also provides a facility for clients to capture dumps of process state +on-demand for diagnostic purposes. + +Crashpad additionally provides minimal facilities for clients to adorn their +crashes with application-specific metadata in the form of per-process key/value +pairs. More sophisticated clients are able to adorn crash reports further +through extensibility points that allow the embedder to augment the crash report +with application-specific metadata. + +## Background + +It’s an unfortunate truth that any large piece of software will contain bugs +that will cause it to occasionally crash. Even in the absence of bugs, software +incompatibilities can cause program instability. + +Fixing bugs and incompatibilities in client software that ships to millions of +users around the world is a daunting task. User reports and manual reproduction +of crashes can work, but even given a user report, often times the problem is +not readily reproducible. This is for various reasons, such as e.g. system +version or third-party software incompatibility, or the problem can happen due +to a race of some sort. Users are also unlikely to report problems they +encounter, and user reports are often of poor quality, as unfortunately most +users don’t have experience with making good bug reports. + +Automatic crash telemetry has been the best solution to the problem so far, as +this relieves the burden of manual reporting from users, while capturing the +hardware and software state at the time of crash. + +TODO(siggi): examples of this? + +Crash telemetry involves capturing postmortem crash dumps and transmitting them +to a backend collection server. On the server they can be stackwalked and +symbolized, and evaluated and aggregated in various ways. Stackwalking and +symbolizing the reports on an upstream server has several benefits over +performing these tasks on the client. High-fidelity stackwalking requires access +to bulky unwind data, and it may be desirable to not ship this to end users out +of concern for the application size. The process of symbolization requires +access to debugging symbols, which can be quite large, and the symbolization +process can consume considerable other resources. Transmitting un-stackwalked +and un-symbolized postmortem dumps to the collection server also allows deep +analysis of individual dumps, which is often necessary to resolve the bug +causing the crash. + +Transmitting reports to the collection server allows aggregating crashes by +cause, which in turn allows assessing the importance of different crashes in +terms of the occurrence rate and e.g. the potential security impact. + +A postmortem crash dump must contain the program state at the time of crash +with sufficient fidelity to allow diagnosing and fixing the problem. As the full +program state is usually too large to transmit to an upstream server, the +postmortem dump captures a heuristic subset of the full state. + +The crashed program is in an indeterminate state and, in fact, has often crashed +because of corrupt global state - such as heap. It’s therefore important to +generate crash reports with as little execution in the crashed process as +possible. Different operating systems vary in the facilities they provide for +this. + +## Overview + +Crashpad is a client-side library that focuses on capturing machine and program +state in a postmortem crash report, and transmitting this report to a backend +server - a “collection server”. The Crashpad library is embedded by the client +application. Conceptually, Crashpad breaks down into the handler and the client. +The handler runs in a separate process from the client or clients. It is +responsible for snapshotting the crashing client process’ state on a crash, +saving it to a crash dump, and transmitting the crash dump to an upstream +server. Clients register with the handler to allow it to capture and upload +their crashes. + +### The Crashpad handler + +The Crashpad handler is instantiated in a process supplied by the embedding +application. It provides means for clients to register themselves by some means +of IPC, or where operating system support is available, by taking advantage of +such support to cause crash notifications to be delivered to the handler. On +crash, the handler snapshots the crashed client process’ state, writes it to a +postmortem dump in a database, and may also transmit the dump to an upstream +server if so configured. + +The Crashpad handler is able to handle cross-bitted requests and generate crash +dumps across bitness, where e.g. the handler is a 64-bit process while the +client is a 32-bit process or vice versa. In the case of Windows, this is +limited by the OS such that a 32-bit handler can only generate crash dumps for +32-bit clients, but a 64-bit handler can acquire nearly all of the detail for a +32-bit process. + +### The Crashpad client + +The Crashpad client provides two main facilities. +1. Registration with the Crashpad handler. +2. Metadata communication to the Crashpad handler on crash. + +A Crashpad embedder links the Crashpad client library into one or more +executables, whether a loadable library or a program file. The client process +then registers with the Crashpad handler through some mode of IPC or other +operating system-specific support. + +On crash, metadata is communicated to the Crashpad handler via the CrashpadInfo +structure. Each client executable module linking the Crashpad client library +embeds a CrashpadInfo structure, which can be updated by the client with +whatever state the client wishes to record with a crash. + +![Overview image](overview.png) + +Here is an overview picture of the conceptual relationships between embedder (in +light blue), client modules (darker blue), and Crashpad (in green). Note that +multiple client modules can contain a CrashpadInfo structure, but only one +registration is necessary. + +## Detailed Design + +### Requirements + +The purpose of Crashpad is to capture machine, OS and application state in +sufficient detail and fidelity to allow developers to diagnose and, where +possible, fix the issue causing the crash. + +Each distinct crash report is assigned a globally unique ID, in order to allow +users to associate them with a user report, report in bug reports and so on. + +It’s critical to safeguard the user’s privacy by ensuring that no crash report +is ever uploaded without user consent. Likewise it’s important to ensure that +Crashpad never captures or uploads reports from non-client processes. + +### Concepts + +* **Client ID**. A UUID tied to a single instance of a Crashpad database. When + creating a crash report, the Crashpad handler includes the client ID stored + in the database. This provides a means to determine how many individual end + users are affected by a specific crash signature. + +* **Crash ID**. A UUID representing a single crash report. Uploaded crash + reports also receive a “server ID.” The Crashpad database indexes both the + locally-generated and server-generated IDs. + +* **Collection Server**. See [crash server documentation.]( + https://goto.google.com/crash-server-overview) + +* **Client Process**. Any process that has registered with a Crashpad handler. + +* **Handler process**. A process hosting the Crashpad handler library. This may + be a dedicated executable, or it may be hosted within a client executable + with control passed to it based on special signaling under the client’s + control, such as a command-line parameter. + +* **CrashpadInfo**. A structure used by client modules to provide information to + the handler. + +* **Annotations**. Each CrashpadInfo structure points to a dictionary of + {string, string} annotations that the client can use to communicate + application state in the case of crash. + +* **Database**. The Crashpad database contains persistent client settings as + well as crash dumps pending upload. + +TODO(siggi): moar concepts? + +### Overview Picture + +Here is a rough overview picture of the various Crashpad constructs, their +layering and intended use by clients. + +![Layering image](layering.png) + +Dark blue boxes are interfaces, light blue boxes are implementation. Gray is the +embedding client application. Note that wherever possible, implementation that +necessarily has to be OS-specific, exposes OS-agnostic interfaces to the rest of +Crashpad and the client. + +### Registration + +The particulars of how a client registers with the handler varies across +operating systems. + +#### macOS + +At registration time, the client designates a Mach port monitored by the +Crashpad handler as the EXC_CRASH exception port for the client. The port may be +acquired by launching a new handler process or by retrieving service already +registered with the system. The registration is maintained by the kernel and is +inherited by subprocesses at creation time by default, so only the topmost +process of a process tree need register. + +Crashpad provides a facility for a process to disassociate (unregister) with an +existing crash handler, which can be necessary when an older client spawns an +updated version. + +#### Windows + +There are two modes of registration on Windows. In both cases the handler is +advised of the address of a set of structures in the client process’ address +space. These structures include a pair of ExceptionInformation structs, one for +generating a postmortem dump for a crashing process, and another one for +generating a dump for a non- crashing process. + +##### Normal registration + +In the normal registration mode, the client connects to a named pipe by a +pre-arranged name. A registration request is written to the pipe. During +registration, the handler creates a set of events, duplicates them to the +registering client, then returns the handle values in the registration response. +This is a blocking process. + +##### Initial Handler Creation + +In order to avoid blocking client startup for the creation and initialization of +the handler, a different mode of registration can be used for the handler +creation. In this mode, the client creates a set of event handles and inherits +them into the newly created handler process. The handler process is advised of +the handle values and the location of the ExceptionInformation structures by way +of command line arguments in this mode. + +#### Linux/Android + +TODO(mmentovai): describe this. See this preliminary doc. + +### Capturing Exceptions + +The details of how Crashpad captures the exceptions leading to crashes varies +between operating systems. + +#### macOS + +On macOS, the operating system will notify the handler of client crashes via the +Mach port set as the client process’ exception port. As exceptions are +dispatched to the Mach port by the kernel, on macOS, exceptions can be handled +entirely from the Crashpad handler without the need to run any code in the crash +process at the time of the exception. + +#### Windows + +On Windows, the OS dispatches exceptions in the context of the crashing thread. +To notify the handler of exceptions, the Crashpad client registers an +UnhandledExceptionFilter (UEF) in the client process. When an exception trickles +up to the UEF, it stores the exception information and the crashing thread’s ID +in the ExceptionInformation structure registered with the handler. It then sets +an event handle to signal the handler to go ahead and process the exception. + +##### Caveats + +* If the crashing thread’s stack is smashed when an exception occurs, the + exception cannot be dispatched. In this case the OS will summarily terminate + the process, without the handler having an opportunity to generate a crash + report. +* If an exception is handled in the crashing thread, it will never propagate + to the UEF, and thus a crash report won’t be generated. This happens a fair + bit in Windows as system libraries will often dispatch callbacks under a + structured exception handler. This occurs during Window message dispatching + on some system configurations, as well as during e.g. DLL entry point + notifications. +* A growing number of conditions in the system and runtime exist where + detected corruption or illegal calls result in summary termination of the + process, in which case no crash report will be generated. + +###### Out-Of-Process Exception Handling + +There exists a mechanism in Windows Error Reporting (WER) that allows a client +process to register for handling client exceptions out of the crashing process. +Unfortunately this mechanism is difficult to use, and doesn’t provide coverage +for many of the caveats above. [Details +here.](https://crashpad.chromium.org/bug/133) + +#### Linux/Android + +TODO(mmentovai): describe this. See [this preliminary +doc.](https://goto.google.com/crashpad-android-dd) + +### The CrashpadInfo structure + +The CrashpadInfo structure is used to communicate information from the client to +the handler. Each executable module in a client process can contain a +CrashpadInfo structure. On a crash, the handler crawls all modules in the +crashing process to locate all CrashpadInfo structures present. The CrashpadInfo +structures are linked into a special, named section of the executable, where the +handler can readily find them. + +The CrashpadInfo structure has a magic signature, and contains a size and a +version field. The intent is to allow backwards compatibility from older client +modules to newer handler. It may also be necessary to provide forwards +compatibility from newer clients to older handler, though this hasn’t occurred +yet. + +The CrashpadInfo structure contains such properties as the cap for how much +memory to include in the crash dump, some tristate flags for controlling the +handler’s behavior, a pointer to an annotation dictionary and so on. + +### Snapshot + +Snapshot is a layer of interfaces that represent the machine and OS entities +that Crashpad cares about. Different concrete implementations of snapshot can +then be backed different ways, such as e.g. from the in-memory representation of +a crashed process, or e.g. from the contents of a minidump. + +### Crash Dump Creation + +To create a crash dump, a subset of the machine, OS and application state is +grabbed from the crashed process into an in-memory snapshot structure in the +handler process. Since the full application state is typically too large for +capturing to disk and transmitting to an upstream server, the snapshot contains +a heuristically selected subset of the full state. + +The precise details of what’s captured varies between operating systems, but +generally includes the following +* The set of modules (executable, shared libraries) that are loaded into the + crashing process. +* An enumeration of the threads running in the crashing process, including the + register contents and the contents of stack memory of each thread. +* A selection of the OS-related state of the process, such as e.g. the command + line, environment and so on. +* A selection of memory potentially referenced from registers and from stack. + +To capture a crash dump, the crashing process is first suspended, then a +snapshot is created in the handler process. The snapshot includes the +CrashpadInfo structures of the modules loaded into the process, and the contents +of those is used to control the level of detail captured for the crash dump. + +Once the snapshot has been constructed, it is then written to a minidump file, +which is added to the database. The process is un-suspended after the minidump +file has been written. In the case of a crash (as opposed to a client request to +produce a dump without crashing), it is then either killed by the operating +system or the Crashpad handler. + +In general the snapshotting process has to be very intimate with the operating +system it’s working with, so there will be a set of concrete implementation +classes, many deriving from the snapshot interfaces, doing this for each +operating system. + +### Minidump + +The minidump implementation is responsible for writing a snapshot to a +serialized on-disk file in the minidump format. The minidump implementation is +OS-agnostic, as it works on an OS-agnostic Snapshot interface. + +TODO(siggi): Talk about two-phase writes and contents ordering here. + +### Database + +The Crashpad database contains persistent client settings, including a unique +crash client identifier and the upload-enabled bit. Note that the crash client +identifier is assigned by Crashpad, and is distinct from any identifiers the +client application uses to identify users, installs, machines or such - if any. +The expectation is that the client application will manage the user’s upload +consent, and inform Crashpad of changes in consent. + +The unique client identifier is set at the time of database creation. It is then +recorded into every crash report collected by the handler and communicated to +the upstream server. + +The database stores a configurable number of recorded crash dumps to a +configurable maximum aggregate size. For each crash dump it stores annotations +relating to whether the crash dumps have been uploaded. For successfully +uploaded crash dumps it also stores their server-assigned ID. + +The database consists of a settings file, named "settings.dat" with binary +contents (see crashpad::Settings::Data for the file format), as well as +directory containing the crash dumps. Additionally each crash dump is adorned +with properties relating to the state of the dump for upload and such. The +details of how these properties are stored vary between platforms. + +#### macOS + +The macOS implementation simply stores database properties on the minidump files +in filesystem extended attributes. + +#### Windows + +The Windows implementation stores database properties in a binary file named +“metadata” at the top level of the database directory. + +### Report Format + +Crash reports are recorded in the Windows minidump format with +extensions to support Crashpad additions, such as e.g. Annotations. + +### Upload to collection server + +#### Wire Format + +For the time being, Crashpad uses the Breakpad wire protocol, which is +essentially a MIME multipart message communicated over HTTP(S). To support this, +the annotations from all the CrashpadInfo structures found in the crashing +process are merged to create the Breakpad “crash keys” as form data. The +postmortem minidump is then attached as an “application/octet- stream” +attachment with the name “upload_file_minidump”. The entirety of the request +body, including the minidump, can be gzip-compressed to reduce transmission time +and increase transmission reliability. Note that by convention there is a set of +“crash keys” that are used to communicate the product, version, client ID and +other relevant data about the client, to the server. Crashpad normally stores +these values in the minidump file itself, but retrieves them from the minidump +and supplies them as form data for compatibility with the Breakpad-style server. + +This is a temporary compatibility measure to allow the current Breakpad-based +upstream server to handle Crashpad reports. In the fullness of time, the wire +protocol is expected to change to remove this redundant transmission and +processing of the Annotations. + +#### Transport + +The embedding client controls the URL of the collection server by the command +line passed to the handler. The handler can upload crashes with HTTP or HTTPS, +depending on client’s preference. It’s strongly suggested use HTTPS transport +for crash uploads to protect the user’s privacy against man-in-the-middle +snoopers. + +TODO(mmentovai): Certificate pinning. + +#### Throttling & Retry Strategy + +To protect both the collection server from DDoS as well as to protect the +clients from unreasonable data transfer demands, the handler implements a +client-side throttling strategy. At the moment, the strategy is very simplistic, +it simply limits uploads to one upload per hour, and failed uploads are aborted. + +An experiment has been conducted to lift all throttling. Analysis on the +aggregate data this produced shows that multiple crashes within a short timespan +on the same client are nearly always due to the same cause. Therefore there is +very little loss of signal due to the throttling, though the ability to +reconstruct at least the full crash count is highly desirable. + +The lack of retry is expected to [change +soon](https://crashpad.chromium.org/bug/23), as this creates blind spots for +client crashes that exclusively occur on e.g. network down events, during +suspend and resume and such. + +### Extensibility + +Clients are able to extend the generated crash reports in two ways, by +manipulating their CrashpadInfo structure. +The two extensibility points are: +1. Nominating a set of address ranges for inclusion in the crash report. +2. Adding user-defined minidump streams for inclusion in the crash report. + +In both cases the CrashpadInfo structure has to be updated before a crash +occurs. + +### Dependencies + +Aside from system headers and APIs, when used outside of Chromium, Crashpad has +a dependency on “mini_chromium”, which is a subset of the Chromium base library. +This is to allow non-Chromium clients to use Crashpad, without taking a direct +dependency on the Chromium base, while allowing Chromium projects to use +Crashpad with minimum code duplication or hassle. When using Crashpad as part of +Chromium, Chromium’s own copy of the base library is used instead of +mini_chromium. + +The downside to this is that mini_chromium must be kept up to date with +interface and implementation changes in Chromium base, for the subset of +functionality used by Crashpad. + +## Caveats + +TODO(anyone): You may need to describe what you did not do or why simpler +approaches don't work. Mention other things to watch out for (if any). + +## Security Considerations + +Crashpad may be used to capture the state of sandboxed processes and it writes +minidumps to disk. It may therefore straddle security boundaries, so it’s +important that Crashpad handle all data it reads out of the crashed process with +extreme care. The Crashpad handler takes care to access client address spaces +through specially-designed accessors that check pointer validity and enforce +accesses within prescribed bounds. The flow of information into the Crashpad +handler is exclusively one-way: Crashpad never communicates anything back to +its clients, aside from providing single-bit indications of completion. + +## Privacy Considerations + +Crashpad may capture arbitrary contents from crashed process’ memory, including +user IDs and passwords, credit card information, URLs and whatever other content +users have trusted the crashing program with. The client program must acquire +and honor the user’s consent to upload crash reports, and appropriately manage +the upload state in Crashpad’s database. + +Crashpad must also be careful not to upload crashes for arbitrary processes on +the user’s system. To this end, Crashpad will never upload a process that hasn’t +registered with the handler, but note that registrations are inherited by child +processes on some operating systems. diff --git a/doc/overview.png b/doc/overview.png new file mode 100644 index 0000000000000000000000000000000000000000..78f849efffcf48b3887df080361592be7b4e0a5e GIT binary patch literal 26517 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 A%K!iX literal 0 HcmV?d00001 From af66c4b74028fcc43303eec3a7de9c4859414329 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 15:05:10 -0400 Subject: [PATCH 3/9] Add overview design doc link to root README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use an underscore instead of a hyphen in the overview design doc’s filename for consistency with the rest of the files in the repository. Change-Id: I15a76a00709a43dfec60e7f4f6ee64a3cd031b2c Reviewed-on: https://chromium-review.googlesource.com/458537 Reviewed-by: Sigurður Ásgeirsson --- README.md | 1 + doc/{overview-design.md => overview_design.md} | 0 2 files changed, 1 insertion(+) rename doc/{overview-design.md => overview_design.md} (100%) diff --git a/README.md b/README.md index 57e81695..914af349 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ limitations under the License. code, building, testing, and contributing to the project. * [Crashpad interface documentation](https://crashpad.chromium.org/doxygen/) * [Crashpad tool man pages](doc/man.md) + * [Crashpad overview design](doc/overview_design.md) ## Source Code diff --git a/doc/overview-design.md b/doc/overview_design.md similarity index 100% rename from doc/overview-design.md rename to doc/overview_design.md From cca10659c7391ef6f36f6d65cacc8612203d8e8f Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 18:01:35 -0400 Subject: [PATCH 4/9] =?UTF-8?q?android:=20Fix=20gmock-using=20tests?= =?UTF-8?q?=E2=80=99=20use=20of=20MOCK=5FMETHODn()=20with=20clang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was already addressed by disabling a warning, but was only effective for macOS and non-Android Linux. The comment for the existing fix, which is now being applied to Android: > The MOCK_METHODn() macros do not specify “override”, which triggers > this warning in users: “error: 'Method' overrides a member function > but is not marked 'override' > [-Werror,-Winconsistent-missing-override]”. Suppress these warnings, > and add -Wno-unknown-warning-option because only recent versions of > clang (trunk r220703 and later, version 3.6 and later) recognize it. Also see https://crbug.com/428099. The errors being encountered since 3983b80ca2fc were: util/file/file_reader_test.cc:48:23: error: 'Read' overrides a member function but is not marked 'override' [-Werror,-Winconsistent-missing-override] FileOperationResult Read(void* data, size_t size) { ^ util/file/file_reader.h:39:31: note: overridden virtual function is here virtual FileOperationResult Read(void* data, size_t size) = 0; ^ util/file/file_reader_test.cc:53:16: error: 'Seek' overrides a member function but is not marked 'override' [-Werror,-Winconsistent-missing-override] MOCK_METHOD2(Seek, FileOffset(FileOffset, int)); ^ util/file/file_seeker.h:31:22: note: overridden virtual function is here virtual FileOffset Seek(FileOffset offset, int whence) = 0; ^ Bug: crashpad:30 Test: crashpad_util_test FileReader.* Change-Id: I10894efdafc0da965e3780219f2e4c1f13f9b99e Reviewed-on: https://chromium-review.googlesource.com/458060 Reviewed-by: Scott Graham Commit-Queue: Mark Mentovai --- third_party/gtest/gmock.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/gtest/gmock.gyp b/third_party/gtest/gmock.gyp index 466de6a9..a6600708 100644 --- a/third_party/gtest/gmock.gyp +++ b/third_party/gtest/gmock.gyp @@ -104,7 +104,7 @@ ], }, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="android"', { 'cflags': [ '-Wno-inconsistent-missing-override', '-Wno-unknown-warning-option', From db8c54e142d98dfe1a1b03f1869aeb84fb6eafbc Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 17:34:54 -0400 Subject: [PATCH 5/9] android: Add gyp_crashpad_android.py for easier Android development Bug: crashpad:30 Change-Id: Idf7e6db944bf946e6571064306897848222cd36f Reviewed-on: https://chromium-review.googlesource.com/458078 Reviewed-by: Joshua Peraza --- build/gyp_crashpad.py | 23 +++++++--- build/gyp_crashpad_android.py | 79 +++++++++++++++++++++++++++++++++++ doc/developing.md | 51 +++++++++------------- 3 files changed, 117 insertions(+), 36 deletions(-) create mode 100755 build/gyp_crashpad_android.py diff --git a/build/gyp_crashpad.py b/build/gyp_crashpad.py index fe9da840..dd5fa69c 100755 --- a/build/gyp_crashpad.py +++ b/build/gyp_crashpad.py @@ -75,11 +75,24 @@ def main(args): return result if sys.platform == 'win32': - # Also generate the x86 build. - result = gyp.main(args + ['-D', 'target_arch=ia32', '-G', 'config=Debug']) - if result != 0: - return result - result = gyp.main(args + ['-D', 'target_arch=ia32', '-G', 'config=Release']) + # Check to make sure that no target_arch was specified. target_arch may be + # set during a cross build, such as a cross build for Android. + has_target_arch = False + for arg_index in xrange(0, len(args)): + arg = args[arg_index] + if (arg.startswith('-Dtarget_arch=') or + (arg == '-D' and arg_index + 1 < len(args) and + args[arg_index + 1].startswith('target_arch='))): + has_target_arch = True + break + + if not has_target_arch: + # Also generate the x86 build. + result = gyp.main(args + ['-D', 'target_arch=ia32', '-G', 'config=Debug']) + if result != 0: + return result + result = gyp.main( + args + ['-D', 'target_arch=ia32', '-G', 'config=Release']) return result diff --git a/build/gyp_crashpad_android.py b/build/gyp_crashpad_android.py new file mode 100755 index 00000000..852839aa --- /dev/null +++ b/build/gyp_crashpad_android.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# Copyright 2017 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. + +import argparse +import glob +import gyp_crashpad +import os +import subprocess +import sys + + +def main(args): + parser = argparse.ArgumentParser( + description='Set up an Android cross build', + epilog='Additional arguments will be passed to gyp_crashpad.py.') + parser.add_argument('--ndk', required=True, help='Standalone NDK toolchain') + parser.add_argument('--compiler', + default='clang', + choices=('clang', 'gcc'), + help='The compiler to use, clang by default') + (parsed, extra_args) = parser.parse_known_args(args) + + NDK_ERROR=( + 'NDK must be a valid standalone NDK toolchain.\n' + + 'See https://developer.android.com/ndk/guides/standalone_toolchain.html') + arch_dirs = glob.glob(os.path.join(parsed.ndk, '*-linux-android*')) + if len(arch_dirs) != 1: + parser.error(NDK_ERROR) + + arch_triplet = os.path.basename(arch_dirs[0]) + ARCH_TRIPLET_TO_ARCH = { + 'arm-linux-androideabi': 'arm', + 'aarch64-linux-android': 'arm64', + 'i686-linux-android': 'x86', + 'x86_64-linux-android': 'x86_64', + 'mipsel-linux-android': 'mips', + 'mips64el-linux-android': 'mips64', + } + if arch_triplet not in ARCH_TRIPLET_TO_ARCH: + parser.error(NDK_ERROR) + arch = ARCH_TRIPLET_TO_ARCH[arch_triplet] + + ndk_bin_dir = os.path.join(parsed.ndk, 'bin') + + if parsed.compiler == 'clang': + os.environ['CC_target'] = os.path.join(ndk_bin_dir, 'clang') + os.environ['CXX_target'] = os.path.join(ndk_bin_dir, 'clang++') + elif parsed.compiler == 'gcc': + os.environ['CC_target'] = os.path.join(ndk_bin_dir, + '%s-gcc' % arch_triplet) + os.environ['CXX_target'] = os.path.join(ndk_bin_dir, + '%s-g++' % arch_triplet) + + for tool in ('ar', 'nm', 'readelf'): + os.environ['%s_target' % tool.upper()] = ( + os.path.join(ndk_bin_dir, '%s-%s' % (arch_triplet, tool))) + + return gyp_crashpad.main( + ['-D', 'OS=android', + '-D', 'target_arch=%s' % arch, + '-D', 'clang=%d' % (1 if parsed.compiler == 'clang' else 0), + '-f', 'ninja-android'] + extra_args) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/doc/developing.md b/doc/developing.md index 9beec52c..65d62356 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -137,46 +137,35 @@ Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for [`build/config/android/config.gni`](https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni) which sets `_android_api_level` and `_android64_api_level`. -To configure a Crashpad build for Android using this standalone toolchain, set -several environment variables directing the build to the standalone toolchain, -along with GYP options to identify an Android build. This must be done after any -`gclient sync`, or instead of any `gclient runhooks` operation. The environment -variables only need to be set for this `gyp_crashpad.py` invocation, and need -not be permanent. +To configure a Crashpad build for Android using the standalone toolchain +assembled above, use `gyp_crashpad_android.py`. This script is a wrapper for +`gyp_crashpad.py` that sets several environment variables directing the build to +the standalone toolchain, and several GYP options to identify an Android build. +This must be done after any `gclient sync`, or instead of any `gclient runhooks` +operation. ``` $ cd ~/crashpad/crashpad -$ CC_target=~/android-ndk-r14_arm64_api21/bin/clang \ - CXX_target=~/android-ndk-r14_arm64_api21/bin/clang++ \ - AR_target=~/android-ndk-r14_arm64_api21/bin/aarch64-linux-android-ar \ - NM_target=~/android-ndk-r14_arm64_api21/bin/aarch64-linux-android-nm \ - READELF_target=~/android-ndk-r14_arm64_api21/bin/aarch64-linux-android-readelf \ - python build/gyp_crashpad.py \ - -DOS=android -Dtarget_arch=arm64 -Dclang=1 \ - --generator-output=out/android_arm64_api21 -f ninja-android +$ python build/gyp_crashpad_android.py \ + --ndk ~/android-ndk-r14_arm64_api21 \ + --generator-output out/android_arm64_api21 ``` -It is also possible to use GCC instead of Clang by making the appropriate -substitutions: `aarch64-linux-android-gcc` for `CC_target`; -`aarch64-linux-android-g++` for `CXX_target`; and `-Dclang=0` as an argument to -`gyp_crashpad.py`. +`gyp_crashpad_android.py` detects the build type based on the characteristics of +the standalone toolchain given in its `--ndk` argument. -Target “triplets” to use for `ar`, `nm`, `readelf`, `gcc`, and `g++` are: +`gyp_crashpad_android.py` sets the build up to use Clang by default. It’s also +possible to use GCC by providing the `--compiler=gcc` argument to +`gyp_crashpad_android.py`. -| Architecture | Target “triplet” | -|:-------------|:------------------------| -| `arm` | `arm-linux-androideabi` | -| `arm64` | `aarch64-linux-android` | -| `x86` | `i686-linux-android` | -| `x86_64` | `x86_64-linux-android` | - -The port is incomplete, but targets known to be working include `crashpad_util`, -`crashpad_test`, and `crashpad_test_test`. This list will grow over time. To -build, direct `ninja` to the specific `out` directory chosen by -`--generator-output` above. +The Android port is incomplete, but targets known to be working include +`crashpad_test`, `crashpad_util`, and their tests. This list will grow over +time. To build, direct `ninja` to the specific `out` directory chosen by the +`--generator-output` argument to `gyp_crashpad_android.py`. ``` -$ ninja -C out/android_arm64_api21/out/Debug crashpad_test_test +$ ninja -C out/android_arm64_api21/out/Debug \ + crashpad_test_test crashpad_util_test ``` ## Testing From 013d5e14a30c1bcf3c1809d79100db65b3730a0c Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 21:44:05 -0400 Subject: [PATCH 6/9] #include where offsetof() is used Bug: crashpad:30 Change-Id: If23ca9ea3141d3d34dc494aa29a1bd1dc8f83130 Reviewed-on: https://chromium-review.googlesource.com/458079 Reviewed-by: Scott Graham --- minidump/minidump_module_writer.cc | 2 ++ minidump/minidump_module_writer_test.cc | 1 + minidump/test/minidump_writable_test_util.cc | 2 ++ snapshot/cpu_context.cc | 1 + snapshot/cpu_context_test.cc | 1 + snapshot/mac/cpu_context_mac.cc | 1 + snapshot/mac/process_types/custom.cc | 1 + snapshot/mac/system_snapshot_mac.cc | 1 + snapshot/win/cpu_context_win.cc | 1 + snapshot/win/pe_image_reader.cc | 1 + snapshot/win/process_snapshot_win.cc | 2 ++ util/file/file_writer.cc | 1 + util/mach/notify_server_test.cc | 2 ++ util/misc/uuid.cc | 1 + util/win/process_info.cc | 1 + util/win/registration_protocol_win.cc | 1 + util/win/scoped_process_suspend.cc | 1 + util/win/scoped_process_suspend_test.cc | 1 + 18 files changed, 22 insertions(+) diff --git a/minidump/minidump_module_writer.cc b/minidump/minidump_module_writer.cc index f74a2a70..8fdda897 100644 --- a/minidump/minidump_module_writer.cc +++ b/minidump/minidump_module_writer.cc @@ -14,6 +14,8 @@ #include "minidump/minidump_module_writer.h" +#include + #include #include diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index f5484744..04b8b263 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -14,6 +14,7 @@ #include "minidump/minidump_module_writer.h" +#include #include #include diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index 66c0591d..49ff1720 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -14,6 +14,8 @@ #include "minidump/test/minidump_writable_test_util.h" +#include + #include #include "base/strings/string16.h" diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc index c3887a2c..5c964480 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -14,6 +14,7 @@ #include "snapshot/cpu_context.h" +#include #include #include "base/logging.h" diff --git a/snapshot/cpu_context_test.cc b/snapshot/cpu_context_test.cc index ffc18cfe..6b94871b 100644 --- a/snapshot/cpu_context_test.cc +++ b/snapshot/cpu_context_test.cc @@ -14,6 +14,7 @@ #include "snapshot/cpu_context.h" +#include #include #include diff --git a/snapshot/mac/cpu_context_mac.cc b/snapshot/mac/cpu_context_mac.cc index 8dca246c..c91e3318 100644 --- a/snapshot/mac/cpu_context_mac.cc +++ b/snapshot/mac/cpu_context_mac.cc @@ -14,6 +14,7 @@ #include "snapshot/mac/cpu_context_mac.h" +#include #include #include "base/logging.h" diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 33e3a7ec..c896ebf6 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -14,6 +14,7 @@ #include "snapshot/mac/process_types.h" +#include #include #include diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc index b65a9e08..135fe98e 100644 --- a/snapshot/mac/system_snapshot_mac.cc +++ b/snapshot/mac/system_snapshot_mac.cc @@ -14,6 +14,7 @@ #include "snapshot/mac/system_snapshot_mac.h" +#include #include #include #include diff --git a/snapshot/win/cpu_context_win.cc b/snapshot/win/cpu_context_win.cc index cc66e1cb..1a76c6d9 100644 --- a/snapshot/win/cpu_context_win.cc +++ b/snapshot/win/cpu_context_win.cc @@ -14,6 +14,7 @@ #include "snapshot/win/cpu_context_win.h" +#include #include #include diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc index f7e8e51d..342021a6 100644 --- a/snapshot/win/pe_image_reader.cc +++ b/snapshot/win/pe_image_reader.cc @@ -14,6 +14,7 @@ #include "snapshot/win/pe_image_reader.h" +#include #include #include diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index 11e83145..7a18dbef 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -14,6 +14,8 @@ #include "snapshot/win/process_snapshot_win.h" +#include + #include #include "base/logging.h" diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index a8d92566..13ac6cf5 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -15,6 +15,7 @@ #include "util/file/file_writer.h" #include +#include #include #include diff --git a/util/mach/notify_server_test.cc b/util/mach/notify_server_test.cc index 445e35bf..b0ef4a35 100644 --- a/util/mach/notify_server_test.cc +++ b/util/mach/notify_server_test.cc @@ -14,6 +14,8 @@ #include "util/mach/notify_server.h" +#include + #include "base/compiler_specific.h" #include "base/mac/scoped_mach_port.h" #include "gmock/gmock.h" diff --git a/util/misc/uuid.cc b/util/misc/uuid.cc index d4345a8a..ac2468c6 100644 --- a/util/misc/uuid.cc +++ b/util/misc/uuid.cc @@ -19,6 +19,7 @@ #include "util/misc/uuid.h" #include +#include #include #include diff --git a/util/win/process_info.cc b/util/win/process_info.cc index 2e285b8b..cb2051c0 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -14,6 +14,7 @@ #include "util/win/process_info.h" +#include #include #include diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc index e5cbd8d0..87c45748 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -14,6 +14,7 @@ #include "util/win/registration_protocol_win.h" +#include #include #include "base/logging.h" diff --git a/util/win/scoped_process_suspend.cc b/util/win/scoped_process_suspend.cc index fc75ce02..f07acc3c 100644 --- a/util/win/scoped_process_suspend.cc +++ b/util/win/scoped_process_suspend.cc @@ -14,6 +14,7 @@ #include "util/win/scoped_process_suspend.h" +#include #include #include "util/win/nt_internals.h" diff --git a/util/win/scoped_process_suspend_test.cc b/util/win/scoped_process_suspend_test.cc index adddfe27..f770456e 100644 --- a/util/win/scoped_process_suspend_test.cc +++ b/util/win/scoped_process_suspend_test.cc @@ -14,6 +14,7 @@ #include "util/win/scoped_process_suspend.h" +#include #include #include From 7a7815506bf2d393f391d07f221d61c8c6d8f15d Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 22:01:35 -0400 Subject: [PATCH 7/9] =?UTF-8?q?GCC=20fix:=20Don=E2=80=99t=20use=20arraysiz?= =?UTF-8?q?e()=20on=20packed=20structs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were previously fixed in f83530bf9a0b for some targets, but not crashpad_minidump_test. While compiling minidump_misc_info_writer_test.cc: In file included from minidump/minidump_misc_info_writer.h:26:0, from minidump/minidump_misc_info_writer_test.cc:15: minidump/minidump_misc_info_writer_test.cc: In member function ‘virtual void crashpad::test::{anonymous}::MinidumpMiscInfoWriter_TimeZone_Test::TestBody()’: minidump/minidump_misc_info_writer_test.cc:401:39: error: cannot bind packed field ‘expected.MINIDUMP_MISC_INFO_3::TimeZone.TIME_ZONE_INFORMATION::StandardName’ to ‘short unsigned int (&)[32]’ arraysize(expected.TimeZone.StandardName)); ~~~~~~~~~~~~~~~~~~^ third_party/mini_chromium/mini_chromium/base/macros.h:41:50: note: in definition of macro ‘arraysize’ #define arraysize(array) (sizeof(ArraySizeHelper(array))) ^~~~~ Bug: crashpad:30 Change-Id: I2a1c3b356c0064e8161ec70a9ac156053fc28df7 Reviewed-on: https://chromium-review.googlesource.com/457881 Reviewed-by: Scott Graham --- minidump/minidump_misc_info_writer_test.cc | 42 +++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index 8f2b5517..71fdbfbd 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -34,6 +34,7 @@ #include "snapshot/test/test_process_snapshot.h" #include "snapshot/test/test_system_snapshot.h" #include "util/file/string_file.h" +#include "util/misc/arraysize_unsafe.h" #include "util/stdlib/strlcpy.h" namespace crashpad { @@ -398,7 +399,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - arraysize(expected.TimeZone.StandardName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kStandardDate, sizeof(expected.TimeZone.StandardDate)); @@ -406,7 +407,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - arraysize(expected.TimeZone.DaylightName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kDaylightDate, sizeof(expected.TimeZone.DaylightDate)); @@ -426,9 +427,10 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { const int32_t kBias = 300; MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string standard_name(arraysize(tmp.TimeZone.StandardName) + 1, 's'); + std::string standard_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.StandardName) + 1, + 's'); const int32_t kStandardBias = 0; - std::string daylight_name(arraysize(tmp.TimeZone.DaylightName), 'd'); + std::string daylight_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.DaylightName), 'd'); const int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to @@ -459,7 +461,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - arraysize(expected.TimeZone.StandardName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -467,7 +469,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - arraysize(expected.TimeZone.DaylightName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -498,12 +500,12 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - arraysize(expected.BuildString)); + ARRAYSIZE_UNSAFE(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - arraysize(expected.DbgBldStr)); + ARRAYSIZE_UNSAFE(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -517,8 +519,8 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string build_string(arraysize(tmp.BuildString) + 1, 'B'); - std::string debug_build_string(arraysize(tmp.DbgBldStr), 'D'); + std::string build_string(ARRAYSIZE_UNSAFE(tmp.BuildString) + 1, 'B'); + std::string debug_build_string(ARRAYSIZE_UNSAFE(tmp.DbgBldStr), 'D'); misc_info_writer->SetBuildString(build_string, debug_build_string); @@ -535,12 +537,12 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { base::string16 build_string_utf16 = base::UTF8ToUTF16(build_string); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - arraysize(expected.BuildString)); + ARRAYSIZE_UNSAFE(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - arraysize(expected.DbgBldStr)); + ARRAYSIZE_UNSAFE(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -680,7 +682,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - arraysize(expected.TimeZone.StandardName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -688,7 +690,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - arraysize(expected.TimeZone.DaylightName)); + ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -696,12 +698,12 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - arraysize(expected.BuildString)); + ARRAYSIZE_UNSAFE(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - arraysize(expected.DbgBldStr)); + ARRAYSIZE_UNSAFE(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -744,18 +746,18 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { expect_misc_info.TimeZone.Bias = 300; c16lcpy(expect_misc_info.TimeZone.StandardName, standard_time_name_utf16.c_str(), - arraysize(expect_misc_info.TimeZone.StandardName)); + ARRAYSIZE_UNSAFE(expect_misc_info.TimeZone.StandardName)); expect_misc_info.TimeZone.StandardBias = 0; c16lcpy(expect_misc_info.TimeZone.DaylightName, daylight_time_name_utf16.c_str(), - arraysize(expect_misc_info.TimeZone.DaylightName)); + ARRAYSIZE_UNSAFE(expect_misc_info.TimeZone.DaylightName)); expect_misc_info.TimeZone.DaylightBias = -60; c16lcpy(expect_misc_info.BuildString, build_string_utf16.c_str(), - arraysize(expect_misc_info.BuildString)); + ARRAYSIZE_UNSAFE(expect_misc_info.BuildString)); c16lcpy(expect_misc_info.DbgBldStr, debug_build_string_utf16.c_str(), - arraysize(expect_misc_info.DbgBldStr)); + ARRAYSIZE_UNSAFE(expect_misc_info.DbgBldStr)); const timeval kStartTime = { static_cast(expect_misc_info.ProcessCreateTime), 0 }; From fa3413e14a22b79b69cbd6f81373f9b3739ba1bb Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 22 Mar 2017 22:13:30 -0400 Subject: [PATCH 8/9] GCC fix for -Wunused-but-set-variable While compiling minidump_module_writer_test.cc: minidump/minidump_module_writer_test.cc: In member function 'virtual void crashpad::test::{anonymous}::MinidumpModuleWriter_InitializeFromSnapshot_Test::TestBody()': minidump/minidump_module_writer_test.cc:656:15: error: variable 'module_names' set but not used [-Werror=unused-but-set-variable] const char* module_names[arraysize(expect_modules)] = {}; ^ Bug: crashpad:30 Change-Id: Ie6bcbced67c947ba6cca32a7057a8ac6de4d0e5a Reviewed-on: https://chromium-review.googlesource.com/457958 Reviewed-by: Scott Graham --- minidump/minidump_module_writer_test.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 04b8b263..6a0464cf 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -654,7 +654,6 @@ void InitializeTestModuleSnapshotFromMinidumpModule( TEST(MinidumpModuleWriter, InitializeFromSnapshot) { MINIDUMP_MODULE expect_modules[3] = {}; const char* module_paths[arraysize(expect_modules)] = {}; - const char* module_names[arraysize(expect_modules)] = {}; const char* module_pdbs[arraysize(expect_modules)] = {}; UUID uuids[arraysize(expect_modules)] = {}; uint32_t ages[arraysize(expect_modules)] = {}; @@ -668,7 +667,6 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[0].VersionInfo.dwProductVersionLS = 0x00070008; expect_modules[0].VersionInfo.dwFileType = VFT_APP; module_paths[0] = "/usr/bin/true"; - module_names[0] = "true"; module_pdbs[0] = "true"; const uint8_t kUUIDBytes0[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, @@ -685,7 +683,6 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[1].VersionInfo.dwProductVersionLS = 0x000f0000; expect_modules[1].VersionInfo.dwFileType = VFT_DLL; module_paths[1] = "/usr/lib/libSystem.B.dylib"; - module_names[1] = "libSystem.B.dylib"; module_pdbs[1] = "libSystem.B.dylib.pdb"; const uint8_t kUUIDBytes1[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -702,7 +699,6 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[2].VersionInfo.dwProductVersionLS = 0xbbbbcccc; expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN; module_paths[2] = "/usr/lib/dyld"; - module_names[2] = "dyld"; module_pdbs[2] = "/usr/lib/dyld.pdb"; const uint8_t kUUIDBytes2[16] = {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, From 810d4815df8aea0174e392668c8dff29ea568eeb Mon Sep 17 00:00:00 2001 From: Sigurdur Asgeirsson Date: Thu, 23 Mar 2017 08:52:46 -0400 Subject: [PATCH 9/9] minidump: Allow for user extension streams computed at crash time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: crashpad:167 Change-Id: I94c143353482f100a31d6afb0685b38757a662d6 Reviewed-on: https://chromium-review.googlesource.com/455976 Commit-Queue: Sigurður Ásgeirsson Reviewed-by: Mark Mentovai --- minidump/minidump.gyp | 2 + minidump/minidump_file_writer.cc | 14 +++ minidump/minidump_file_writer.h | 29 ++++++ minidump/minidump_file_writer_test.cc | 45 +++++++++ ...idump_user_extension_stream_data_source.cc | 30 ++++++ ...nidump_user_extension_stream_data_source.h | 55 +++++++++++ minidump/minidump_user_stream_writer.cc | 95 +++++++++++++++---- minidump/minidump_user_stream_writer.h | 32 ++++--- minidump/minidump_user_stream_writer_test.cc | 62 ++++++++++-- 9 files changed, 322 insertions(+), 42 deletions(-) create mode 100644 minidump/minidump_user_extension_stream_data_source.cc create mode 100644 minidump/minidump_user_extension_stream_data_source.h diff --git a/minidump/minidump.gyp b/minidump/minidump.gyp index 35528060..3135de3d 100644 --- a/minidump/minidump.gyp +++ b/minidump/minidump.gyp @@ -72,6 +72,8 @@ 'minidump_thread_writer.h', 'minidump_unloaded_module_writer.cc', 'minidump_unloaded_module_writer.h', + 'minidump_user_extension_stream_data_source.cc', + 'minidump_user_extension_stream_data_source.h', 'minidump_user_stream_writer.cc', 'minidump_user_stream_writer.h', 'minidump_writable.cc', diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index ebff2bab..3e99d2a3 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -29,6 +29,7 @@ #include "minidump/minidump_thread_id_map.h" #include "minidump/minidump_thread_writer.h" #include "minidump/minidump_unloaded_module_writer.h" +#include "minidump/minidump_user_extension_stream_data_source.h" #include "minidump/minidump_user_stream_writer.h" #include "minidump/minidump_writer_util.h" #include "snapshot/exception_snapshot.h" @@ -199,6 +200,19 @@ bool MinidumpFileWriter::AddStream( return true; } +bool MinidumpFileWriter::AddUserExtensionStream( + std::unique_ptr + user_extension_stream_data) { + DCHECK_EQ(state(), kStateMutable); + + auto user_stream = base::WrapUnique(new MinidumpUserStreamWriter()); + user_stream->InitializeFromBuffer(user_extension_stream_data->stream_type(), + user_extension_stream_data->buffer(), + user_extension_stream_data->buffer_size()); + + return AddStream(std::move(user_stream)); +} + bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateMutable); diff --git a/minidump/minidump_file_writer.h b/minidump/minidump_file_writer.h index 05cecb14..d5e2d1a5 100644 --- a/minidump/minidump_file_writer.h +++ b/minidump/minidump_file_writer.h @@ -33,6 +33,7 @@ namespace crashpad { class ProcessSnapshot; +class MinidumpUserExtensionStreamDataSource; //! \brief The root-level object in a minidump file. //! @@ -61,7 +62,11 @@ class MinidumpFileWriter final : public internal::MinidumpWritable { //! - kMinidumpStreamTypeThreadList //! - kMinidumpStreamTypeException (if present) //! - kMinidumpStreamTypeModuleList + //! - kMinidumpStreamTypeUnloadedModuleList (if present) //! - kMinidumpStreamTypeCrashpadInfo (if present) + //! - kMinidumpStreamTypeMemoryInfoList (if present) + //! - kMinidumpStreamTypeHandleData (if present) + //! - User streams (if present) //! - kMinidumpStreamTypeMemoryList //! //! \param[in] process_snapshot The process snapshot to use as source data. @@ -95,6 +100,30 @@ class MinidumpFileWriter final : public internal::MinidumpWritable { //! with a message logged. bool AddStream(std::unique_ptr stream); + //! \brief Adds a user extension stream to the minidump file and arranges for + //! a MINIDUMP_DIRECTORY entry to point to it. + //! + //! This object takes ownership of \a user_extension_stream_data. + //! + //! At most one object of each stream type (as obtained from + //! internal::MinidumpStreamWriter::StreamType()) may be added to a + //! MinidumpFileWriter object. If an attempt is made to add a stream whose + //! type matches an existing stream’s type, this method discards the new + //! stream. + //! + //! \param[in] user_extension_stream_data The stream data to add to the + //! minidump file. Note that the buffer this object points to must be valid + //! through WriteEverything(). + //! + //! \note Valid in #kStateMutable. + //! + //! \return `true` on success. `false` on failure, as occurs when an attempt + //! is made to add a stream whose type matches an existing stream’s type, + //! with a message logged. + bool AddUserExtensionStream( + std::unique_ptr + user_extension_stream_data); + // MinidumpWritable: //! \copydoc internal::MinidumpWritable::WriteEverything() diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index d8d0f394..0d300603 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -25,6 +25,7 @@ #include "base/memory/ptr_util.h" #include "gtest/gtest.h" #include "minidump/minidump_stream_writer.h" +#include "minidump/minidump_user_extension_stream_data_source.h" #include "minidump/minidump_writable.h" #include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" @@ -127,6 +128,50 @@ TEST(MinidumpFileWriter, OneStream) { EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize)); } +TEST(MinidumpFileWriter, AddUserExtensionStream) { + MinidumpFileWriter minidump_file; + const time_t kTimestamp = 0x155d2fb8; + minidump_file.SetTimestamp(kTimestamp); + + static const uint8_t kStreamData[] = "Hello World!"; + const size_t kStreamSize = arraysize(kStreamData); + const MinidumpStreamType kStreamType = static_cast(0x4d); + + auto stream = base::WrapUnique(new MinidumpUserExtensionStreamDataSource( + kStreamType, kStreamData, kStreamSize)); + ASSERT_TRUE(minidump_file.AddUserExtensionStream(std::move(stream))); + + // Adding the same stream type a second time should fail. + stream = base::WrapUnique(new MinidumpUserExtensionStreamDataSource( + kStreamType, kStreamData, kStreamSize)); + ASSERT_FALSE(minidump_file.AddUserExtensionStream(std::move(stream))); + + StringFile string_file; + ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); + + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + const size_t kFileSize = kStreamOffset + kStreamSize; + + ASSERT_EQ(kFileSize, string_file.string().size()); + + const MINIDUMP_DIRECTORY* directory; + const MINIDUMP_HEADER* header = + MinidumpHeaderAtStart(string_file.string(), &directory); + ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, kTimestamp)); + ASSERT_TRUE(directory); + + EXPECT_EQ(kStreamType, directory[0].StreamType); + EXPECT_EQ(kStreamSize, directory[0].Location.DataSize); + EXPECT_EQ(kStreamOffset, directory[0].Location.Rva); + + const uint8_t* stream_data = MinidumpWritableAtLocationDescriptor( + string_file.string(), directory[0].Location); + ASSERT_TRUE(stream_data); + + EXPECT_EQ(0, memcmp(stream_data, kStreamData, kStreamSize)); +} + TEST(MinidumpFileWriter, ThreeStreams) { MinidumpFileWriter minidump_file; const time_t kTimestamp = 0x155d2fb8; diff --git a/minidump/minidump_user_extension_stream_data_source.cc b/minidump/minidump_user_extension_stream_data_source.cc new file mode 100644 index 00000000..8056011c --- /dev/null +++ b/minidump/minidump_user_extension_stream_data_source.cc @@ -0,0 +1,30 @@ +// Copyright 2017 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 "minidump/minidump_user_extension_stream_data_source.h" + +namespace crashpad { + +MinidumpUserExtensionStreamDataSource::MinidumpUserExtensionStreamDataSource( + uint32_t stream_type, + const void* buffer, + size_t buffer_size) + : stream_type_(static_cast(stream_type)), + buffer_(buffer), + buffer_size_(buffer_size) {} + +MinidumpUserExtensionStreamDataSource:: + ~MinidumpUserExtensionStreamDataSource() {} + +} // namespace crashpad diff --git a/minidump/minidump_user_extension_stream_data_source.h b/minidump/minidump_user_extension_stream_data_source.h new file mode 100644 index 00000000..1afb1661 --- /dev/null +++ b/minidump/minidump_user_extension_stream_data_source.h @@ -0,0 +1,55 @@ +// Copyright 2017 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_MINIDUMP_MINIDUMP_USER_EXTENSION_STREAM_DATA_SOURCE_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_USER_EXTENSION_STREAM_DATA_SOURCE_H_ + +#include +#include + +#include "base/macros.h" + +#include "minidump/minidump_extensions.h" + +namespace crashpad { + +//! \brief Describes a user extension data stream in a minidump. +class MinidumpUserExtensionStreamDataSource { + public: + //! \brief Constructs a MinidumpUserExtensionStreamDataSource. + //! + //! \param[in] stream_type The type of the user extension stream. + //! \param[in] buffer Points to the data for this stream. \a buffer is not + //! owned, and must outlive the use of this object. + //! \param[in] buffer_size The length of data in \a buffer. + MinidumpUserExtensionStreamDataSource(uint32_t stream_type, + const void* buffer, + size_t buffer_size); + ~MinidumpUserExtensionStreamDataSource(); + + MinidumpStreamType stream_type() const { return stream_type_; } + const void* buffer() const { return buffer_; } + size_t buffer_size() const { return buffer_size_; } + + private: + MinidumpStreamType stream_type_; + const void* buffer_; // weak + size_t buffer_size_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpUserExtensionStreamDataSource); +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_USER_EXTENSION_STREAM_DATA_SOURCE_H_ diff --git a/minidump/minidump_user_stream_writer.cc b/minidump/minidump_user_stream_writer.cc index 7332cd01..6520f0f4 100644 --- a/minidump/minidump_user_stream_writer.cc +++ b/minidump/minidump_user_stream_writer.cc @@ -14,13 +14,67 @@ #include "minidump/minidump_user_stream_writer.h" +#include "base/memory/ptr_util.h" #include "util/file/file_writer.h" namespace crashpad { -MinidumpUserStreamWriter::MinidumpUserStreamWriter() - : stream_type_(0), reader_() { -} +class MinidumpUserStreamWriter::ContentsWriter { + public: + virtual ~ContentsWriter() {} + virtual bool WriteContents(FileWriterInterface* writer) = 0; + virtual size_t GetSize() const = 0; +}; + +class MinidumpUserStreamWriter::SnapshotContentsWriter final + : public MinidumpUserStreamWriter::ContentsWriter, + public MemorySnapshot::Delegate { + public: + explicit SnapshotContentsWriter(const MemorySnapshot* snapshot) + : snapshot_(snapshot), writer_(nullptr) {} + + bool WriteContents(FileWriterInterface* writer) override { + DCHECK(!writer_); + + writer_ = writer; + if (!snapshot_) + return true; + + return snapshot_->Read(this); + } + + size_t GetSize() const override { return snapshot_ ? snapshot_->Size() : 0; }; + + bool MemorySnapshotDelegateRead(void* data, size_t size) override { + return writer_->Write(data, size); + } + + private: + const MemorySnapshot* snapshot_; + FileWriterInterface* writer_; + + DISALLOW_COPY_AND_ASSIGN(SnapshotContentsWriter); +}; + +class MinidumpUserStreamWriter::BufferContentsWriter final + : public MinidumpUserStreamWriter::ContentsWriter { + public: + BufferContentsWriter(const void* buffer, size_t buffer_size) + : buffer_(buffer), buffer_size_(buffer_size) {} + + bool WriteContents(FileWriterInterface* writer) override { + return writer->Write(buffer_, buffer_size_); + } + size_t GetSize() const override { return buffer_size_; } + + private: + const void* buffer_; + size_t buffer_size_; + + DISALLOW_COPY_AND_ASSIGN(BufferContentsWriter); +}; + +MinidumpUserStreamWriter::MinidumpUserStreamWriter() : stream_type_() {} MinidumpUserStreamWriter::~MinidumpUserStreamWriter() { } @@ -28,10 +82,23 @@ MinidumpUserStreamWriter::~MinidumpUserStreamWriter() { void MinidumpUserStreamWriter::InitializeFromSnapshot( const UserMinidumpStream* stream) { DCHECK_EQ(state(), kStateMutable); + DCHECK(!contents_writer_.get()); - stream_type_ = stream->stream_type(); - if (stream->memory()) - stream->memory()->Read(&reader_); + stream_type_ = static_cast(stream->stream_type()); + contents_writer_ = + base::WrapUnique(new SnapshotContentsWriter(stream->memory())); +} + +void MinidumpUserStreamWriter::InitializeFromBuffer( + MinidumpStreamType stream_type, + const void* buffer, + size_t buffer_size) { + DCHECK_EQ(state(), kStateMutable); + DCHECK(!contents_writer_.get()); + + stream_type_ = stream_type; + contents_writer_ = + base::WrapUnique(new BufferContentsWriter(buffer, buffer_size)); } bool MinidumpUserStreamWriter::Freeze() { @@ -42,7 +109,8 @@ bool MinidumpUserStreamWriter::Freeze() { size_t MinidumpUserStreamWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); - return reader_.size(); + + return contents_writer_->GetSize(); } std::vector @@ -53,21 +121,12 @@ MinidumpUserStreamWriter::Children() { bool MinidumpUserStreamWriter::WriteObject(FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); - return file_writer->Write(reader_.data(), reader_.size()); + + return contents_writer_->WriteContents(file_writer); } MinidumpStreamType MinidumpUserStreamWriter::StreamType() const { return static_cast(stream_type_); } -MinidumpUserStreamWriter::MemoryReader::~MemoryReader() {} - -bool MinidumpUserStreamWriter::MemoryReader::MemorySnapshotDelegateRead( - void* data, - size_t size) { - data_.resize(size); - memcpy(&data_[0], data, size); - return true; -} - } // namespace crashpad diff --git a/minidump/minidump_user_stream_writer.h b/minidump/minidump_user_stream_writer.h index b31247a3..838ed0de 100644 --- a/minidump/minidump_user_stream_writer.h +++ b/minidump/minidump_user_stream_writer.h @@ -22,6 +22,7 @@ #include #include "base/macros.h" +#include "minidump/minidump_extensions.h" #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_writable.h" #include "snapshot/module_snapshot.h" @@ -41,6 +42,18 @@ class MinidumpUserStreamWriter final : public internal::MinidumpStreamWriter { //! \note Valid in #kStateMutable. void InitializeFromSnapshot(const UserMinidumpStream* stream); + //! \brief Initializes a MINIDUMP_USER_STREAM based on \a stream_type, + //! \a buffer and \a buffer_size. + //! + //! \param[in] stream_type The type of the stream. + //! \param[in] buffer The data for the stream. + //! \param[in] buffer_size The length of \a buffer, and the resulting stream. + //! + //! \note Valid in #kStateMutable. + void InitializeFromBuffer(MinidumpStreamType stream_type, + const void* buffer, + size_t buffer_size); + protected: // MinidumpWritable: bool Freeze() override; @@ -52,22 +65,13 @@ class MinidumpUserStreamWriter final : public internal::MinidumpStreamWriter { MinidumpStreamType StreamType() const override; private: - class MemoryReader : public MemorySnapshot::Delegate { - public: - ~MemoryReader() override; - bool MemorySnapshotDelegateRead(void* data, size_t size) override; + class ContentsWriter; + class SnapshotContentsWriter; + class BufferContentsWriter; - const void* data() const { - return reinterpret_cast(data_.data()); - } - size_t size() const { return data_.size(); } + std::unique_ptr contents_writer_; - private: - std::vector data_; - }; - - uint32_t stream_type_; - MemoryReader reader_; + MinidumpStreamType stream_type_; DISALLOW_COPY_AND_ASSIGN(MinidumpUserStreamWriter); }; diff --git a/minidump/minidump_user_stream_writer_test.cc b/minidump/minidump_user_stream_writer_test.cc index e4e8cccb..3942e0e6 100644 --- a/minidump/minidump_user_stream_writer_test.cc +++ b/minidump/minidump_user_stream_writer_test.cc @@ -32,7 +32,8 @@ namespace { // The user stream is expected to be the only stream. void GetUserStream(const std::string& file_contents, MINIDUMP_LOCATION_DESCRIPTOR* user_stream_location, - uint32_t stream_type) { + uint32_t stream_type, + size_t stream_size) { const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); const size_t kUserStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); @@ -47,13 +48,16 @@ void GetUserStream(const std::string& file_contents, ASSERT_EQ(stream_type, directory[kDirectoryIndex].StreamType); EXPECT_EQ(kUserStreamOffset, directory[kDirectoryIndex].Location.Rva); + EXPECT_EQ(stream_size, directory[kDirectoryIndex].Location.DataSize); *user_stream_location = directory[kDirectoryIndex].Location; } -TEST(MinidumpUserStreamWriter, NoData) { +constexpr MinidumpStreamType kTestStreamId = + static_cast(0x123456); + +TEST(MinidumpUserStreamWriter, InitializeFromSnapshotNoData) { MinidumpFileWriter minidump_file_writer; auto user_stream_writer = base::WrapUnique(new MinidumpUserStreamWriter()); - const uint32_t kTestStreamId = 0x123456; auto stream = base::WrapUnique(new UserMinidumpStream(kTestStreamId, nullptr)); user_stream_writer->InitializeFromSnapshot(stream.get()); @@ -67,14 +71,29 @@ TEST(MinidumpUserStreamWriter, NoData) { MINIDUMP_LOCATION_DESCRIPTOR user_stream_location; ASSERT_NO_FATAL_FAILURE(GetUserStream( - string_file.string(), &user_stream_location, kTestStreamId)); - EXPECT_EQ(0u, user_stream_location.DataSize); + string_file.string(), &user_stream_location, kTestStreamId, 0u)); } -TEST(MinidumpUserStreamWriter, OneStream) { +TEST(MinidumpUserStreamWriter, InitializeFromBufferNoData) { + MinidumpFileWriter minidump_file_writer; + auto user_stream_writer = base::WrapUnique(new MinidumpUserStreamWriter()); + user_stream_writer->InitializeFromBuffer(kTestStreamId, nullptr, 0); + minidump_file_writer.AddStream(std::move(user_stream_writer)); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY), + string_file.string().size()); + + MINIDUMP_LOCATION_DESCRIPTOR user_stream_location; + ASSERT_NO_FATAL_FAILURE(GetUserStream( + string_file.string(), &user_stream_location, kTestStreamId, 0u)); +} + +TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) { MinidumpFileWriter minidump_file_writer; auto user_stream_writer = base::WrapUnique(new MinidumpUserStreamWriter()); - const uint32_t kTestStreamId = 0x123456; TestMemorySnapshot* test_data = new TestMemorySnapshot(); test_data->SetAddress(97865); @@ -92,10 +111,33 @@ TEST(MinidumpUserStreamWriter, OneStream) { ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + kStreamSize, string_file.string().size()); - MINIDUMP_LOCATION_DESCRIPTOR user_stream_location; + MINIDUMP_LOCATION_DESCRIPTOR user_stream_location = {}; ASSERT_NO_FATAL_FAILURE(GetUserStream( - string_file.string(), &user_stream_location, kTestStreamId)); - EXPECT_EQ(kStreamSize, user_stream_location.DataSize); + string_file.string(), &user_stream_location, kTestStreamId, kStreamSize)); + const std::string stream_data = string_file.string().substr( + user_stream_location.Rva, user_stream_location.DataSize); + EXPECT_EQ(std::string(kStreamSize, 'c'), stream_data); +} + +TEST(MinidumpUserStreamWriter, InitializeFromBufferOneStream) { + MinidumpFileWriter minidump_file_writer; + auto user_stream_writer = base::WrapUnique(new MinidumpUserStreamWriter()); + + const size_t kStreamSize = 128; + std::vector data(kStreamSize, 'c'); + user_stream_writer->InitializeFromBuffer( + kTestStreamId, &data[0], data.size()); + minidump_file_writer.AddStream(std::move(user_stream_writer)); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + kStreamSize, + string_file.string().size()); + + MINIDUMP_LOCATION_DESCRIPTOR user_stream_location = {}; + ASSERT_NO_FATAL_FAILURE(GetUserStream( + string_file.string(), &user_stream_location, kTestStreamId, kStreamSize)); const std::string stream_data = string_file.string().substr( user_stream_location.Rva, user_stream_location.DataSize); EXPECT_EQ(std::string(kStreamSize, 'c'), stream_data);