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