diff options
Diffstat (limited to 'src/client/solaris/handler/solaris_lwp.cc')
-rw-r--r-- | src/client/solaris/handler/solaris_lwp.cc | 125 |
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 |