143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Copyright (c) 2005, Google Inc. 243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// All rights reserved. 343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// 443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Redistribution and use in source and binary forms, with or without 543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// modification, are permitted provided that the following conditions are 643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// met: 743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// 843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// * Redistributions of source code must retain the above copyright 943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// notice, this list of conditions and the following disclaimer. 1043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// * Redistributions in binary form must reproduce the above 1143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// copyright notice, this list of conditions and the following disclaimer 1243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// in the documentation and/or other materials provided with the 1343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// distribution. 1443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// * Neither the name of Google Inc. nor the names of its 1543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// contributors may be used to endorse or promote products derived from 1643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// this software without specific prior written permission. 1743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// 1843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 3043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// --- 3143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Author: Craig Silverstein 3243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// 3343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// This is an internal header file used by profiler.cc. It defines 3443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// the single (inline) function GetPC. GetPC is used in a signal 3556454717593e7552d6846198b8e0f661fa36a3cayangguo@chromium.org// handler to figure out the instruction that was being executed when 3643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// the signal-handler was triggered. 3743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// 3843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// To get this, we use the ucontext_t argument to the signal-handler 3993a47f4837f2137c8d8349250fd8e91da3108126jkummerow@chromium.org// callback, which holds the full context of what was going on when 409dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// the signal triggered. How to get from a ucontext_t to a Program 4143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Counter is OS-dependent. 4243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 4343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#ifndef BASE_GETPC_H_ 4443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#define BASE_GETPC_H_ 4571affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org 4671affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org#include "config.h" 4743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 4843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// On many linux systems, we may need _GNU_SOURCE to get access to 4943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// the defined constants that define the register we want to see (eg 5043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// REG_EIP). Note this #define must come first! 51c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org#define _GNU_SOURCE 1 52c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org// If #define _GNU_SOURCE causes problems, this might work instead. 53c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org// It will cause problems for FreeBSD though!, because it turns off 54c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org// the needed __BSD_VISIBLE. 55750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org//#define _XOPEN_SOURCE 500 5663ea3d20e0c5531a4bb0853218d5f746117edea1mvstanton@chromium.org 5743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#include <string.h> // for memcmp 5843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#if defined(HAVE_SYS_UCONTEXT_H) 59003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org#include <sys/ucontext.h> 60003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org#elif defined(HAVE_UCONTEXT_H) 61003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org#include <ucontext.h> // for ucontext_t (and also mcontext_t) 62003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org#elif defined(HAVE_CYGWIN_SIGNAL_H) 63003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org#include <cygwin/signal.h> 64003650ee766f5e92756d470a37973fd371757485yangguo@chromium.orgtypedef ucontext ucontext_t; 65a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org#endif 66a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org 67a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org 68a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// Take the example where function Foo() calls function Bar(). For 69169691d93a961c8b511f8ac8fd8ee33d081ca10fdanno@chromium.org// many architectures, Bar() is responsible for setting up and tearing 70a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// down its own stack frame. In that case, it's possible for the 71a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// interrupt to happen when execution is in Bar(), but the stack frame 72a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// is not properly set up (either before it's done being set up, or 73a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// after it's been torn down but before Bar() returns). In those 74a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// cases, the stack trace cannot see the caller function anymore. 75a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// 76a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// GetPC can try to identify this situation, on architectures where it 77a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// might occur, and unwind the current function call in that case to 78169691d93a961c8b511f8ac8fd8ee33d081ca10fdanno@chromium.org// avoid false edges in the profile graph (that is, edges that appear 79a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// to show a call skipping over a function). To do this, we hard-code 80a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// in the asm instructions we might see when setting up or tearing 81a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// down a stack frame. 82a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// 83a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// This is difficult to get right: the instructions depend on the 84a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// processor, the compiler ABI, and even the optimization level. This 85a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// is a best effort patch -- if we fail to detect such a situation, or 86a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org// mess up the PC, nothing happens; the returned PC is not used for 87169691d93a961c8b511f8ac8fd8ee33d081ca10fdanno@chromium.org// any further processing. 88a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.orgstruct CallUnrollInfo { 89a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org // Offset from (e)ip register where this instruction sequence 90a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org // should be matched. Interpreted as bytes. Offset 0 is the next 91a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org // instruction to execute. Be extra careful with negative offsets in 92c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org // architectures of variable instruction length (like x86) - it is 93c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org // not that easy as taking an offset to step one instruction back! 94061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org int pc_offset; 95c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org // The actual instruction bytes. Feel free to make it larger if you 96c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org // need a longer sequence. 97c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org char ins[16]; 98c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org // How many bytes to match from ins array? 99c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org int ins_size; 100c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org // The offset from the stack pointer (e)sp where to look for the 101c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org // call return address. Interpreted as bytes. 102061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org int return_sp_offset; 1031e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org}; 1041e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org 1051e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org 1061e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org// The dereferences needed to get the PC from a struct ucontext were 107c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org// determined at configure time, and stored in the macro 1081e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org// PC_FROM_UCONTEXT in config.h. The only thing we need to do here, 1091e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org// then, is to do the magic call-unrolling for systems that support it. 110c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org 1111e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org// -- Special case 1: linux x86, for which we have CallUnrollInfo 1121e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org#if defined(__linux) && defined(__i386) && defined(__GNUC__) 1131e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.orgstatic const CallUnrollInfo callunrollinfo[] = { 1141e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org // Entry to a function: push %ebp; mov %esp,%ebp 1151e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org // Top-of-stack contains the caller IP. 11643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen { 0, 1171e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org {0x55, 0x89, 0xe5}, 3, 1181e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org 0 1191e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org }, 1201e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org // Entry to a function, second instruction: push %ebp; mov %esp,%ebp 1211e8da746019f818a22dfdc6f691dbc0447048cadjkummerow@chromium.org // Top-of-stack contains the old frame, caller IP is +4. 122750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org { -1, 123750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org {0x55, 0x89, 0xe5}, 3, 124750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org 4 12543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen }, 12643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Return from a function: RET. 12743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // Top-of-stack contains the caller IP. 12843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen { 0, 1297276f14ca716596e0a0d17539516370c1f453847kasper.lund {0xc3}, 1, 1307276f14ca716596e0a0d17539516370c1f453847kasper.lund 0 1317276f14ca716596e0a0d17539516370c1f453847kasper.lund } 1327276f14ca716596e0a0d17539516370c1f453847kasper.lund}; 1337276f14ca716596e0a0d17539516370c1f453847kasper.lund 1347276f14ca716596e0a0d17539516370c1f453847kasper.lundinline void* GetPC(const ucontext_t& signal_ucontext) { 1357276f14ca716596e0a0d17539516370c1f453847kasper.lund // See comment above struct CallUnrollInfo. Only try instruction 1367276f14ca716596e0a0d17539516370c1f453847kasper.lund // flow matching if both eip and esp looks reasonable. 13743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen const int eip = signal_ucontext.uc_mcontext.gregs[REG_EIP]; 1387276f14ca716596e0a0d17539516370c1f453847kasper.lund const int esp = signal_ucontext.uc_mcontext.gregs[REG_ESP]; 1397276f14ca716596e0a0d17539516370c1f453847kasper.lund if ((eip & 0xffff0000) != 0 && (~eip & 0xffff0000) != 0 && 1407276f14ca716596e0a0d17539516370c1f453847kasper.lund (esp & 0xffff0000) != 0) { 1417276f14ca716596e0a0d17539516370c1f453847kasper.lund char* eip_char = reinterpret_cast<char*>(eip); 14243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen for (int i = 0; i < sizeof(callunrollinfo)/sizeof(*callunrollinfo); ++i) { 14343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen if (!memcmp(eip_char + callunrollinfo[i].pc_offset, 14443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen callunrollinfo[i].ins, callunrollinfo[i].ins_size)) { 14543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen // We have a match. 14643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen void **retaddr = (void**)(esp + callunrollinfo[i].return_sp_offset); 14743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return *retaddr; 14843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 149236ad9617a7359a463144a6ebeb5431a70f769cfager@chromium.org } 150c4e51ac6d26b42753a57a4a9e4a419243b50151clrn@chromium.org } 151e4ac3ef2f6fa9300bc78c5a4cb7d4cb66ac6e83dmvstanton@chromium.org return (void*)eip; 15243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen} 15343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1549dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// Special case #2: Windows, which has to do something totally different. 1559dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com#elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) 1569dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// If this is ever implemented, probably the way to do it is to have 1579dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// profiler.cc use a high-precision timer via timeSetEvent: 1589dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// http://msdn2.microsoft.com/en-us/library/ms712713.aspx 1599dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// We'd use it in mode TIME_CALLBACK_FUNCTION/TIME_PERIODIC. 1609dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// The callback function would be something like prof_handler, but 1619dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// alas the arguments are different: no ucontext_t! I don't know 1629dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com// how we'd get the PC (using StackWalk64?) 163245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org// http://msdn2.microsoft.com/en-us/library/ms680650.aspx 16443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 16543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#include "base/logging.h" // for RAW_LOG 16643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen#ifndef HAVE_CYGWIN_SIGNAL_H 16743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansentypedef int ucontext_t; 1684af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org#endif 1694af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org 1704af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.orginline void* GetPC(const struct ucontext_t& signal_ucontext) { 17143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); 17243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return NULL; 17343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen} 17443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 17543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Normal cases. If this doesn't compile, it's probably because 176245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org// PC_FROM_UCONTEXT is the empty string. You need to figure out 17743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// the right value for your system, and add it to the list in 1784af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org// configure.ac (or set it manually in your config.h). 1794af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org#else 18043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hanseninline void* GetPC(const ucontext_t& signal_ucontext) { 1814af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org return (void*)signal_ucontext.PC_FROM_UCONTEXT; // defined in config.h 18243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen} 1834af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org 1844af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org#endif 1854af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org 1864af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org#endif // BASE_GETPC_H_ 1874af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org