Added missing breakpad files.
This commit is contained in:
		
							parent
							
								
									e8f2f6e8c9
								
							
						
					
					
						commit
						7fdbd505a2
					
				@ -15,7 +15,6 @@ syntax: regexp
 | 
				
			|||||||
^google-breakpad/src/common/solaris
 | 
					^google-breakpad/src/common/solaris
 | 
				
			||||||
^google-breakpad/src/common/testdata
 | 
					^google-breakpad/src/common/testdata
 | 
				
			||||||
^google-breakpad/src/common/tests
 | 
					^google-breakpad/src/common/tests
 | 
				
			||||||
^google-breakpad/src/common/windows
 | 
					 | 
				
			||||||
^google-breakpad/src/processor
 | 
					^google-breakpad/src/processor
 | 
				
			||||||
^google-breakpad/src/testing
 | 
					^google-breakpad/src/testing
 | 
				
			||||||
^google-breakpad/src/third_party/curl
 | 
					^google-breakpad/src/third_party/curl
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										87
									
								
								google-breakpad/src/common/windows/common_windows.gyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								google-breakpad/src/common/windows/common_windows.gyp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					# Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					# modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					# met:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					# notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					#     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					# copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					# in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					# distribution.
 | 
				
			||||||
 | 
					#     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					# contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					# this software without specific prior written permission.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  'includes': [
 | 
				
			||||||
 | 
					    '../../client/windows/build/common.gypi',
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  'targets': [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      'target_name': 'dia_sdk',
 | 
				
			||||||
 | 
					      'type': 'none',
 | 
				
			||||||
 | 
					      'all_dependent_settings': {
 | 
				
			||||||
 | 
					        'include_dirs': [
 | 
				
			||||||
 | 
					          '<(DEPTH)',
 | 
				
			||||||
 | 
					          '$(VSInstallDir)\DIA SDK\include',
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        'msvs_settings': {
 | 
				
			||||||
 | 
					          'VCLinkerTool': {
 | 
				
			||||||
 | 
					            'AdditionalDependencies': [
 | 
				
			||||||
 | 
					              '$(VSInstallDir)\DIA SDK\lib\diaguids.lib',
 | 
				
			||||||
 | 
					              'imagehlp.lib',
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      'target_name': 'common_windows_lib',
 | 
				
			||||||
 | 
					      'type': 'static_library',
 | 
				
			||||||
 | 
					      'sources': [
 | 
				
			||||||
 | 
					        'dia_util.cc',
 | 
				
			||||||
 | 
					        'dia_util.h',
 | 
				
			||||||
 | 
					        'guid_string.cc',
 | 
				
			||||||
 | 
					        'guid_string.h',
 | 
				
			||||||
 | 
					        'http_upload.cc',
 | 
				
			||||||
 | 
					        'http_upload.h',
 | 
				
			||||||
 | 
					        'omap.cc',
 | 
				
			||||||
 | 
					        'omap.h',
 | 
				
			||||||
 | 
					        'omap_internal.h',
 | 
				
			||||||
 | 
					        'pdb_source_line_writer.cc',
 | 
				
			||||||
 | 
					        'pdb_source_line_writer.h',
 | 
				
			||||||
 | 
					        'string_utils.cc',
 | 
				
			||||||
 | 
					        'string_utils-inl.h',
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      'dependencies': [
 | 
				
			||||||
 | 
					        'dia_sdk',
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      'target_name': 'common_windows_unittests',
 | 
				
			||||||
 | 
					      'type': 'executable',
 | 
				
			||||||
 | 
					      'sources': [
 | 
				
			||||||
 | 
					        'omap_unittest.cc',
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      'dependencies': [
 | 
				
			||||||
 | 
					        '<(DEPTH)/client/windows/unittests/testing.gyp:gmock',
 | 
				
			||||||
 | 
					        '<(DEPTH)/client/windows/unittests/testing.gyp:gtest',
 | 
				
			||||||
 | 
					        'common_windows_lib',
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								google-breakpad/src/common/windows/dia_util.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								google-breakpad/src/common/windows/dia_util.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/dia_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atlbase.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool FindDebugStream(const wchar_t* name,
 | 
				
			||||||
 | 
					                     IDiaSession* session,
 | 
				
			||||||
 | 
					                     IDiaEnumDebugStreamData** debug_stream) {
 | 
				
			||||||
 | 
					  CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
 | 
				
			||||||
 | 
					  if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
 | 
				
			||||||
 | 
					  ULONG fetched = 0;
 | 
				
			||||||
 | 
					  while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
 | 
				
			||||||
 | 
					         fetched == 1) {
 | 
				
			||||||
 | 
					    CComBSTR stream_name;
 | 
				
			||||||
 | 
					    if (FAILED(temp_debug_stream->get_name(&stream_name))) {
 | 
				
			||||||
 | 
					      fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Found the stream?
 | 
				
			||||||
 | 
					    if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
 | 
				
			||||||
 | 
					      *debug_stream = temp_debug_stream.Detach();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    temp_debug_stream.Release();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // No table was found.
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool FindTable(REFIID iid, IDiaSession* session, void** table) {
 | 
				
			||||||
 | 
					  // Get the table enumerator.
 | 
				
			||||||
 | 
					  CComPtr<IDiaEnumTables> enum_tables;
 | 
				
			||||||
 | 
					  if (FAILED(session->getEnumTables(&enum_tables))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaSession::getEnumTables failed\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Iterate through the tables.
 | 
				
			||||||
 | 
					  CComPtr<IDiaTable> temp_table;
 | 
				
			||||||
 | 
					  ULONG fetched = 0;
 | 
				
			||||||
 | 
					  while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
 | 
				
			||||||
 | 
					         fetched == 1) {
 | 
				
			||||||
 | 
					    void* temp = NULL;
 | 
				
			||||||
 | 
					    if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
 | 
				
			||||||
 | 
					      *table = temp;
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    temp_table.Release();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The table was not found.
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										59
									
								
								google-breakpad/src/common/windows/dia_util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								google-breakpad/src/common/windows/dia_util.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Utilities for loading debug streams and tables from a PDB file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#include <dia2.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Find the debug stream of the given |name| in the given |session|. Returns
 | 
				
			||||||
 | 
					// true on success, false on error of if the stream does not exist. On success
 | 
				
			||||||
 | 
					// the stream will be returned via |debug_stream|.
 | 
				
			||||||
 | 
					bool FindDebugStream(const wchar_t* name,
 | 
				
			||||||
 | 
					                     IDiaSession* session,
 | 
				
			||||||
 | 
					                     IDiaEnumDebugStreamData** debug_stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Finds the first table implementing the COM interface with ID |iid| in the
 | 
				
			||||||
 | 
					// given |session|. Returns true on success, false on error or if no such
 | 
				
			||||||
 | 
					// table is found. On success the table will be returned via |table|.
 | 
				
			||||||
 | 
					bool FindTable(REFIID iid, IDiaSession* session, void** table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A templated version of FindTable. Finds the first table implementing type
 | 
				
			||||||
 | 
					// |InterfaceType| in the given |session|. Returns true on success, false on
 | 
				
			||||||
 | 
					// error or if no such table is found. On success the table will be returned via
 | 
				
			||||||
 | 
					// |table|.
 | 
				
			||||||
 | 
					template<typename InterfaceType>
 | 
				
			||||||
 | 
					bool FindTable(IDiaSession* session, InterfaceType** table) {
 | 
				
			||||||
 | 
					  return FindTable(__uuidof(InterfaceType),
 | 
				
			||||||
 | 
					                   session,
 | 
				
			||||||
 | 
					                   reinterpret_cast<void**>(table));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										76
									
								
								google-breakpad/src/common/windows/guid_string.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								google-breakpad/src/common/windows/guid_string.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// guid_string.cc: Convert GUIDs to strings.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// See guid_string.h for documentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/string_utils-inl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/guid_string.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring GUIDString::GUIDToWString(GUID *guid) {
 | 
				
			||||||
 | 
					  wchar_t guid_string[37];
 | 
				
			||||||
 | 
					  swprintf(
 | 
				
			||||||
 | 
					      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
 | 
				
			||||||
 | 
					      L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
 | 
				
			||||||
 | 
					      guid->Data1, guid->Data2, guid->Data3,
 | 
				
			||||||
 | 
					      guid->Data4[0], guid->Data4[1], guid->Data4[2],
 | 
				
			||||||
 | 
					      guid->Data4[3], guid->Data4[4], guid->Data4[5],
 | 
				
			||||||
 | 
					      guid->Data4[6], guid->Data4[7]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // remove when VC++7.1 is no longer supported
 | 
				
			||||||
 | 
					  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return wstring(guid_string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) {
 | 
				
			||||||
 | 
					  wchar_t guid_string[33];
 | 
				
			||||||
 | 
					  swprintf(
 | 
				
			||||||
 | 
					      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
 | 
				
			||||||
 | 
					      L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
 | 
				
			||||||
 | 
					      guid->Data1, guid->Data2, guid->Data3,
 | 
				
			||||||
 | 
					      guid->Data4[0], guid->Data4[1], guid->Data4[2],
 | 
				
			||||||
 | 
					      guid->Data4[3], guid->Data4[4], guid->Data4[5],
 | 
				
			||||||
 | 
					      guid->Data4[6], guid->Data4[7]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // remove when VC++7.1 is no longer supported
 | 
				
			||||||
 | 
					  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return wstring(guid_string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										58
									
								
								google-breakpad/src/common/windows/guid_string.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								google-breakpad/src/common/windows/guid_string.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// guid_string.cc: Convert GUIDs to strings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMMON_WINDOWS_GUID_STRING_H__
 | 
				
			||||||
 | 
					#define COMMON_WINDOWS_GUID_STRING_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Guiddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using std::wstring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GUIDString {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  // Converts guid to a string in the format recommended by RFC 4122 and
 | 
				
			||||||
 | 
					  // returns the string.
 | 
				
			||||||
 | 
					  static wstring GUIDToWString(GUID *guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Converts guid to a string formatted as uppercase hexadecimal, with
 | 
				
			||||||
 | 
					  // no separators, and returns the string.  This is the format used for
 | 
				
			||||||
 | 
					  // symbol server identifiers, although identifiers have an age tacked
 | 
				
			||||||
 | 
					  // on to the string.
 | 
				
			||||||
 | 
					  static wstring GUIDToSymbolServerWString(GUID *guid);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // COMMON_WINDOWS_GUID_STRING_H__
 | 
				
			||||||
							
								
								
									
										412
									
								
								google-breakpad/src/common/windows/http_upload.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								google-breakpad/src/common/windows/http_upload.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,412 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Disable exception handler warnings.
 | 
				
			||||||
 | 
					#pragma warning( disable : 4530 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/string_utils-inl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/http_upload.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using std::ifstream;
 | 
				
			||||||
 | 
					using std::ios;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Helper class which closes an internet handle when it goes away
 | 
				
			||||||
 | 
					class HTTPUpload::AutoInternetHandle {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}
 | 
				
			||||||
 | 
					  ~AutoInternetHandle() {
 | 
				
			||||||
 | 
					    if (handle_) {
 | 
				
			||||||
 | 
					      InternetCloseHandle(handle_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HINTERNET get() { return handle_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  HINTERNET handle_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool HTTPUpload::SendRequest(const wstring &url,
 | 
				
			||||||
 | 
					                             const map<wstring, wstring> ¶meters,
 | 
				
			||||||
 | 
					                             const wstring &upload_file,
 | 
				
			||||||
 | 
					                             const wstring &file_part_name,
 | 
				
			||||||
 | 
					                             int *timeout,
 | 
				
			||||||
 | 
					                             wstring *response_body,
 | 
				
			||||||
 | 
					                             int *response_code) {
 | 
				
			||||||
 | 
					  if (response_code) {
 | 
				
			||||||
 | 
					    *response_code = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // TODO(bryner): support non-ASCII parameter names
 | 
				
			||||||
 | 
					  if (!CheckParameters(parameters)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Break up the URL and make sure we can handle it
 | 
				
			||||||
 | 
					  wchar_t scheme[16], host[256], path[256];
 | 
				
			||||||
 | 
					  URL_COMPONENTS components;
 | 
				
			||||||
 | 
					  memset(&components, 0, sizeof(components));
 | 
				
			||||||
 | 
					  components.dwStructSize = sizeof(components);
 | 
				
			||||||
 | 
					  components.lpszScheme = scheme;
 | 
				
			||||||
 | 
					  components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
 | 
				
			||||||
 | 
					  components.lpszHostName = host;
 | 
				
			||||||
 | 
					  components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
 | 
				
			||||||
 | 
					  components.lpszUrlPath = path;
 | 
				
			||||||
 | 
					  components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
 | 
				
			||||||
 | 
					  if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),
 | 
				
			||||||
 | 
					                        0, &components)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  bool secure = false;
 | 
				
			||||||
 | 
					  if (wcscmp(scheme, L"https") == 0) {
 | 
				
			||||||
 | 
					    secure = true;
 | 
				
			||||||
 | 
					  } else if (wcscmp(scheme, L"http") != 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AutoInternetHandle internet(InternetOpen(kUserAgent,
 | 
				
			||||||
 | 
					                                           INTERNET_OPEN_TYPE_PRECONFIG,
 | 
				
			||||||
 | 
					                                           NULL,  // proxy name
 | 
				
			||||||
 | 
					                                           NULL,  // proxy bypass
 | 
				
			||||||
 | 
					                                           0));   // flags
 | 
				
			||||||
 | 
					  if (!internet.get()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AutoInternetHandle connection(InternetConnect(internet.get(),
 | 
				
			||||||
 | 
					                                                host,
 | 
				
			||||||
 | 
					                                                components.nPort,
 | 
				
			||||||
 | 
					                                                NULL,    // user name
 | 
				
			||||||
 | 
					                                                NULL,    // password
 | 
				
			||||||
 | 
					                                                INTERNET_SERVICE_HTTP,
 | 
				
			||||||
 | 
					                                                0,       // flags
 | 
				
			||||||
 | 
					                                                NULL));  // context
 | 
				
			||||||
 | 
					  if (!connection.get()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;
 | 
				
			||||||
 | 
					  http_open_flags |= INTERNET_FLAG_NO_COOKIES;
 | 
				
			||||||
 | 
					  AutoInternetHandle request(HttpOpenRequest(connection.get(),
 | 
				
			||||||
 | 
					                                             L"POST",
 | 
				
			||||||
 | 
					                                             path,
 | 
				
			||||||
 | 
					                                             NULL,    // version
 | 
				
			||||||
 | 
					                                             NULL,    // referer
 | 
				
			||||||
 | 
					                                             NULL,    // agent type
 | 
				
			||||||
 | 
					                                             http_open_flags,
 | 
				
			||||||
 | 
					                                             NULL));  // context
 | 
				
			||||||
 | 
					  if (!request.get()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wstring boundary = GenerateMultipartBoundary();
 | 
				
			||||||
 | 
					  wstring content_type_header = GenerateRequestHeader(boundary);
 | 
				
			||||||
 | 
					  HttpAddRequestHeaders(request.get(),
 | 
				
			||||||
 | 
					                        content_type_header.c_str(),
 | 
				
			||||||
 | 
					                        static_cast<DWORD>(-1),
 | 
				
			||||||
 | 
					                        HTTP_ADDREQ_FLAG_ADD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string request_body;
 | 
				
			||||||
 | 
					  if (!GenerateRequestBody(parameters, upload_file,
 | 
				
			||||||
 | 
					                           file_part_name, boundary, &request_body)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout) {
 | 
				
			||||||
 | 
					    if (!InternetSetOption(request.get(),
 | 
				
			||||||
 | 
					                           INTERNET_OPTION_SEND_TIMEOUT,
 | 
				
			||||||
 | 
					                           timeout,
 | 
				
			||||||
 | 
					                           sizeof(*timeout))) {
 | 
				
			||||||
 | 
					      fwprintf(stderr, L"Could not unset send timeout, continuing...\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!InternetSetOption(request.get(),
 | 
				
			||||||
 | 
					                           INTERNET_OPTION_RECEIVE_TIMEOUT,
 | 
				
			||||||
 | 
					                           timeout,
 | 
				
			||||||
 | 
					                           sizeof(*timeout))) {
 | 
				
			||||||
 | 
					      fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if (!HttpSendRequest(request.get(), NULL, 0,
 | 
				
			||||||
 | 
					                       const_cast<char *>(request_body.data()),
 | 
				
			||||||
 | 
					                       static_cast<DWORD>(request_body.size()))) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The server indicates a successful upload with HTTP status 200.
 | 
				
			||||||
 | 
					  wchar_t http_status[4];
 | 
				
			||||||
 | 
					  DWORD http_status_size = sizeof(http_status);
 | 
				
			||||||
 | 
					  if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,
 | 
				
			||||||
 | 
					                     static_cast<LPVOID>(&http_status), &http_status_size,
 | 
				
			||||||
 | 
					                     0)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int http_response = wcstol(http_status, NULL, 10);
 | 
				
			||||||
 | 
					  if (response_code) {
 | 
				
			||||||
 | 
					    *response_code = http_response;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool result = (http_response == 200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (result) {
 | 
				
			||||||
 | 
					    result = ReadResponse(request.get(), response_body);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {
 | 
				
			||||||
 | 
					  bool has_content_length_header = false;
 | 
				
			||||||
 | 
					  wchar_t content_length[32];
 | 
				
			||||||
 | 
					  DWORD content_length_size = sizeof(content_length);
 | 
				
			||||||
 | 
					  DWORD claimed_size = 0;
 | 
				
			||||||
 | 
					  string response_body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,
 | 
				
			||||||
 | 
					                    static_cast<LPVOID>(&content_length),
 | 
				
			||||||
 | 
					                    &content_length_size, 0)) {
 | 
				
			||||||
 | 
					    has_content_length_header = true;
 | 
				
			||||||
 | 
					    claimed_size = wcstol(content_length, NULL, 10);
 | 
				
			||||||
 | 
					    response_body.reserve(claimed_size);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DWORD bytes_available;
 | 
				
			||||||
 | 
					  DWORD total_read = 0;
 | 
				
			||||||
 | 
					  BOOL return_code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (((return_code = InternetQueryDataAvailable(request, &bytes_available,
 | 
				
			||||||
 | 
						  0, 0)) != 0) && bytes_available > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vector<char> response_buffer(bytes_available);
 | 
				
			||||||
 | 
					    DWORD size_read;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return_code = InternetReadFile(request,
 | 
				
			||||||
 | 
					                                   &response_buffer[0],
 | 
				
			||||||
 | 
					                                   bytes_available, &size_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (return_code && size_read > 0) {
 | 
				
			||||||
 | 
					      total_read += size_read;
 | 
				
			||||||
 | 
					      response_body.append(&response_buffer[0], size_read);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool succeeded = return_code && (!has_content_length_header ||
 | 
				
			||||||
 | 
					                                   (total_read == claimed_size));
 | 
				
			||||||
 | 
					  if (succeeded && response) {
 | 
				
			||||||
 | 
					    *response = UTF8ToWide(response_body);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return succeeded;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring HTTPUpload::GenerateMultipartBoundary() {
 | 
				
			||||||
 | 
					  // The boundary has 27 '-' characters followed by 16 hex digits
 | 
				
			||||||
 | 
					  static const wchar_t kBoundaryPrefix[] = L"---------------------------";
 | 
				
			||||||
 | 
					  static const int kBoundaryLength = 27 + 16 + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Generate some random numbers to fill out the boundary
 | 
				
			||||||
 | 
					  int r0 = rand();
 | 
				
			||||||
 | 
					  int r1 = rand();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wchar_t temp[kBoundaryLength];
 | 
				
			||||||
 | 
					  swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // remove when VC++7.1 is no longer supported
 | 
				
			||||||
 | 
					  temp[kBoundaryLength - 1] = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return wstring(temp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
 | 
				
			||||||
 | 
					  wstring header = L"Content-Type: multipart/form-data; boundary=";
 | 
				
			||||||
 | 
					  header += boundary;
 | 
				
			||||||
 | 
					  return header;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> ¶meters,
 | 
				
			||||||
 | 
					                                     const wstring &upload_file,
 | 
				
			||||||
 | 
					                                     const wstring &file_part_name,
 | 
				
			||||||
 | 
					                                     const wstring &boundary,
 | 
				
			||||||
 | 
					                                     string *request_body) {
 | 
				
			||||||
 | 
					  vector<char> contents;
 | 
				
			||||||
 | 
					  if (!GetFileContents(upload_file, &contents)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string boundary_str = WideToUTF8(boundary);
 | 
				
			||||||
 | 
					  if (boundary_str.empty()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request_body->clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Append each of the parameter pairs as a form-data part
 | 
				
			||||||
 | 
					  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
 | 
				
			||||||
 | 
					       pos != parameters.end(); ++pos) {
 | 
				
			||||||
 | 
					    request_body->append("--" + boundary_str + "\r\n");
 | 
				
			||||||
 | 
					    request_body->append("Content-Disposition: form-data; name=\"" +
 | 
				
			||||||
 | 
					                         WideToUTF8(pos->first) + "\"\r\n\r\n" +
 | 
				
			||||||
 | 
					                         WideToUTF8(pos->second) + "\r\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Now append the upload file as a binary (octet-stream) part
 | 
				
			||||||
 | 
					  string filename_utf8 = WideToUTF8(upload_file);
 | 
				
			||||||
 | 
					  if (filename_utf8.empty()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string file_part_name_utf8 = WideToUTF8(file_part_name);
 | 
				
			||||||
 | 
					  if (file_part_name_utf8.empty()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request_body->append("--" + boundary_str + "\r\n");
 | 
				
			||||||
 | 
					  request_body->append("Content-Disposition: form-data; "
 | 
				
			||||||
 | 
					                       "name=\"" + file_part_name_utf8 + "\"; "
 | 
				
			||||||
 | 
					                       "filename=\"" + filename_utf8 + "\"\r\n");
 | 
				
			||||||
 | 
					  request_body->append("Content-Type: application/octet-stream\r\n");
 | 
				
			||||||
 | 
					  request_body->append("\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!contents.empty()) {
 | 
				
			||||||
 | 
					      request_body->append(&(contents[0]), contents.size());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  request_body->append("\r\n");
 | 
				
			||||||
 | 
					  request_body->append("--" + boundary_str + "--\r\n");
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool HTTPUpload::GetFileContents(const wstring &filename,
 | 
				
			||||||
 | 
					                                 vector<char> *contents) {
 | 
				
			||||||
 | 
					  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
 | 
				
			||||||
 | 
					  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
 | 
				
			||||||
 | 
					  // later, _wfopen has been deprecated in favor of _wfopen_s, which does
 | 
				
			||||||
 | 
					  // not exist in earlier versions, so let the ifstream open the file itself.
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  ifstream file;
 | 
				
			||||||
 | 
					  file.open(filename.c_str(), ios::binary);
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  ifstream file(_wfopen(filename.c_str(), L"rb"));
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  if (file.is_open()) {
 | 
				
			||||||
 | 
					    file.seekg(0, ios::end);
 | 
				
			||||||
 | 
					    std::streamoff length = file.tellg();
 | 
				
			||||||
 | 
					    contents->resize(length);
 | 
				
			||||||
 | 
					    if (length != 0) {
 | 
				
			||||||
 | 
					      file.seekg(0, ios::beg);
 | 
				
			||||||
 | 
					      file.read(&((*contents)[0]), length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    file.close();
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring HTTPUpload::UTF8ToWide(const string &utf8) {
 | 
				
			||||||
 | 
					  if (utf8.length() == 0) {
 | 
				
			||||||
 | 
					    return wstring();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // compute the length of the buffer we'll need
 | 
				
			||||||
 | 
					  int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (charcount == 0) {
 | 
				
			||||||
 | 
					    return wstring();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // convert
 | 
				
			||||||
 | 
					  wchar_t* buf = new wchar_t[charcount];
 | 
				
			||||||
 | 
					  MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);
 | 
				
			||||||
 | 
					  wstring result(buf);
 | 
				
			||||||
 | 
					  delete[] buf;
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					string HTTPUpload::WideToUTF8(const wstring &wide) {
 | 
				
			||||||
 | 
					  if (wide.length() == 0) {
 | 
				
			||||||
 | 
					    return string();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // compute the length of the buffer we'll need
 | 
				
			||||||
 | 
					  int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1,
 | 
				
			||||||
 | 
					                                      NULL, 0, NULL, NULL);
 | 
				
			||||||
 | 
					  if (charcount == 0) {
 | 
				
			||||||
 | 
					    return string();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // convert
 | 
				
			||||||
 | 
					  char *buf = new char[charcount];
 | 
				
			||||||
 | 
					  WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount,
 | 
				
			||||||
 | 
					                      NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string result(buf);
 | 
				
			||||||
 | 
					  delete[] buf;
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool HTTPUpload::CheckParameters(const map<wstring, wstring> ¶meters) {
 | 
				
			||||||
 | 
					  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
 | 
				
			||||||
 | 
					       pos != parameters.end(); ++pos) {
 | 
				
			||||||
 | 
					    const wstring &str = pos->first;
 | 
				
			||||||
 | 
					    if (str.size() == 0) {
 | 
				
			||||||
 | 
					      return false;  // disallow empty parameter names
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (unsigned int i = 0; i < str.size(); ++i) {
 | 
				
			||||||
 | 
					      wchar_t c = str[i];
 | 
				
			||||||
 | 
					      if (c < 32 || c == '"' || c > 127) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										126
									
								
								google-breakpad/src/common/windows/http_upload.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								google-breakpad/src/common/windows/http_upload.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
 | 
				
			||||||
 | 
					// request using wininet.  It currently supports requests that contain
 | 
				
			||||||
 | 
					// a set of string parameters (key/value pairs), and a file to upload.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H__
 | 
				
			||||||
 | 
					#define COMMON_WINDOWS_HTTP_UPLOAD_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning( push )
 | 
				
			||||||
 | 
					// Disable exception handler warnings.
 | 
				
			||||||
 | 
					#pragma warning( disable : 4530 ) 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#include <WinInet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using std::string;
 | 
				
			||||||
 | 
					using std::wstring;
 | 
				
			||||||
 | 
					using std::map;
 | 
				
			||||||
 | 
					using std::vector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HTTPUpload {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  // Sends the given set of parameters, along with the contents of
 | 
				
			||||||
 | 
					  // upload_file, as a multipart POST request to the given URL.
 | 
				
			||||||
 | 
					  // file_part_name contains the name of the file part of the request
 | 
				
			||||||
 | 
					  // (i.e. it corresponds to the name= attribute on an <input type="file">.
 | 
				
			||||||
 | 
					  // Parameter names must contain only printable ASCII characters,
 | 
				
			||||||
 | 
					  // and may not contain a quote (") character.
 | 
				
			||||||
 | 
					  // Only HTTP(S) URLs are currently supported.  Returns true on success.
 | 
				
			||||||
 | 
					  // If the request is successful and response_body is non-NULL,
 | 
				
			||||||
 | 
					  // the response body will be returned in response_body.
 | 
				
			||||||
 | 
					  // If response_code is non-NULL, it will be set to the HTTP response code
 | 
				
			||||||
 | 
					  // received (or 0 if the request failed before getting an HTTP response).
 | 
				
			||||||
 | 
					  static bool SendRequest(const wstring &url,
 | 
				
			||||||
 | 
					                          const map<wstring, wstring> ¶meters,
 | 
				
			||||||
 | 
					                          const wstring &upload_file,
 | 
				
			||||||
 | 
					                          const wstring &file_part_name,
 | 
				
			||||||
 | 
					                          int *timeout,
 | 
				
			||||||
 | 
					                          wstring *response_body,
 | 
				
			||||||
 | 
					                          int *response_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  class AutoInternetHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Retrieves the HTTP response.  If NULL is passed in for response,
 | 
				
			||||||
 | 
					  // this merely checks (via the return value) that we were successfully
 | 
				
			||||||
 | 
					  // able to retrieve exactly as many bytes of content in the response as
 | 
				
			||||||
 | 
					  // were specified in the Content-Length header.
 | 
				
			||||||
 | 
					  static bool HTTPUpload::ReadResponse(HINTERNET request, wstring* response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Generates a new multipart boundary for a POST request
 | 
				
			||||||
 | 
					  static wstring GenerateMultipartBoundary();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Generates a HTTP request header for a multipart form submit.
 | 
				
			||||||
 | 
					  static wstring GenerateRequestHeader(const wstring &boundary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Given a set of parameters, an upload filename, and a file part name,
 | 
				
			||||||
 | 
					  // generates a multipart request body string with these parameters
 | 
				
			||||||
 | 
					  // and minidump contents.  Returns true on success.
 | 
				
			||||||
 | 
					  static bool GenerateRequestBody(const map<wstring, wstring> ¶meters,
 | 
				
			||||||
 | 
					                                  const wstring &upload_file,
 | 
				
			||||||
 | 
					                                  const wstring &file_part_name,
 | 
				
			||||||
 | 
					                                  const wstring &boundary,
 | 
				
			||||||
 | 
					                                  string *request_body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Fills the supplied vector with the contents of filename.
 | 
				
			||||||
 | 
					  static bool GetFileContents(const wstring &filename, vector<char> *contents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Converts a UTF8 string to UTF16.
 | 
				
			||||||
 | 
					  static wstring UTF8ToWide(const string &utf8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Converts a UTF16 string to UTF8.
 | 
				
			||||||
 | 
					  static string WideToUTF8(const wstring &wide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Checks that the given list of parameters has only printable
 | 
				
			||||||
 | 
					  // ASCII characters in the parameter name, and does not contain
 | 
				
			||||||
 | 
					  // any quote (") characters.  Returns true if so.
 | 
				
			||||||
 | 
					  static bool CheckParameters(const map<wstring, wstring> ¶meters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // No instances of this class should be created.
 | 
				
			||||||
 | 
					  // Disallow all constructors, destructors, and operator=.
 | 
				
			||||||
 | 
					  HTTPUpload();
 | 
				
			||||||
 | 
					  explicit HTTPUpload(const HTTPUpload &);
 | 
				
			||||||
 | 
					  void operator=(const HTTPUpload &);
 | 
				
			||||||
 | 
					  ~HTTPUpload();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning( pop )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // COMMON_WINDOWS_HTTP_UPLOAD_H__
 | 
				
			||||||
							
								
								
									
										694
									
								
								google-breakpad/src/common/windows/omap.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								google-breakpad/src/common/windows/omap.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,694 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This contains a suite of tools for transforming symbol information when
 | 
				
			||||||
 | 
					// when that information has been extracted from a PDB containing OMAP
 | 
				
			||||||
 | 
					// information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OMAP information is a lightweight description of a mapping between two
 | 
				
			||||||
 | 
					// address spaces. It consists of two streams, each of them a vector 2-tuples.
 | 
				
			||||||
 | 
					// The OMAPTO stream contains tuples of the form
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   (RVA in transformed image, RVA in original image)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// while the OMAPFROM stream contains tuples of the form
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   (RVA in original image, RVA in transformed image)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The entries in each vector are sorted by the first value of the tuple, and
 | 
				
			||||||
 | 
					// the lengths associated with a mapping are implicit as the distance between
 | 
				
			||||||
 | 
					// two successive addresses in the vector.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Consider a trivial 10-byte function described by the following symbol:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   Function: RVA 0x00001000, length 10, "foo"
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Now consider the same function, but with 5-bytes of instrumentation injected
 | 
				
			||||||
 | 
					// at offset 5. The OMAP streams describing this would look like:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   OMAPTO  :  [ [0x00001000, 0x00001000],
 | 
				
			||||||
 | 
					//                [0x00001005, 0xFFFFFFFF],
 | 
				
			||||||
 | 
					//                [0x0000100a, 0x00001005] ]
 | 
				
			||||||
 | 
					//   OMAPFROM:  [ [0x00001000, 0x00001000],
 | 
				
			||||||
 | 
					//                [0x00001005, 0x0000100a] ]
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// In this case the injected code has been marked as not originating in the
 | 
				
			||||||
 | 
					// source image, and thus it will have no symbol information at all. However,
 | 
				
			||||||
 | 
					// the injected code may also be associated with an original address range;
 | 
				
			||||||
 | 
					// for example, when prepending instrumentation to a basic block the
 | 
				
			||||||
 | 
					// instrumentation can be labelled as originating from the same source BB such
 | 
				
			||||||
 | 
					// that symbol resolution will still find the appropriate source code line
 | 
				
			||||||
 | 
					// number. In this case the OMAP stream would look like:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   OMAPTO  :  [ [0x00001000, 0x00001000],
 | 
				
			||||||
 | 
					//                [0x00001005, 0x00001005],
 | 
				
			||||||
 | 
					//                [0x0000100a, 0x00001005] ]
 | 
				
			||||||
 | 
					//   OMAPFROM:  [ [0x00001000, 0x00001000],
 | 
				
			||||||
 | 
					//                [0x00001005, 0x0000100a] ]
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the
 | 
				
			||||||
 | 
					// instrumented image. It would first run this through the OMAPTO table and
 | 
				
			||||||
 | 
					// translate that address to 0x00001005. It would then lookup the symbol
 | 
				
			||||||
 | 
					// at that address and return the symbol for the function "foo". This is the
 | 
				
			||||||
 | 
					// correct result.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// However, if we query DIA for the length and address of the symbol it will
 | 
				
			||||||
 | 
					// tell us that it has length 10 and is at RVA 0x00001000. The location is
 | 
				
			||||||
 | 
					// correct, but the length doesn't take into account the 5-bytes of injected
 | 
				
			||||||
 | 
					// code. Symbol resolution works (starting from an instrumented address,
 | 
				
			||||||
 | 
					// mapping to an original address, and looking up a symbol), but the symbol
 | 
				
			||||||
 | 
					// metadata is incorrect.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If we dump the symbols using DIA they will have their addresses
 | 
				
			||||||
 | 
					// appropriately transformed and reflect positions in the instrumented image.
 | 
				
			||||||
 | 
					// However, if we try to do a lookup using those symbols resolution can fail.
 | 
				
			||||||
 | 
					// For example, the address 0x0000100a will not map to the symbol for "foo",
 | 
				
			||||||
 | 
					// because DIA tells us it is at location 0x00001000 (correct) with length
 | 
				
			||||||
 | 
					// 10 (incorrect). The problem is one of order of operations: in this case
 | 
				
			||||||
 | 
					// we're attempting symbol resolution by looking up an instrumented address
 | 
				
			||||||
 | 
					// in the table of translated symbols.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// One way to handle this is to dump the OMAP information as part of the
 | 
				
			||||||
 | 
					// breakpad symbols. This requires the rest of the toolchain to be aware of
 | 
				
			||||||
 | 
					// OMAP information and to use it when present prior to performing lookup. The
 | 
				
			||||||
 | 
					// other option is to properly transform the symbols (updating length as well as
 | 
				
			||||||
 | 
					// position) so that resolution will work as expected for translated addresses.
 | 
				
			||||||
 | 
					// This is transparent to the rest of the toolchain.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/omap.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atlbase.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/dia_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO";
 | 
				
			||||||
 | 
					static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Dependending on where this is used in breakpad we sometimes get min/max from
 | 
				
			||||||
 | 
					// windef, and other times from algorithm. To get around this we simply
 | 
				
			||||||
 | 
					// define our own min/max functions.
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// It makes things more readable to have two different OMAP types. We cast
 | 
				
			||||||
 | 
					// normal OMAPs into these. They must be the same size as the OMAP structure
 | 
				
			||||||
 | 
					// for this to work, hence the static asserts.
 | 
				
			||||||
 | 
					struct OmapOrigToTran {
 | 
				
			||||||
 | 
					  DWORD rva_original;
 | 
				
			||||||
 | 
					  DWORD rva_transformed;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					struct OmapTranToOrig {
 | 
				
			||||||
 | 
					  DWORD rva_transformed;
 | 
				
			||||||
 | 
					  DWORD rva_original;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP),
 | 
				
			||||||
 | 
					              "OmapOrigToTran must have same size as OMAP.");
 | 
				
			||||||
 | 
					static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP),
 | 
				
			||||||
 | 
					              "OmapTranToOrig must have same size as OMAP.");
 | 
				
			||||||
 | 
					typedef std::vector<OmapOrigToTran> OmapFromTable;
 | 
				
			||||||
 | 
					typedef std::vector<OmapTranToOrig> OmapToTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used for sorting and searching through a Mapping.
 | 
				
			||||||
 | 
					bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) {
 | 
				
			||||||
 | 
					  if (lhs.rva_original < rhs.rva_original)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  if (lhs.rva_original > rhs.rva_original)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  return lhs.length < rhs.length;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) {
 | 
				
			||||||
 | 
					  if (lhs.rva_transformed < rhs.rva_transformed)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  if (lhs.rva_transformed > rhs.rva_transformed)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  return lhs.length < rhs.length;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used for searching through the EndpointIndexMap.
 | 
				
			||||||
 | 
					bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) {
 | 
				
			||||||
 | 
					  return ei1.endpoint < ei2.endpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Finds the debug stream with the given |name| in the given |session|, and
 | 
				
			||||||
 | 
					// populates |table| with its contents. Casts the data directly into OMAP
 | 
				
			||||||
 | 
					// structs.
 | 
				
			||||||
 | 
					bool FindAndLoadOmapTable(const wchar_t* name,
 | 
				
			||||||
 | 
					                          IDiaSession* session,
 | 
				
			||||||
 | 
					                          OmapTable* table) {
 | 
				
			||||||
 | 
					  assert(name != NULL);
 | 
				
			||||||
 | 
					  assert(session != NULL);
 | 
				
			||||||
 | 
					  assert(table != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CComPtr<IDiaEnumDebugStreamData> stream;
 | 
				
			||||||
 | 
					  if (!FindDebugStream(name, session, &stream))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  assert(stream.p != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LONG count = 0;
 | 
				
			||||||
 | 
					  if (FAILED(stream->get_Count(&count))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream "
 | 
				
			||||||
 | 
					                    "\"%ws\"\n", name);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get the length of the stream in bytes.
 | 
				
			||||||
 | 
					  DWORD bytes_read = 0;
 | 
				
			||||||
 | 
					  ULONG count_read = 0;
 | 
				
			||||||
 | 
					  if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading "
 | 
				
			||||||
 | 
					                    "length of stream \"%ws\"\n", name);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ensure it's consistent with the OMAP data type.
 | 
				
			||||||
 | 
					  DWORD bytes_expected = count * sizeof(OmapTable::value_type);
 | 
				
			||||||
 | 
					  if (count * sizeof(OmapTable::value_type) != bytes_read) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Read the table.
 | 
				
			||||||
 | 
					  table->resize(count);
 | 
				
			||||||
 | 
					  bytes_read = 0;
 | 
				
			||||||
 | 
					  count_read = 0;
 | 
				
			||||||
 | 
					  if (FAILED(stream->Next(count, bytes_expected, &bytes_read,
 | 
				
			||||||
 | 
					                          reinterpret_cast<BYTE*>(&table->at(0)),
 | 
				
			||||||
 | 
					                          &count_read))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading "
 | 
				
			||||||
 | 
					                    "data from stream \"%ws\"\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This determines the original image length by looking through the segment
 | 
				
			||||||
 | 
					// table.
 | 
				
			||||||
 | 
					bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) {
 | 
				
			||||||
 | 
					  assert(session != NULL);
 | 
				
			||||||
 | 
					  assert(image_length != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CComPtr<IDiaEnumSegments> enum_segments;
 | 
				
			||||||
 | 
					  if (!FindTable(session, &enum_segments))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  assert(enum_segments.p != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DWORD temp_image_length = 0;
 | 
				
			||||||
 | 
					  CComPtr<IDiaSegment> segment;
 | 
				
			||||||
 | 
					  ULONG fetched = 0;
 | 
				
			||||||
 | 
					  while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) &&
 | 
				
			||||||
 | 
					         fetched == 1) {
 | 
				
			||||||
 | 
					    assert(segment.p != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DWORD rva = 0;
 | 
				
			||||||
 | 
					    DWORD length = 0;
 | 
				
			||||||
 | 
					    DWORD frame = 0;
 | 
				
			||||||
 | 
					    if (FAILED(segment->get_relativeVirtualAddress(&rva)) ||
 | 
				
			||||||
 | 
					        FAILED(segment->get_length(&length)) ||
 | 
				
			||||||
 | 
					        FAILED(segment->get_frame(&frame))) {
 | 
				
			||||||
 | 
					      fprintf(stderr, "Failed to get basic properties for IDiaSegment\n");
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (frame > 0) {
 | 
				
			||||||
 | 
					      DWORD segment_end = rva + length;
 | 
				
			||||||
 | 
					      if (segment_end > temp_image_length)
 | 
				
			||||||
 | 
					        temp_image_length = segment_end;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    segment.Release();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *image_length = temp_image_length;
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Detects regions of the original image that have been removed in the
 | 
				
			||||||
 | 
					// transformed image, and sets the 'removed' property on all mapped ranges
 | 
				
			||||||
 | 
					// immediately preceding a gap. The mapped ranges must be sorted by
 | 
				
			||||||
 | 
					// 'rva_original'.
 | 
				
			||||||
 | 
					void FillInRemovedLengths(Mapping* mapping) {
 | 
				
			||||||
 | 
					  assert(mapping != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Find and fill gaps. We do this with two sweeps. We first sweep forward
 | 
				
			||||||
 | 
					  // looking for gaps. When we identify a gap we then sweep forward with a
 | 
				
			||||||
 | 
					  // second scan and set the 'removed' property for any intervals that
 | 
				
			||||||
 | 
					  // immediately precede the gap.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Gaps are typically between two successive intervals, but not always:
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  //   Range 1: ---------------
 | 
				
			||||||
 | 
					  //   Range 2:     -------
 | 
				
			||||||
 | 
					  //   Range 3:                      -------------
 | 
				
			||||||
 | 
					  //   Gap    :                ******
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // In the above example the gap is between range 1 and range 3. A forward
 | 
				
			||||||
 | 
					  // sweep finds the gap, and a second forward sweep identifies that range 1
 | 
				
			||||||
 | 
					  // immediately precedes the gap and sets its 'removed' property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t fill = 0;
 | 
				
			||||||
 | 
					  DWORD rva_front = 0;
 | 
				
			||||||
 | 
					  for (size_t find = 0; find < mapping->size(); ++find) {
 | 
				
			||||||
 | 
					#ifndef NDEBUG
 | 
				
			||||||
 | 
					    // We expect the mapped ranges to be sorted by 'rva_original'.
 | 
				
			||||||
 | 
					    if (find > 0) {
 | 
				
			||||||
 | 
					      assert(mapping->at(find - 1).rva_original <=
 | 
				
			||||||
 | 
					                 mapping->at(find).rva_original);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rva_front < mapping->at(find).rva_original) {
 | 
				
			||||||
 | 
					      // We've found a gap. Fill it in by setting the 'removed' property for
 | 
				
			||||||
 | 
					      // any affected intervals.
 | 
				
			||||||
 | 
					      DWORD removed = mapping->at(find).rva_original - rva_front;
 | 
				
			||||||
 | 
					      for (; fill < find; ++fill) {
 | 
				
			||||||
 | 
					        if (mapping->at(fill).rva_original + mapping->at(fill).length !=
 | 
				
			||||||
 | 
					                rva_front) {
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // This interval ends right where the gap starts. It needs to have its
 | 
				
			||||||
 | 
					        // 'removed' information filled in.
 | 
				
			||||||
 | 
					        mapping->at(fill).removed = removed;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Advance the front that indicates the covered portion of the image.
 | 
				
			||||||
 | 
					    rva_front = mapping->at(find).rva_original + mapping->at(find).length;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Builds a unified view of the mapping between the original and transformed
 | 
				
			||||||
 | 
					// image space by merging OMAPTO and OMAPFROM data.
 | 
				
			||||||
 | 
					void BuildMapping(const OmapData& omap_data, Mapping* mapping) {
 | 
				
			||||||
 | 
					  assert(mapping != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mapping->clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (omap_data.omap_from.empty() || omap_data.omap_to.empty())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The names 'omap_to' and 'omap_from' are awfully confusing, so we make
 | 
				
			||||||
 | 
					  // ourselves more explicit here. This cast is only safe because the underlying
 | 
				
			||||||
 | 
					  // types have the exact same size.
 | 
				
			||||||
 | 
					  const OmapToTable& tran2orig =
 | 
				
			||||||
 | 
					      reinterpret_cast<const OmapToTable&>(omap_data.omap_to);
 | 
				
			||||||
 | 
					  const OmapFromTable& orig2tran = reinterpret_cast<const OmapFromTable&>(
 | 
				
			||||||
 | 
					      omap_data.omap_from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle the range of data at the beginning of the image. This is not usually
 | 
				
			||||||
 | 
					  // specified by the OMAP data.
 | 
				
			||||||
 | 
					  if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) {
 | 
				
			||||||
 | 
					    DWORD header_transformed = tran2orig[0].rva_transformed;
 | 
				
			||||||
 | 
					    DWORD header_original = orig2tran[0].rva_original;
 | 
				
			||||||
 | 
					    DWORD header = Min(header_transformed, header_original);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MappedRange mr = {};
 | 
				
			||||||
 | 
					    mr.length = header;
 | 
				
			||||||
 | 
					    mr.injected = header_transformed - header;
 | 
				
			||||||
 | 
					    mr.removed = header_original - header;
 | 
				
			||||||
 | 
					    mapping->push_back(mr);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Convert the implied lengths to explicit lengths, and infer which content
 | 
				
			||||||
 | 
					  // has been injected into the transformed image. Injected content is inferred
 | 
				
			||||||
 | 
					  // as regions of the transformed address space that does not map back to
 | 
				
			||||||
 | 
					  // known valid content in the original image.
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < tran2orig.size(); ++i) {
 | 
				
			||||||
 | 
					    const OmapTranToOrig& o1 = tran2orig[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This maps to content that is outside the original image, thus it
 | 
				
			||||||
 | 
					    // describes injected content. We can skip this entry.
 | 
				
			||||||
 | 
					    if (o1.rva_original >= omap_data.length_original)
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Calculate the length of the current OMAP entry. This is implicit as the
 | 
				
			||||||
 | 
					    // distance between successive |rva| values, capped at the end of the
 | 
				
			||||||
 | 
					    // original image.
 | 
				
			||||||
 | 
					    DWORD length = 0;
 | 
				
			||||||
 | 
					    if (i + 1 < tran2orig.size()) {
 | 
				
			||||||
 | 
					      const OmapTranToOrig& o2 = tran2orig[i + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // We expect the table to be sorted by rva_transformed.
 | 
				
			||||||
 | 
					      assert(o1.rva_transformed <= o2.rva_transformed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      length = o2.rva_transformed - o1.rva_transformed;
 | 
				
			||||||
 | 
					      if (o1.rva_original + length > omap_data.length_original) {
 | 
				
			||||||
 | 
					        length = omap_data.length_original - o1.rva_original;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      length = omap_data.length_original - o1.rva_original;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Zero-length entries don't describe anything and can be ignored.
 | 
				
			||||||
 | 
					    if (length == 0)
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Any gaps in the transformed address-space are due to injected content.
 | 
				
			||||||
 | 
					    if (!mapping->empty()) {
 | 
				
			||||||
 | 
					      MappedRange& prev_mr = mapping->back();
 | 
				
			||||||
 | 
					      prev_mr.injected += o1.rva_transformed -
 | 
				
			||||||
 | 
					          (prev_mr.rva_transformed + prev_mr.length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MappedRange mr = {};
 | 
				
			||||||
 | 
					    mr.rva_original = o1.rva_original;
 | 
				
			||||||
 | 
					    mr.rva_transformed = o1.rva_transformed;
 | 
				
			||||||
 | 
					    mr.length = length;
 | 
				
			||||||
 | 
					    mapping->push_back(mr);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sort based on the original image addresses.
 | 
				
			||||||
 | 
					  std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Fill in the 'removed' lengths by looking for gaps in the coverage of the
 | 
				
			||||||
 | 
					  // original address space.
 | 
				
			||||||
 | 
					  FillInRemovedLengths(mapping);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BuildEndpointIndexMap(ImageMap* image_map) {
 | 
				
			||||||
 | 
					  assert(image_map != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (image_map->mapping.size() == 0)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Mapping& mapping = image_map->mapping;
 | 
				
			||||||
 | 
					  EndpointIndexMap& eim = image_map->endpoint_index_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get the unique set of interval endpoints.
 | 
				
			||||||
 | 
					  std::set<DWORD> endpoints;
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < mapping.size(); ++i) {
 | 
				
			||||||
 | 
					    endpoints.insert(mapping[i].rva_original);
 | 
				
			||||||
 | 
					    endpoints.insert(mapping[i].rva_original +
 | 
				
			||||||
 | 
					                         mapping[i].length +
 | 
				
			||||||
 | 
					                         mapping[i].removed);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Use the endpoints to initialize the secondary search structure for the
 | 
				
			||||||
 | 
					  // mapping.
 | 
				
			||||||
 | 
					  eim.resize(endpoints.size());
 | 
				
			||||||
 | 
					  std::set<DWORD>::const_iterator it = endpoints.begin();
 | 
				
			||||||
 | 
					  for (size_t i = 0; it != endpoints.end(); ++it, ++i) {
 | 
				
			||||||
 | 
					    eim[i].endpoint = *it;
 | 
				
			||||||
 | 
					    eim[i].index = mapping.size();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // For each endpoint we want the smallest index of any interval containing
 | 
				
			||||||
 | 
					  // it. We iterate over the intervals and update the indices associated with
 | 
				
			||||||
 | 
					  // each interval endpoint contained in the current interval. In the general
 | 
				
			||||||
 | 
					  // case of an arbitrary set of intervals this is O(n^2), but the structure of
 | 
				
			||||||
 | 
					  // OMAP data makes this O(n).
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < mapping.size(); ++i) {
 | 
				
			||||||
 | 
					    EndpointIndex ei1 = { mapping[i].rva_original, 0 };
 | 
				
			||||||
 | 
					    EndpointIndexMap::iterator it1 = std::lower_bound(
 | 
				
			||||||
 | 
					        eim.begin(), eim.end(), ei1, EndpointIndexLess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length +
 | 
				
			||||||
 | 
					                              mapping[i].removed, 0 };
 | 
				
			||||||
 | 
					    EndpointIndexMap::iterator it2 = std::lower_bound(
 | 
				
			||||||
 | 
					        eim.begin(), eim.end(), ei2, EndpointIndexLess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (; it1 != it2; ++it1)
 | 
				
			||||||
 | 
					      it1->index = Min(i, it1->index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Clips the given mapped range.
 | 
				
			||||||
 | 
					void ClipMappedRangeOriginal(const AddressRange& clip_range,
 | 
				
			||||||
 | 
					                             MappedRange* mapped_range) {
 | 
				
			||||||
 | 
					  assert(mapped_range != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The clipping range is entirely outside of the mapped range.
 | 
				
			||||||
 | 
					  if (clip_range.end() <= mapped_range->rva_original ||
 | 
				
			||||||
 | 
					      mapped_range->rva_original + mapped_range->length +
 | 
				
			||||||
 | 
					          mapped_range->removed <= clip_range.rva) {
 | 
				
			||||||
 | 
					    mapped_range->length = 0;
 | 
				
			||||||
 | 
					    mapped_range->injected = 0;
 | 
				
			||||||
 | 
					    mapped_range->removed = 0;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Clip the left side.
 | 
				
			||||||
 | 
					  if (mapped_range->rva_original < clip_range.rva) {
 | 
				
			||||||
 | 
					    DWORD clip_left = clip_range.rva - mapped_range->rva_original;
 | 
				
			||||||
 | 
					    mapped_range->rva_original += clip_left;
 | 
				
			||||||
 | 
					    mapped_range->rva_transformed += clip_left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (clip_left > mapped_range->length) {
 | 
				
			||||||
 | 
					      // The left clipping boundary entirely erases the content section of the
 | 
				
			||||||
 | 
					      // range.
 | 
				
			||||||
 | 
					      DWORD trim = clip_left - mapped_range->length;
 | 
				
			||||||
 | 
					      mapped_range->length = 0;
 | 
				
			||||||
 | 
					      mapped_range->injected -= Min(trim, mapped_range->injected);
 | 
				
			||||||
 | 
					      // We know that trim <= mapped_range->remove.
 | 
				
			||||||
 | 
					      mapped_range->removed -= trim;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // The left clipping boundary removes some, but not all, of the content.
 | 
				
			||||||
 | 
					      // As such it leaves the removed/injected component intact.
 | 
				
			||||||
 | 
					      mapped_range->length -= clip_left;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Clip the right side.
 | 
				
			||||||
 | 
					  DWORD end_original = mapped_range->rva_original + mapped_range->length;
 | 
				
			||||||
 | 
					  if (clip_range.end() < end_original) {
 | 
				
			||||||
 | 
					    // The right clipping boundary lands in the 'content' section of the range,
 | 
				
			||||||
 | 
					    // entirely clearing the injected/removed portion.
 | 
				
			||||||
 | 
					    DWORD clip_right = end_original - clip_range.end();
 | 
				
			||||||
 | 
					    mapped_range->length -= clip_right;
 | 
				
			||||||
 | 
					    mapped_range->injected = 0;
 | 
				
			||||||
 | 
					    mapped_range->removed = 0;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // The right clipping boundary is outside of the content, but may affect
 | 
				
			||||||
 | 
					    // the removed/injected portion of the range.
 | 
				
			||||||
 | 
					    DWORD end_removed = end_original + mapped_range->removed;
 | 
				
			||||||
 | 
					    if (clip_range.end() < end_removed)
 | 
				
			||||||
 | 
					      mapped_range->removed = clip_range.end() - end_original;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DWORD end_injected = end_original + mapped_range->injected;
 | 
				
			||||||
 | 
					    if (clip_range.end() < end_injected)
 | 
				
			||||||
 | 
					      mapped_range->injected = clip_range.end() - end_original;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int AddressRange::Compare(const AddressRange& rhs) const {
 | 
				
			||||||
 | 
					  if (end() <= rhs.rva)
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  if (rhs.end() <= rva)
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool GetOmapDataAndDisableTranslation(IDiaSession* session,
 | 
				
			||||||
 | 
					                                      OmapData* omap_data) {
 | 
				
			||||||
 | 
					  assert(session != NULL);
 | 
				
			||||||
 | 
					  assert(omap_data != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CComPtr<IDiaAddressMap> address_map;
 | 
				
			||||||
 | 
					  if (FAILED(session->QueryInterface(&address_map))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  assert(address_map.p != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BOOL omap_enabled = FALSE;
 | 
				
			||||||
 | 
					  if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!omap_enabled) {
 | 
				
			||||||
 | 
					    // We indicate the non-presence of OMAP data by returning empty tables.
 | 
				
			||||||
 | 
					    omap_data->omap_from.clear();
 | 
				
			||||||
 | 
					    omap_data->omap_to.clear();
 | 
				
			||||||
 | 
					    omap_data->length_original = 0;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // OMAP data is present. Disable translation.
 | 
				
			||||||
 | 
					  if (FAILED(address_map->put_addressMapEnabled(FALSE))) {
 | 
				
			||||||
 | 
					    fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Read the OMAP streams.
 | 
				
			||||||
 | 
					  if (!FindAndLoadOmapTable(kOmapFromDebugStreamName,
 | 
				
			||||||
 | 
					                            session,
 | 
				
			||||||
 | 
					                            &omap_data->omap_from)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!FindAndLoadOmapTable(kOmapToDebugStreamName,
 | 
				
			||||||
 | 
					                            session,
 | 
				
			||||||
 | 
					                            &omap_data->omap_to)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get the lengths of the address spaces.
 | 
				
			||||||
 | 
					  if (!GetOriginalImageLength(session, &omap_data->length_original))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) {
 | 
				
			||||||
 | 
					  assert(image_map != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BuildMapping(omap_data, &image_map->mapping);
 | 
				
			||||||
 | 
					  BuildEndpointIndexMap(image_map);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MapAddressRange(const ImageMap& image_map,
 | 
				
			||||||
 | 
					                     const AddressRange& original_range,
 | 
				
			||||||
 | 
					                     AddressRangeVector* mapped_ranges) {
 | 
				
			||||||
 | 
					  assert(mapped_ranges != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Mapping& map = image_map.mapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle the trivial case of an empty image_map. This means that there is
 | 
				
			||||||
 | 
					  // no transformation to be applied, and we can simply return the original
 | 
				
			||||||
 | 
					  // range.
 | 
				
			||||||
 | 
					  if (map.empty()) {
 | 
				
			||||||
 | 
					    mapped_ranges->push_back(original_range);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If we get a query of length 0 we need to handle it by using a non-zero
 | 
				
			||||||
 | 
					  // query length.
 | 
				
			||||||
 | 
					  AddressRange query_range(original_range);
 | 
				
			||||||
 | 
					  if (query_range.length == 0)
 | 
				
			||||||
 | 
					    query_range.length = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Find the range of intervals that can potentially intersect our query range.
 | 
				
			||||||
 | 
					  size_t imin = 0;
 | 
				
			||||||
 | 
					  size_t imax = 0;
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    // The index of the earliest possible range that can affect is us done by
 | 
				
			||||||
 | 
					    // searching through the secondary indexing structure.
 | 
				
			||||||
 | 
					    const EndpointIndexMap& eim = image_map.endpoint_index_map;
 | 
				
			||||||
 | 
					    EndpointIndex q1 = { query_range.rva, 0 };
 | 
				
			||||||
 | 
					    EndpointIndexMap::const_iterator it1 = std::lower_bound(
 | 
				
			||||||
 | 
					        eim.begin(), eim.end(), q1, EndpointIndexLess);
 | 
				
			||||||
 | 
					    if (it1 == eim.end()) {
 | 
				
			||||||
 | 
					      imin  = map.size();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // Backup to find the interval that contains our query point.
 | 
				
			||||||
 | 
					      if (it1 != eim.begin() && query_range.rva < it1->endpoint)
 | 
				
			||||||
 | 
					        --it1;
 | 
				
			||||||
 | 
					      imin = it1->index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The first range that can't possibly intersect us is found by searching
 | 
				
			||||||
 | 
					    // through the image map directly as it is already sorted by interval start
 | 
				
			||||||
 | 
					    // point.
 | 
				
			||||||
 | 
					    MappedRange q2 = { query_range.end(), 0 };
 | 
				
			||||||
 | 
					    Mapping::const_iterator it2 = std::lower_bound(
 | 
				
			||||||
 | 
					        map.begin(), map.end(), q2, MappedRangeOriginalLess);
 | 
				
			||||||
 | 
					    imax = it2 - map.begin();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Find all intervals that intersect the query range.
 | 
				
			||||||
 | 
					  Mapping temp_map;
 | 
				
			||||||
 | 
					  for (size_t i = imin; i < imax; ++i) {
 | 
				
			||||||
 | 
					    MappedRange mr = map[i];
 | 
				
			||||||
 | 
					    ClipMappedRangeOriginal(query_range, &mr);
 | 
				
			||||||
 | 
					    if (mr.length + mr.injected > 0)
 | 
				
			||||||
 | 
					      temp_map.push_back(mr);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If there are no intersecting ranges then the query range has been removed
 | 
				
			||||||
 | 
					  // from the image in question.
 | 
				
			||||||
 | 
					  if (temp_map.empty())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sort based on transformed addresses.
 | 
				
			||||||
 | 
					  std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Zero-length queries can't actually be merged. We simply output the set of
 | 
				
			||||||
 | 
					  // unique RVAs that correspond to the query RVA.
 | 
				
			||||||
 | 
					  if (original_range.length == 0) {
 | 
				
			||||||
 | 
					    mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0));
 | 
				
			||||||
 | 
					    for (size_t i = 1; i < temp_map.size(); ++i) {
 | 
				
			||||||
 | 
					      if (temp_map[i].rva_transformed > mapped_ranges->back().rva)
 | 
				
			||||||
 | 
					        mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Merge any ranges that are consecutive in the mapped image. We merge over
 | 
				
			||||||
 | 
					  // injected content if it makes ranges contiguous, but we ignore any injected
 | 
				
			||||||
 | 
					  // content at the tail end of a range. This allows us to detect symbols that
 | 
				
			||||||
 | 
					  // have been lengthened by injecting content in the middle. However, it
 | 
				
			||||||
 | 
					  // misses the case where content has been injected at the head or the tail.
 | 
				
			||||||
 | 
					  // The problem is that it doesn't know whether to attribute it to the
 | 
				
			||||||
 | 
					  // preceding or following symbol. It is up to the author of the transform to
 | 
				
			||||||
 | 
					  // output explicit OMAP info in these cases to ensure full coverage of the
 | 
				
			||||||
 | 
					  // transformed address space.
 | 
				
			||||||
 | 
					  DWORD rva_begin = temp_map[0].rva_transformed;
 | 
				
			||||||
 | 
					  DWORD rva_cur_content = rva_begin + temp_map[0].length;
 | 
				
			||||||
 | 
					  DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected;
 | 
				
			||||||
 | 
					  for (size_t i = 1; i < temp_map.size(); ++i) {
 | 
				
			||||||
 | 
					    if (rva_cur_injected < temp_map[i].rva_transformed) {
 | 
				
			||||||
 | 
					      // This marks the end of a continuous range in the image. Output the
 | 
				
			||||||
 | 
					      // current range and start a new one.
 | 
				
			||||||
 | 
					      if (rva_begin < rva_cur_content) {
 | 
				
			||||||
 | 
					        mapped_ranges->push_back(
 | 
				
			||||||
 | 
					            AddressRange(rva_begin, rva_cur_content - rva_begin));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      rva_begin = temp_map[i].rva_transformed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length;
 | 
				
			||||||
 | 
					    rva_cur_injected = rva_cur_content + temp_map[i].injected;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output the range in progress.
 | 
				
			||||||
 | 
					  if (rva_begin < rva_cur_content) {
 | 
				
			||||||
 | 
					    mapped_ranges->push_back(
 | 
				
			||||||
 | 
					        AddressRange(rva_begin, rva_cur_content - rva_begin));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										72
									
								
								google-breakpad/src/common/windows/omap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								google-breakpad/src/common/windows/omap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Provides an API for mapping symbols through OMAP information, if a PDB file
 | 
				
			||||||
 | 
					// is augmented with it. This allows breakpad to work with addresses in
 | 
				
			||||||
 | 
					// transformed images by transforming the symbols themselves, rather than
 | 
				
			||||||
 | 
					// transforming addresses prior to querying symbols (the way it is typically
 | 
				
			||||||
 | 
					// done by Windows-native tools, including the DIA).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMMON_WINDOWS_OMAP_H__
 | 
				
			||||||
 | 
					#define COMMON_WINDOWS_OMAP_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/omap_internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If the given session contains OMAP data this extracts it, populating
 | 
				
			||||||
 | 
					// |omap_data|, and then disabling automatic translation for the session.
 | 
				
			||||||
 | 
					// OMAP data is present in the PDB if |omap_data| is not empty. This returns
 | 
				
			||||||
 | 
					// true on success, false otherwise.
 | 
				
			||||||
 | 
					bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session,
 | 
				
			||||||
 | 
					                                      OmapData* omap_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Given raw OMAP data builds an ImageMap. This can be used to query individual
 | 
				
			||||||
 | 
					// image ranges using MapAddressRange.
 | 
				
			||||||
 | 
					// |omap_data|| is the OMAP data extracted from the PDB.
 | 
				
			||||||
 | 
					// |image_map| will be populated with a description of the image mapping. If
 | 
				
			||||||
 | 
					//     |omap_data| is empty then this will also be empty.
 | 
				
			||||||
 | 
					void BuildImageMap(const OmapData& omap_data, ImageMap* image_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Given an address range in the original image space determines how exactly it
 | 
				
			||||||
 | 
					// has been tranformed.
 | 
				
			||||||
 | 
					// |omap_data| is the OMAP data extracted from the PDB, which must not be
 | 
				
			||||||
 | 
					//     empty.
 | 
				
			||||||
 | 
					// |original_range| is the address range in the original image being queried.
 | 
				
			||||||
 | 
					// |mapped_ranges| will be populated with a full description of the mapping.
 | 
				
			||||||
 | 
					//     They may be disjoint in the transformed image so a vector is needed to
 | 
				
			||||||
 | 
					//     fully represent the mapping. This will be appended to if it is not
 | 
				
			||||||
 | 
					//     empty. If |omap_data| is empty then |mapped_ranges| will simply be
 | 
				
			||||||
 | 
					//     populated with a copy of |original_range| (the identity transform).
 | 
				
			||||||
 | 
					void MapAddressRange(const ImageMap& image_map,
 | 
				
			||||||
 | 
					                     const AddressRange& original_range,
 | 
				
			||||||
 | 
					                     AddressRangeVector* mapped_ranges);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // COMMON_WINDOWS_OMAP_H__
 | 
				
			||||||
							
								
								
									
										137
									
								
								google-breakpad/src/common/windows/omap_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								google-breakpad/src/common/windows/omap_internal.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Declares internal implementation details for functionality in omap.h and
 | 
				
			||||||
 | 
					// omap.cc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H__
 | 
				
			||||||
 | 
					#define COMMON_WINDOWS_OMAP_INTERNAL_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <windows.h>
 | 
				
			||||||
 | 
					#include <dia2.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The OMAP struct is defined by debughlp.h, which doesn't play nicely with
 | 
				
			||||||
 | 
					// imagehlp.h. We simply redefine it.
 | 
				
			||||||
 | 
					struct OMAP {
 | 
				
			||||||
 | 
					  DWORD rva;
 | 
				
			||||||
 | 
					  DWORD rvaTo;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure.");
 | 
				
			||||||
 | 
					typedef std::vector<OMAP> OmapTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This contains the OMAP data extracted from an image.
 | 
				
			||||||
 | 
					struct OmapData {
 | 
				
			||||||
 | 
					  // The table of OMAP entries describing the transformation from the
 | 
				
			||||||
 | 
					  // original image to the transformed image.
 | 
				
			||||||
 | 
					  OmapTable omap_from;  
 | 
				
			||||||
 | 
					  // The table of OMAP entries describing the transformation from the
 | 
				
			||||||
 | 
					  // instrumented image to the original image.
 | 
				
			||||||
 | 
					  OmapTable omap_to;
 | 
				
			||||||
 | 
					  // The length of the original untransformed image.
 | 
				
			||||||
 | 
					  DWORD length_original;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OmapData() : length_original(0) { }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This represents a range of addresses in an image.
 | 
				
			||||||
 | 
					struct AddressRange {
 | 
				
			||||||
 | 
					  DWORD rva;
 | 
				
			||||||
 | 
					  DWORD length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange() : rva(0), length(0) { }
 | 
				
			||||||
 | 
					  AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Returns the end address of this range.
 | 
				
			||||||
 | 
					  DWORD end() const { return rva + length; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Addreses only compare as less-than or greater-than if they are not
 | 
				
			||||||
 | 
					  // overlapping. Otherwise, they compare equal.
 | 
				
			||||||
 | 
					  int Compare(const AddressRange& rhs) const;
 | 
				
			||||||
 | 
					  bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; }
 | 
				
			||||||
 | 
					  bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Equality operators compare exact values.
 | 
				
			||||||
 | 
					  bool operator==(const AddressRange& rhs) const {
 | 
				
			||||||
 | 
					    return rva == rhs.rva && length == rhs.length;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  bool operator!=(const  AddressRange& rhs) const { return !((*this) == rhs); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef std::vector<AddressRange> AddressRangeVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This represents an address range in an original image, and its corresponding
 | 
				
			||||||
 | 
					// range in the transformed image.
 | 
				
			||||||
 | 
					struct MappedRange {
 | 
				
			||||||
 | 
					  // An address in the original image.
 | 
				
			||||||
 | 
					  DWORD rva_original;
 | 
				
			||||||
 | 
					  // The corresponding addresses in the transformed image.
 | 
				
			||||||
 | 
					  DWORD rva_transformed;
 | 
				
			||||||
 | 
					  // The length of the address range.
 | 
				
			||||||
 | 
					  DWORD length;
 | 
				
			||||||
 | 
					  // It is possible for code to be injected into a transformed image, for which
 | 
				
			||||||
 | 
					  // there is no corresponding code in the original image. If this range of
 | 
				
			||||||
 | 
					  // transformed image is immediately followed by such injected code we maintain
 | 
				
			||||||
 | 
					  // a record of its length here.
 | 
				
			||||||
 | 
					  DWORD injected;
 | 
				
			||||||
 | 
					  // It is possible for code to be removed from the original image. This happens
 | 
				
			||||||
 | 
					  // for things like padding between blocks. There is no actual content lost,
 | 
				
			||||||
 | 
					  // but the spacing between items may be lost. This keeps track of any removed
 | 
				
			||||||
 | 
					  // content immediately following the |original| range.
 | 
				
			||||||
 | 
					  DWORD removed;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					// A vector of mapped ranges is used as a more useful representation of
 | 
				
			||||||
 | 
					// OMAP data.
 | 
				
			||||||
 | 
					typedef std::vector<MappedRange> Mapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used as a secondary search structure accompanying a Mapping.
 | 
				
			||||||
 | 
					struct EndpointIndex {
 | 
				
			||||||
 | 
					  DWORD endpoint;
 | 
				
			||||||
 | 
					  size_t index;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef std::vector<EndpointIndex> EndpointIndexMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// An ImageMap is vector of mapped ranges, plus a secondary index into it for
 | 
				
			||||||
 | 
					// doing interval searches. (An interval tree would also work, but is overkill
 | 
				
			||||||
 | 
					// because we don't need insertion and deletion.)
 | 
				
			||||||
 | 
					struct ImageMap {
 | 
				
			||||||
 | 
					  // This is a description of the mapping between original and transformed
 | 
				
			||||||
 | 
					  // image, sorted by addresses in the original image.
 | 
				
			||||||
 | 
					  Mapping mapping;
 | 
				
			||||||
 | 
					  // For all interval endpoints in |mapping| this stores the minimum index of
 | 
				
			||||||
 | 
					  // an interval in |mapping| that contains the endpoint. Useful for doing
 | 
				
			||||||
 | 
					  // interval intersection queries.
 | 
				
			||||||
 | 
					  EndpointIndexMap endpoint_index_map;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // COMMON_WINDOWS_OMAP_INTERNAL_H__
 | 
				
			||||||
							
								
								
									
										330
									
								
								google-breakpad/src/common/windows/omap_unittest.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								google-breakpad/src/common/windows/omap_unittest.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,330 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unittests for OMAP related functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/omap.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gmock/gmock.h"
 | 
				
			||||||
 | 
					#include "gtest/gtest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Equality operators for ContainerEq. These must be outside of the anonymous
 | 
				
			||||||
 | 
					// namespace in order for them to be found.
 | 
				
			||||||
 | 
					bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
 | 
				
			||||||
 | 
					  return mr1.rva_original == mr2.rva_original &&
 | 
				
			||||||
 | 
					      mr1.rva_transformed == mr2.rva_transformed &&
 | 
				
			||||||
 | 
					      mr1.length == mr2.length &&
 | 
				
			||||||
 | 
					      mr1.injected == mr2.injected &&
 | 
				
			||||||
 | 
					      mr1.removed == mr2.removed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
 | 
				
			||||||
 | 
					  return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pretty printers for more meaningful error messages. Also need to be outside
 | 
				
			||||||
 | 
					// the anonymous namespace.
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
 | 
				
			||||||
 | 
					  os << "MappedRange(rva_original=" << mr.rva_original
 | 
				
			||||||
 | 
					     << ", rva_transformed=" << mr.rva_transformed
 | 
				
			||||||
 | 
					     << ", length=" << mr.length
 | 
				
			||||||
 | 
					     << ", injected=" << mr.injected
 | 
				
			||||||
 | 
					     << ", removed=" << mr.removed << ")";
 | 
				
			||||||
 | 
					  return os;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
 | 
				
			||||||
 | 
					  os << "EndpointIndex(endpoint=" << ei.endpoint
 | 
				
			||||||
 | 
					     << ", index=" << ei.index << ")";
 | 
				
			||||||
 | 
					  return os;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
 | 
				
			||||||
 | 
					  os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
 | 
				
			||||||
 | 
					  return os;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
 | 
				
			||||||
 | 
					  OMAP o = { rva, rvaTo };
 | 
				
			||||||
 | 
					  return o;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MappedRange CreateMappedRange(DWORD rva_original,
 | 
				
			||||||
 | 
					                              DWORD rva_transformed,
 | 
				
			||||||
 | 
					                              DWORD length,
 | 
				
			||||||
 | 
					                              DWORD injected,
 | 
				
			||||||
 | 
					                              DWORD removed) {
 | 
				
			||||||
 | 
					  MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
 | 
				
			||||||
 | 
					  return mr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
 | 
				
			||||||
 | 
					  EndpointIndex ei = { endpoint, index };
 | 
				
			||||||
 | 
					  return ei;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//              (C is removed)
 | 
				
			||||||
 | 
					// Original   :  A B C D E F G H
 | 
				
			||||||
 | 
					// Transformed:  A B D F E * H1 G1 G2 H2
 | 
				
			||||||
 | 
					//              (* is injected, G is copied, H is split)
 | 
				
			||||||
 | 
					// A is implied.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Layout of the original image.
 | 
				
			||||||
 | 
					const AddressRange B(100, 15);
 | 
				
			||||||
 | 
					const AddressRange C(B.end(), 10);
 | 
				
			||||||
 | 
					const AddressRange D(C.end(), 25);
 | 
				
			||||||
 | 
					const AddressRange E(D.end(), 10);
 | 
				
			||||||
 | 
					const AddressRange F(E.end(), 40);
 | 
				
			||||||
 | 
					const AddressRange G(F.end(), 3);
 | 
				
			||||||
 | 
					const AddressRange H(G.end(), 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Layout of the transformed image.
 | 
				
			||||||
 | 
					const AddressRange Bt(100, 15);
 | 
				
			||||||
 | 
					const AddressRange Dt(Bt.end(), 20);  // D is shortened.
 | 
				
			||||||
 | 
					const AddressRange Ft(Dt.end(), F.length);
 | 
				
			||||||
 | 
					const AddressRange Et(Ft.end(), E.length);
 | 
				
			||||||
 | 
					const AddressRange injected(Et.end(), 5);
 | 
				
			||||||
 | 
					const AddressRange H1t(injected.end(), 4);  // H is split.
 | 
				
			||||||
 | 
					const AddressRange G1t(H1t.end(), G.length);  // G is copied.
 | 
				
			||||||
 | 
					const AddressRange G2t(G1t.end(), G.length);  // G is copied.
 | 
				
			||||||
 | 
					const AddressRange H2t(G2t.end(), 3);  // H is split.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BuildImageMapTest : public testing::Test {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  static const DWORD kInvalidAddress = 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void InitOmapData() {
 | 
				
			||||||
 | 
					    omap_data.length_original = H.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Build the OMAPTO vector (from transformed to original).
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
 | 
				
			||||||
 | 
					    omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Build the OMAPFROM vector (from original to transformed).
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
 | 
				
			||||||
 | 
					    omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OmapData omap_data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
 | 
				
			||||||
 | 
					  ASSERT_EQ(0u, omap_data.omap_from.size());
 | 
				
			||||||
 | 
					  ASSERT_EQ(0u, omap_data.omap_to.size());
 | 
				
			||||||
 | 
					  ASSERT_EQ(0u, omap_data.length_original);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ImageMap image_map;
 | 
				
			||||||
 | 
					  BuildImageMap(omap_data, &image_map);
 | 
				
			||||||
 | 
					  EXPECT_EQ(0u, image_map.mapping.size());
 | 
				
			||||||
 | 
					  EXPECT_EQ(0u, image_map.endpoint_index_map.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
 | 
				
			||||||
 | 
					  InitOmapData();
 | 
				
			||||||
 | 
					  ASSERT_LE(0u, omap_data.omap_from.size());
 | 
				
			||||||
 | 
					  ASSERT_LE(0u, omap_data.omap_to.size());
 | 
				
			||||||
 | 
					  ASSERT_LE(0u, omap_data.length_original);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ImageMap image_map;
 | 
				
			||||||
 | 
					  BuildImageMap(omap_data, &image_map);
 | 
				
			||||||
 | 
					  EXPECT_LE(9u, image_map.mapping.size());
 | 
				
			||||||
 | 
					  EXPECT_LE(9u, image_map.endpoint_index_map.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Mapping mapping;
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
 | 
				
			||||||
 | 
					  // C is removed, and it originally comes immediately after B.
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
 | 
				
			||||||
 | 
					  // D is shortened by a length of 5.
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
 | 
				
			||||||
 | 
					  // The injected content comes immediately after E in the transformed image.
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
 | 
				
			||||||
 | 
					                                      0));
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
 | 
				
			||||||
 | 
					  // G is copied so creates two entries.
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
 | 
				
			||||||
 | 
					  // H is split, so create two entries.
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
 | 
				
			||||||
 | 
					  mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
 | 
				
			||||||
 | 
					                                      0, 0));
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapping,
 | 
				
			||||||
 | 
					              testing::ContainerEq(image_map.mapping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EndpointIndexMap endpoint_index_map;
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
 | 
				
			||||||
 | 
					  // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
 | 
				
			||||||
 | 
					  // H is split so we expect 2 endpoints to show up attributed to it.
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
 | 
				
			||||||
 | 
					  endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
 | 
				
			||||||
 | 
					  EXPECT_THAT(endpoint_index_map,
 | 
				
			||||||
 | 
					              testing::ContainerEq(image_map.endpoint_index_map));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MapAddressRangeTest : public BuildImageMapTest {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  typedef BuildImageMapTest Super;
 | 
				
			||||||
 | 
					  virtual void SetUp() {
 | 
				
			||||||
 | 
					    Super::SetUp();
 | 
				
			||||||
 | 
					    InitOmapData();
 | 
				
			||||||
 | 
					    BuildImageMap(omap_data, &image_map);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ImageMap image_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  using BuildImageMapTest::InitOmapData;
 | 
				
			||||||
 | 
					  using BuildImageMapTest::omap_data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
 | 
				
			||||||
 | 
					  ImageMap im;
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  AddressRange ar(0, 1024);
 | 
				
			||||||
 | 
					  MapAddressRange(im, ar, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_EQ(ar, mapped_ranges[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapOutOfImage) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(0u, mapped_ranges.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapIdentity) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, B, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange DEF(D.rva, F.end() - D.rva);
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, DEF, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapEmptySingle) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapEmptyCopied) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(2u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
 | 
				
			||||||
 | 
					                                                  AddressRange(G2t.rva, 0)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, G, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(
 | 
				
			||||||
 | 
					      AddressRange(G1t.rva, G2t.end() - G1t.rva)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, H, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(2u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapInjected) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange EFGH(E.rva, H.end() - E.rva);
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, EFGH, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, C, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(0u, mapped_ranges.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapRemovedPartly) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, D, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(MapAddressRangeTest, MapFull) {
 | 
				
			||||||
 | 
					  AddressRangeVector mapped_ranges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange AH(0, H.end());
 | 
				
			||||||
 | 
					  MapAddressRange(image_map, AH, &mapped_ranges);
 | 
				
			||||||
 | 
					  EXPECT_EQ(1u, mapped_ranges.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AddressRange AHt(0, H2t.end());
 | 
				
			||||||
 | 
					  EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
							
								
								
									
										1066
									
								
								google-breakpad/src/common/windows/pdb_source_line_writer.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1066
									
								
								google-breakpad/src/common/windows/pdb_source_line_writer.cc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										243
									
								
								google-breakpad/src/common/windows/pdb_source_line_writer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								google-breakpad/src/common/windows/pdb_source_line_writer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,243 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output
 | 
				
			||||||
 | 
					// a line/address map for use with BasicSourceLineResolver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _PDB_SOURCE_LINE_WRITER_H__
 | 
				
			||||||
 | 
					#define _PDB_SOURCE_LINE_WRITER_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atlcomcli.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <hash_map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/omap.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct IDiaEnumLineNumbers;
 | 
				
			||||||
 | 
					struct IDiaSession;
 | 
				
			||||||
 | 
					struct IDiaSymbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using std::wstring;
 | 
				
			||||||
 | 
					using stdext::hash_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A structure that carries information that identifies a pdb file.
 | 
				
			||||||
 | 
					struct PDBModuleInfo {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  // The basename of the pdb file from which information was loaded.
 | 
				
			||||||
 | 
					  wstring debug_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The pdb's identifier.  For recent pdb files, the identifier consists
 | 
				
			||||||
 | 
					  // of the pdb's guid, in uppercase hexadecimal form without any dashes
 | 
				
			||||||
 | 
					  // or separators, followed immediately by the pdb's age, also in
 | 
				
			||||||
 | 
					  // uppercase hexadecimal form.  For older pdb files which have no guid,
 | 
				
			||||||
 | 
					  // the identifier is the pdb's 32-bit signature value, in zero-padded
 | 
				
			||||||
 | 
					  // hexadecimal form, followed immediately by the pdb's age, in lowercase
 | 
				
			||||||
 | 
					  // hexadecimal form.
 | 
				
			||||||
 | 
					  wstring debug_identifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A string identifying the cpu that the pdb is associated with.
 | 
				
			||||||
 | 
					  // Currently, this may be "x86" or "unknown".
 | 
				
			||||||
 | 
					  wstring cpu;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A structure that carries information that identifies a PE file,
 | 
				
			||||||
 | 
					// either an EXE or a DLL.
 | 
				
			||||||
 | 
					struct PEModuleInfo {
 | 
				
			||||||
 | 
					  // The basename of the PE file.
 | 
				
			||||||
 | 
					  wstring code_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The PE file's code identifier, which consists of its timestamp
 | 
				
			||||||
 | 
					  // and file size concatenated together into a single hex string.
 | 
				
			||||||
 | 
					  // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
 | 
				
			||||||
 | 
					  // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
 | 
				
			||||||
 | 
					  // documentation.) This is not well documented, if it's documented
 | 
				
			||||||
 | 
					  // at all, but it's what symstore does and what DbgHelp supports.
 | 
				
			||||||
 | 
					  wstring code_identifier;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PDBSourceLineWriter {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  enum FileFormat {
 | 
				
			||||||
 | 
					    PDB_FILE,  // a .pdb file containing debug symbols
 | 
				
			||||||
 | 
					    EXE_FILE,  // a .exe or .dll file
 | 
				
			||||||
 | 
					    ANY_FILE   // try PDB_FILE and then EXE_FILE
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  explicit PDBSourceLineWriter();
 | 
				
			||||||
 | 
					  ~PDBSourceLineWriter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Opens the given file.  For executable files, the corresponding pdb
 | 
				
			||||||
 | 
					  // file must be available; Open will be if it is not.
 | 
				
			||||||
 | 
					  // If there is already a pdb file open, it is automatically closed.
 | 
				
			||||||
 | 
					  // Returns true on success.
 | 
				
			||||||
 | 
					  bool Open(const wstring &file, FileFormat format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Locates the pdb file for the given executable (exe or dll) file,
 | 
				
			||||||
 | 
					  // and opens it.  If there is already a pdb file open, it is automatically
 | 
				
			||||||
 | 
					  // closed.  Returns true on success.
 | 
				
			||||||
 | 
					  bool OpenExecutable(const wstring &exe_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Writes a map file from the current pdb file to the given file stream.
 | 
				
			||||||
 | 
					  // Returns true on success.
 | 
				
			||||||
 | 
					  bool WriteMap(FILE *map_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Closes the current pdb file and its associated resources.
 | 
				
			||||||
 | 
					  void Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Retrieves information about the module's debugging file.  Returns
 | 
				
			||||||
 | 
					  // true on success and false on failure.
 | 
				
			||||||
 | 
					  bool GetModuleInfo(PDBModuleInfo *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Retrieves information about the module's PE file.  Returns
 | 
				
			||||||
 | 
					  // true on success and false on failure.
 | 
				
			||||||
 | 
					  bool GetPEInfo(PEModuleInfo *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sets uses_guid to true if the opened file uses a new-style CodeView
 | 
				
			||||||
 | 
					  // record with a 128-bit GUID, or false if the opened file uses an old-style
 | 
				
			||||||
 | 
					  // CodeView record.  When no GUID is available, a 32-bit signature should be
 | 
				
			||||||
 | 
					  // used to identify the module instead.  If the information cannot be
 | 
				
			||||||
 | 
					  // determined, this method returns false.
 | 
				
			||||||
 | 
					  bool UsesGUID(bool *uses_guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  // Outputs the line/address pairs for each line in the enumerator.
 | 
				
			||||||
 | 
					  // Returns true on success.
 | 
				
			||||||
 | 
					  bool PrintLines(IDiaEnumLineNumbers *lines);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs a function address and name, followed by its source line list.
 | 
				
			||||||
 | 
					  // block can be the same object as function, or it can be a reference
 | 
				
			||||||
 | 
					  // to a code block that is lexically part of this function, but
 | 
				
			||||||
 | 
					  // resides at a separate address.
 | 
				
			||||||
 | 
					  // Returns true on success.
 | 
				
			||||||
 | 
					  bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs all functions as described above.  Returns true on success.
 | 
				
			||||||
 | 
					  bool PrintFunctions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs all of the source files in the session's pdb file.
 | 
				
			||||||
 | 
					  // Returns true on success.
 | 
				
			||||||
 | 
					  bool PrintSourceFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs all of the frame information necessary to construct stack
 | 
				
			||||||
 | 
					  // backtraces in the absence of frame pointers.  Returns true on success.
 | 
				
			||||||
 | 
					  bool PrintFrameData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs a single public symbol address and name, if the symbol corresponds
 | 
				
			||||||
 | 
					  // to a code address.  Returns true on success.  If symbol is does not
 | 
				
			||||||
 | 
					  // correspond to code, returns true without outputting anything.
 | 
				
			||||||
 | 
					  bool PrintCodePublicSymbol(IDiaSymbol *symbol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs a line identifying the PDB file that is being dumped, along with
 | 
				
			||||||
 | 
					  // its uuid and age.
 | 
				
			||||||
 | 
					  bool PrintPDBInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Outputs a line identifying the PE file corresponding to the PDB
 | 
				
			||||||
 | 
					  // file that is being dumped, along with its code identifier,
 | 
				
			||||||
 | 
					  // which consists of its timestamp and file size.
 | 
				
			||||||
 | 
					  bool PrintPEInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Returns true if this filename has already been seen,
 | 
				
			||||||
 | 
					  // and an ID is stored for it, or false if it has not.
 | 
				
			||||||
 | 
					  bool FileIDIsCached(const wstring &file) {
 | 
				
			||||||
 | 
					    return unique_files_.find(file) != unique_files_.end();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Cache this filename and ID for later reuse.
 | 
				
			||||||
 | 
					  void CacheFileID(const wstring &file, DWORD id) {
 | 
				
			||||||
 | 
					    unique_files_[file] = id;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Store this ID in the cache as a duplicate for this filename.
 | 
				
			||||||
 | 
					  void StoreDuplicateFileID(const wstring &file, DWORD id) {
 | 
				
			||||||
 | 
					    hash_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
 | 
				
			||||||
 | 
					    if (iter != unique_files_.end()) {
 | 
				
			||||||
 | 
					      // map this id to the previously seen one
 | 
				
			||||||
 | 
					      file_ids_[id] = iter->second;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Given a file's unique ID, return the ID that should be used to
 | 
				
			||||||
 | 
					  // reference it. There may be multiple files with identical filenames
 | 
				
			||||||
 | 
					  // but different unique IDs. The cache attempts to coalesce these into
 | 
				
			||||||
 | 
					  // one ID per unique filename.
 | 
				
			||||||
 | 
					  DWORD GetRealFileID(DWORD id) {
 | 
				
			||||||
 | 
					    hash_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
 | 
				
			||||||
 | 
					    if (iter == file_ids_.end())
 | 
				
			||||||
 | 
					      return id;
 | 
				
			||||||
 | 
					    return iter->second;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Find the PE file corresponding to the loaded PDB file, and
 | 
				
			||||||
 | 
					  // set the code_file_ member. Returns false on failure.
 | 
				
			||||||
 | 
					  bool FindPEFile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Returns the function name for a symbol.  If possible, the name is
 | 
				
			||||||
 | 
					  // undecorated.  If the symbol's decorated form indicates the size of
 | 
				
			||||||
 | 
					  // parameters on the stack, this information is returned in stack_param_size.
 | 
				
			||||||
 | 
					  // Returns true on success.  If the symbol doesn't encode parameter size
 | 
				
			||||||
 | 
					  // information, stack_param_size is set to -1.
 | 
				
			||||||
 | 
					  static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name,
 | 
				
			||||||
 | 
					                                    int *stack_param_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Returns the number of bytes of stack space used for a function's
 | 
				
			||||||
 | 
					  // parameters.  function must have the tag SymTagFunction.  In the event of
 | 
				
			||||||
 | 
					  // a failure, returns 0, which is also a valid number of bytes.
 | 
				
			||||||
 | 
					  static int GetFunctionStackParamSize(IDiaSymbol *function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The filename of the PE file corresponding to the currently-open
 | 
				
			||||||
 | 
					  // pdb file.
 | 
				
			||||||
 | 
					  wstring code_file_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The session for the currently-open pdb file.
 | 
				
			||||||
 | 
					  CComPtr<IDiaSession> session_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The current output file for this WriteMap invocation.
 | 
				
			||||||
 | 
					  FILE *output_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // There may be many duplicate filenames with different IDs.
 | 
				
			||||||
 | 
					  // This maps from the DIA "unique ID" to a single ID per unique
 | 
				
			||||||
 | 
					  // filename.
 | 
				
			||||||
 | 
					  hash_map<DWORD, DWORD> file_ids_;
 | 
				
			||||||
 | 
					  // This maps unique filenames to file IDs.
 | 
				
			||||||
 | 
					  hash_map<wstring, DWORD> unique_files_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // This is used for calculating post-transform symbol addresses and lengths.
 | 
				
			||||||
 | 
					  ImageMap image_map_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Disallow copy ctor and operator=
 | 
				
			||||||
 | 
					  PDBSourceLineWriter(const PDBSourceLineWriter&);
 | 
				
			||||||
 | 
					  void operator=(const PDBSourceLineWriter&);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // _PDB_SOURCE_LINE_WRITER_H__
 | 
				
			||||||
							
								
								
									
										142
									
								
								google-breakpad/src/common/windows/string_utils-inl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								google-breakpad/src/common/windows/string_utils-inl.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// string_utils-inl.h: Safer string manipulation on Windows, supporting
 | 
				
			||||||
 | 
					// pre-MSVC8 environments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__
 | 
				
			||||||
 | 
					#define COMMON_WINDOWS_STRING_UTILS_INL_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The "ll" printf format size specifier corresponding to |long long| was
 | 
				
			||||||
 | 
					// intrudced in MSVC8.  Earlier versions did not provide this size specifier,
 | 
				
			||||||
 | 
					// but "I64" can be used to print 64-bit types.  Don't use "I64" where "ll"
 | 
				
			||||||
 | 
					// is available, in the event of oddball systems where |long long| is not
 | 
				
			||||||
 | 
					// 64 bits wide.
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					#define WIN_STRING_FORMAT_LL "ll"
 | 
				
			||||||
 | 
					#else  // MSC_VER >= 1400
 | 
				
			||||||
 | 
					#define WIN_STRING_FORMAT_LL "I64"
 | 
				
			||||||
 | 
					#endif  // MSC_VER >= 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A nonconforming version of swprintf, without the length argument, was
 | 
				
			||||||
 | 
					// included with the CRT prior to MSVC8.  Although a conforming version was
 | 
				
			||||||
 | 
					// also available via an overload, it is not reliably chosen.  _snwprintf
 | 
				
			||||||
 | 
					// behaves as a standards-confirming swprintf should, so force the use of
 | 
				
			||||||
 | 
					// _snwprintf when using older CRTs.
 | 
				
			||||||
 | 
					#if _MSC_VER < 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					#define swprintf _snwprintf
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently,
 | 
				
			||||||
 | 
					// it takes the same argument list as swprintf.
 | 
				
			||||||
 | 
					#define swprintf swprintf_s
 | 
				
			||||||
 | 
					#endif  // MSC_VER < 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using std::string;
 | 
				
			||||||
 | 
					using std::wstring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WindowsStringUtils {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
 | 
				
			||||||
 | 
					  // not fail if source is longer than destination_size.  The destination
 | 
				
			||||||
 | 
					  // buffer is always 0-terminated.
 | 
				
			||||||
 | 
					  static void safe_wcscpy(wchar_t *destination, size_t destination_size,
 | 
				
			||||||
 | 
					                          const wchar_t *source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
 | 
				
			||||||
 | 
					  // be passed directly, and pre-MSVC8, this will not fail if source or count
 | 
				
			||||||
 | 
					  // are longer than destination_size.  The destination buffer is always
 | 
				
			||||||
 | 
					  // 0-terminated.
 | 
				
			||||||
 | 
					  static void safe_wcsncpy(wchar_t *destination, size_t destination_size,
 | 
				
			||||||
 | 
					                           const wchar_t *source, size_t count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Performs multi-byte to wide character conversion on C++ strings, using
 | 
				
			||||||
 | 
					  // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8).  Returns false on failure,
 | 
				
			||||||
 | 
					  // without setting wcs.
 | 
				
			||||||
 | 
					  static bool safe_mbstowcs(const string &mbs, wstring *wcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The inverse of safe_mbstowcs.
 | 
				
			||||||
 | 
					  static bool safe_wcstombs(const wstring &wcs, string *mbs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Returns the base name of a file, e.g. strips off the path.
 | 
				
			||||||
 | 
					  static wstring GetBaseName(const wstring &filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  // Disallow instantiation and other object-based operations.
 | 
				
			||||||
 | 
					  WindowsStringUtils();
 | 
				
			||||||
 | 
					  WindowsStringUtils(const WindowsStringUtils&);
 | 
				
			||||||
 | 
					  ~WindowsStringUtils();
 | 
				
			||||||
 | 
					  void operator=(const WindowsStringUtils&);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
 | 
				
			||||||
 | 
					                                            size_t destination_size,
 | 
				
			||||||
 | 
					                                            const wchar_t *source) {
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  wcscpy_s(destination, destination_size, source);
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  // Pre-MSVC 2005/8 doesn't have wcscpy_s.  Simulate it with wcsncpy.
 | 
				
			||||||
 | 
					  // wcsncpy doesn't 0-terminate the destination buffer if the source string
 | 
				
			||||||
 | 
					  // is longer than size.  Ensure that the destination is 0-terminated.
 | 
				
			||||||
 | 
					  wcsncpy(destination, source, destination_size);
 | 
				
			||||||
 | 
					  if (destination && destination_size)
 | 
				
			||||||
 | 
					    destination[destination_size - 1] = 0;
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
 | 
				
			||||||
 | 
					                                             size_t destination_size,
 | 
				
			||||||
 | 
					                                             const wchar_t *source,
 | 
				
			||||||
 | 
					                                             size_t count) {
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  wcsncpy_s(destination, destination_size, source, count);
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  // Pre-MSVC 2005/8 doesn't have wcsncpy_s.  Simulate it with wcsncpy.
 | 
				
			||||||
 | 
					  // wcsncpy doesn't 0-terminate the destination buffer if the source string
 | 
				
			||||||
 | 
					  // is longer than size.  Ensure that the destination is 0-terminated.
 | 
				
			||||||
 | 
					  if (destination_size < count)
 | 
				
			||||||
 | 
					    count = destination_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wcsncpy(destination, source, count);
 | 
				
			||||||
 | 
					  if (destination && count)
 | 
				
			||||||
 | 
					    destination[count - 1] = 0;
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // COMMON_WINDOWS_STRING_UTILS_INL_H__
 | 
				
			||||||
							
								
								
									
										133
									
								
								google-breakpad/src/common/windows/string_utils.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								google-breakpad/src/common/windows/string_utils.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2006, Google Inc.
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					// modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					// met:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					// notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					//     * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					// copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					// in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					// distribution.
 | 
				
			||||||
 | 
					//     * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					// contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					// this software without specific prior written permission.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/windows/string_utils-inl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace google_breakpad {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
 | 
				
			||||||
 | 
					  wstring base_name(filename);
 | 
				
			||||||
 | 
					  size_t slash_pos = base_name.find_last_of(L"/\\");
 | 
				
			||||||
 | 
					  if (slash_pos != wstring::npos) {
 | 
				
			||||||
 | 
					    base_name.erase(0, slash_pos + 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return base_name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
 | 
				
			||||||
 | 
					  assert(wcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // First, determine the length of the destination buffer.
 | 
				
			||||||
 | 
					  size_t wcs_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  errno_t err;
 | 
				
			||||||
 | 
					  if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  assert(wcs_length > 0);
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) < 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Leave space for the 0-terminator.
 | 
				
			||||||
 | 
					  ++wcs_length;
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<wchar_t> wcs_v(wcs_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Now, convert.
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(),
 | 
				
			||||||
 | 
					                        _TRUNCATE)) != 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) < 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ensure presence of 0-terminator.
 | 
				
			||||||
 | 
					  wcs_v[wcs_length - 1] = '\0';
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *wcs = &wcs_v[0];
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) {
 | 
				
			||||||
 | 
					  assert(mbs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // First, determine the length of the destination buffer.
 | 
				
			||||||
 | 
					  size_t mbs_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  errno_t err;
 | 
				
			||||||
 | 
					  if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  assert(mbs_length > 0);
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) < 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Leave space for the 0-terminator.
 | 
				
			||||||
 | 
					  ++mbs_length;
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<char> mbs_v(mbs_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Now, convert.
 | 
				
			||||||
 | 
					#if _MSC_VER >= 1400  // MSVC 2005/8
 | 
				
			||||||
 | 
					  if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(),
 | 
				
			||||||
 | 
					                        _TRUNCATE)) != 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#else  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					  if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) < 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ensure presence of 0-terminator.
 | 
				
			||||||
 | 
					  mbs_v[mbs_length - 1] = '\0';
 | 
				
			||||||
 | 
					#endif  // _MSC_VER >= 1400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *mbs = &mbs_v[0];
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace google_breakpad
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user