OLD | NEW |
---|---|
1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 //#define _XOPEN_SOURCE 500 | 55 //#define _XOPEN_SOURCE 500 |
56 | 56 |
57 #include <string.h> // for memcmp | 57 #include <string.h> // for memcmp |
58 #if defined(HAVE_SYS_UCONTEXT_H) | 58 #if defined(HAVE_SYS_UCONTEXT_H) |
59 #include <sys/ucontext.h> | 59 #include <sys/ucontext.h> |
60 #elif defined(HAVE_UCONTEXT_H) | 60 #elif defined(HAVE_UCONTEXT_H) |
61 #include <ucontext.h> // for ucontext_t (and also mcontext_t) | 61 #include <ucontext.h> // for ucontext_t (and also mcontext_t) |
62 #elif defined(HAVE_CYGWIN_SIGNAL_H) | 62 #elif defined(HAVE_CYGWIN_SIGNAL_H) |
63 #include <cygwin/signal.h> | 63 #include <cygwin/signal.h> |
64 typedef ucontext ucontext_t; | 64 typedef ucontext ucontext_t; |
65 #elif defined(__ANDROID__) | |
66 #include <unwind.h> | |
65 #endif | 67 #endif |
66 | 68 |
67 | 69 |
68 // Take the example where function Foo() calls function Bar(). For | 70 // Take the example where function Foo() calls function Bar(). For |
69 // many architectures, Bar() is responsible for setting up and tearing | 71 // many architectures, Bar() is responsible for setting up and tearing |
70 // down its own stack frame. In that case, it's possible for the | 72 // down its own stack frame. In that case, it's possible for the |
71 // interrupt to happen when execution is in Bar(), but the stack frame | 73 // interrupt to happen when execution is in Bar(), but the stack frame |
72 // is not properly set up (either before it's done being set up, or | 74 // is not properly set up (either before it's done being set up, or |
73 // after it's been torn down but before Bar() returns). In those | 75 // after it's been torn down but before Bar() returns). In those |
74 // cases, the stack trace cannot see the caller function anymore. | 76 // cases, the stack trace cannot see the caller function anymore. |
(...skipping 27 matching lines...) Expand all Loading... | |
102 int return_sp_offset; | 104 int return_sp_offset; |
103 }; | 105 }; |
104 | 106 |
105 | 107 |
106 // The dereferences needed to get the PC from a struct ucontext were | 108 // The dereferences needed to get the PC from a struct ucontext were |
107 // determined at configure time, and stored in the macro | 109 // determined at configure time, and stored in the macro |
108 // PC_FROM_UCONTEXT in config.h. The only thing we need to do here, | 110 // PC_FROM_UCONTEXT in config.h. The only thing we need to do here, |
109 // then, is to do the magic call-unrolling for systems that support it. | 111 // then, is to do the magic call-unrolling for systems that support it. |
110 | 112 |
111 // -- Special case 1: linux x86, for which we have CallUnrollInfo | 113 // -- Special case 1: linux x86, for which we have CallUnrollInfo |
112 #if defined(__linux) && defined(__i386) && defined(__GNUC__) | 114 #if defined(__linux) && defined(__i386) && defined(__GNUC__) |
Dai Mikurube (NOT FULLTIME)
2013/05/03 08:53:00
I'm not sure if we have x86 Android, but we may wa
bulach
2013/05/07 14:55:51
we do have x86, added the guard here.
| |
113 static const CallUnrollInfo callunrollinfo[] = { | 115 static const CallUnrollInfo callunrollinfo[] = { |
114 // Entry to a function: push %ebp; mov %esp,%ebp | 116 // Entry to a function: push %ebp; mov %esp,%ebp |
115 // Top-of-stack contains the caller IP. | 117 // Top-of-stack contains the caller IP. |
116 { 0, | 118 { 0, |
117 {0x55, 0x89, 0xe5}, 3, | 119 {0x55, 0x89, 0xe5}, 3, |
118 0 | 120 0 |
119 }, | 121 }, |
120 // Entry to a function, second instruction: push %ebp; mov %esp,%ebp | 122 // Entry to a function, second instruction: push %ebp; mov %esp,%ebp |
121 // Top-of-stack contains the old frame, caller IP is +4. | 123 // Top-of-stack contains the old frame, caller IP is +4. |
122 { -1, | 124 { -1, |
123 {0x55, 0x89, 0xe5}, 3, | 125 {0x55, 0x89, 0xe5}, 3, |
124 4 | 126 4 |
125 }, | 127 }, |
126 // Return from a function: RET. | 128 // Return from a function: RET. |
127 // Top-of-stack contains the caller IP. | 129 // Top-of-stack contains the caller IP. |
128 { 0, | 130 { 0, |
129 {0xc3}, 1, | 131 {0xc3}, 1, |
130 0 | 132 0 |
131 } | 133 } |
132 }; | 134 }; |
133 | 135 |
134 inline void* GetPC(const ucontext_t& signal_ucontext) { | 136 inline void* GetPC(const ucontext_t& signal_ucontext) { |
135 // See comment above struct CallUnrollInfo. Only try instruction | 137 // See comment above struct CallUnrollInfo. Only try instruction |
136 // flow matching if both eip and esp looks reasonable. | 138 // flow matching if both eip and esp looks reasonable. |
137 const int eip = signal_ucontext.uc_mcontext.gregs[REG_EIP]; | 139 const int eip = signal_ucontext.uc_mcontext.gregs[REG_EIP]; |
138 const int esp = signal_ucontext.uc_mcontext.gregs[REG_ESP]; | 140 const int esp = signal_ucontext.uc_mcontext.gregs[REG_ESP]; |
139 if ((eip & 0xffff0000) != 0 && (~eip & 0xffff0000) != 0 && | 141 if ((eip & 0xffff0000) != 0 && (~eip & 0xffff0000) != 0 && |
140 (esp & 0xffff0000) != 0) { | 142 (esp & 0xffff0000) != 0) { |
141 char* eip_char = reinterpret_cast<char*>(eip); | 143 char* eip_char = reinterpret_cast<char*>(eip); |
142 for (int i = 0; i < sizeof(callunrollinfo)/sizeof(*callunrollinfo); ++i) { | 144 for (int i = 0; i < sizeof(CallUnrollInfo)/sizeof(*callunrollinfo); ++i) { |
Dai Mikurube (NOT FULLTIME)
2013/05/03 08:53:00
It's necessary? (Since tcmalloc is a third_party
bulach
2013/05/07 14:55:51
Done.
| |
143 if (!memcmp(eip_char + callunrollinfo[i].pc_offset, | 145 if (!memcmp(eip_char + callunrollinfo[i].pc_offset, |
144 callunrollinfo[i].ins, callunrollinfo[i].ins_size)) { | 146 callunrollinfo[i].ins, callunrollinfo[i].ins_size)) { |
145 // We have a match. | 147 // We have a match. |
146 void **retaddr = (void**)(esp + callunrollinfo[i].return_sp_offset); | 148 void **retaddr = (void**)(esp + callunrollinfo[i].return_sp_offset); |
147 return *retaddr; | 149 return *retaddr; |
148 } | 150 } |
149 } | 151 } |
150 } | 152 } |
151 return (void*)eip; | 153 return (void*)eip; |
152 } | 154 } |
(...skipping 11 matching lines...) Expand all Loading... | |
164 | 166 |
165 #include "base/logging.h" // for RAW_LOG | 167 #include "base/logging.h" // for RAW_LOG |
166 #ifndef HAVE_CYGWIN_SIGNAL_H | 168 #ifndef HAVE_CYGWIN_SIGNAL_H |
167 typedef int ucontext_t; | 169 typedef int ucontext_t; |
168 #endif | 170 #endif |
169 | 171 |
170 inline void* GetPC(const struct ucontext_t& signal_ucontext) { | 172 inline void* GetPC(const struct ucontext_t& signal_ucontext) { |
171 RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); | 173 RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); |
172 return NULL; | 174 return NULL; |
173 } | 175 } |
176 #elif defined(__ANDROID__) | |
174 | 177 |
178 typedef struct _Unwind_Context ucontext_t; | |
179 | |
180 inline void* GetPC(const ucontext_t& signal_ucontext) { | |
181 // Bionic doesn't export ucontext, see | |
182 // https://code.google.com/p/android/issues/detail?id=34784. | |
183 return reinterpret_cast<void*>(_Unwind_GetIP( | |
184 const_cast<ucontext_t*>(&signal_ucontext))); | |
185 } | |
186 #else | |
187 // | |
175 // Normal cases. If this doesn't compile, it's probably because | 188 // Normal cases. If this doesn't compile, it's probably because |
176 // PC_FROM_UCONTEXT is the empty string. You need to figure out | 189 // PC_FROM_UCONTEXT is the empty string. You need to figure out |
177 // the right value for your system, and add it to the list in | 190 // the right value for your system, and add it to the list in |
178 // configure.ac (or set it manually in your config.h). | 191 // configure.ac (or set it manually in your config.h). |
179 #else | |
180 inline void* GetPC(const ucontext_t& signal_ucontext) { | 192 inline void* GetPC(const ucontext_t& signal_ucontext) { |
181 return (void*)signal_ucontext.PC_FROM_UCONTEXT; // defined in config.h | 193 return (void*)signal_ucontext.PC_FROM_UCONTEXT; // defined in config.h |
182 } | 194 } |
183 | 195 |
184 #endif | 196 #endif |
185 | 197 |
186 #endif // BASE_GETPC_H_ | 198 #endif // BASE_GETPC_H_ |
OLD | NEW |