aboutsummaryrefslogtreecommitdiff
path: root/src/client/solaris/handler/solaris_lwp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/solaris/handler/solaris_lwp.cc')
-rw-r--r--src/client/solaris/handler/solaris_lwp.cc125
1 files changed, 116 insertions, 9 deletions
diff --git a/src/client/solaris/handler/solaris_lwp.cc b/src/client/solaris/handler/solaris_lwp.cc
index 9ce7b4fd..0148997a 100644
--- a/src/client/solaris/handler/solaris_lwp.cc
+++ b/src/client/solaris/handler/solaris_lwp.cc
@@ -30,9 +30,11 @@
// Author: Alfred Peng
#include <dirent.h>
+#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <sys/frame.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -56,6 +58,16 @@ uintptr_t stack_base_address = 0;
static const int HEADER_MAX = 2000;
static const int MAP_MAX = 1000;
+// Context information for the callbacks when validating address by listing
+// modules.
+struct AddressValidatingContext {
+ uintptr_t address;
+ bool is_mapped;
+
+ AddressValidatingContext() : address(0UL), is_mapped(false) {
+ }
+};
+
// Convert from string to int.
static bool LocalAtoi(char *s, int *r) {
assert(s != NULL);
@@ -69,18 +81,19 @@ static bool LocalAtoi(char *s, int *r) {
}
// Callback invoked for each mapped module.
-// It use the module's adderss range to validate the address.
+// It uses the module's adderss range to validate the address.
static bool AddressNotInModuleCallback(const ModuleInfo &module_info,
void *context) {
- uintptr_t addr = reinterpret_cast<uintptr_t>(context);
- if ((module_info.start_addr > 0) &&
- (addr >= module_info.start_addr) &&
- (addr <= module_info.start_addr + module_info.size)) {
+ AddressValidatingContext *addr =
+ reinterpret_cast<AddressValidatingContext *>(context);
+ if (addr->is_mapped = ((module_info.start_addr > 0) &&
+ (addr->address >= module_info.start_addr) &&
+ (addr->address <= module_info.start_addr +
+ module_info.size))) {
stack_base_address = module_info.start_addr + module_info.size;
- return false;
}
- return true;
+ return !addr->is_mapped;
}
static int IterateLwpAll(int pid,
@@ -114,6 +127,28 @@ static int IterateLwpAll(int pid,
return count;
}
+#if defined(__i386) && !defined(NO_FRAME_POINTER)
+void *GetNextFrame(void **last_ebp) {
+ void *sp = *last_ebp;
+ if ((unsigned long)sp == (unsigned long)last_ebp)
+ return NULL;
+ if ((unsigned long)sp & (sizeof(void *) - 1))
+ return NULL;
+ if ((unsigned long)sp - (unsigned long)last_ebp > 100000)
+ return NULL;
+ return sp;
+}
+#elif defined(__sparc)
+void *GetNextFrame(void *last_ebp) {
+ return reinterpret_cast<struct frame *>(last_ebp)->fr_savfp;
+}
+#else
+void *GetNextFrame(void **last_ebp) {
+ return reinterpret_cast<void*>(last_ebp);
+}
+#endif
+
+
class AutoCloser {
public:
AutoCloser(int fd) : fd_(fd) {}
@@ -250,8 +285,10 @@ int SolarisLwp::Lwp_iter_all(int pid,
}
uintptr_t SolarisLwp::GetLwpStackBottom(uintptr_t current_esp) const {
+ AddressValidatingContext addr;
+ addr.address = current_esp;
CallbackParam<ModuleCallback> callback_param(AddressNotInModuleCallback,
- (void *)current_esp);
+ &addr);
ListModules(&callback_param);
return stack_base_address;
}
@@ -313,7 +350,28 @@ int SolarisLwp::ListModules(
memset(&module, 0, sizeof (module));
module.start_addr = _maps->pr_vaddr;
module.size = _maps->pr_size;
- if ((strlen(name) > 0) && (strcmp(name, "a.out") != 0)) {
+ if (strlen(name) > 0) {
+ int objectfd = 0;
+ char path[PATH_MAX];
+ char buf[SELFMAG];
+
+ snprintf(path, sizeof (path), "/proc/self/object/%s", name);
+ if ((objectfd = open(path, O_RDONLY)) < 0) {
+ print_message1(2, "can't open module file\n");
+ continue;
+ }
+
+ AutoCloser autocloser(objectfd);
+
+ if (read(objectfd, buf, SELFMAG) != SELFMAG) {
+ print_message1(2, "can't read module file\n");
+ continue;
+ }
+ if (buf[0] != ELFMAG0 || buf[1] != ELFMAG1 ||
+ buf[2] != ELFMAG2 || buf[3] != ELFMAG3) {
+ continue;
+ }
+
strncpy(module.name, name, sizeof (module.name) - 1);
++module_count;
}
@@ -326,4 +384,53 @@ int SolarisLwp::ListModules(
return module_count;
}
+// Check if the address is a valid virtual address.
+// If the address is in any of the mapped modules, we take it as valid.
+// Otherwise it is invalid.
+bool SolarisLwp::IsAddressMapped(uintptr_t address) const {
+ AddressValidatingContext addr;
+ addr.address = address;
+ CallbackParam<ModuleCallback> callback_param(AddressNotInModuleCallback,
+ &addr);
+ ListModules(&callback_param);
+ return addr.is_mapped;
+}
+
+// We're looking for a ucontext_t as the second parameter
+// to a signal handler function call. Luckily, the ucontext_t
+// has an ebp(fp on SPARC) member which should match the ebp(fp)
+// pointed to by the ebp(fp) of the signal handler frame.
+// The Solaris stack looks like this:
+// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81
+bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp,
+ ucontext_t **sig_ctx) {
+ uintptr_t previous_ebp;
+ uintptr_t sig_ebp;
+ const int MAX_STACK_DEPTH = 50;
+ int depth_counter = 0;
+
+ do {
+#if TARGET_CPU_SPARC
+ previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
+ reinterpret_cast<void*>(sighandler_ebp)));
+ *sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame));
+ uintptr_t sig_esp = (*sig_ctx)->uc_mcontext.gregs[REG_O6];
+ if (sig_esp < previous_ebp && sig_esp > sighandler_ebp)
+ sig_ebp = (uintptr_t)(((struct frame *)sig_esp)->fr_savfp);
+
+#elif TARGET_CPU_X86
+ previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
+ reinterpret_cast<void**>(sighandler_ebp)));
+ *sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame) +
+ 3 * sizeof(uintptr_t));
+ sig_ebp = (*sig_ctx)->uc_mcontext.gregs[EBP];
+#endif
+ sighandler_ebp = previous_ebp;
+ depth_counter++;
+ } while(previous_ebp != sig_ebp && sighandler_ebp != 0 &&
+ IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH);
+
+ return previous_ebp == sig_ebp && previous_ebp != 0;
+}
+
} // namespace google_breakpad