19e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura/* libunwind - a platform-independent unwind library 23b9fd99cb78383e0ce8cd1a31e3b824a30ef965eLassi Tuura Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY 39e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 49e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraThis file is part of libunwind. 59e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 69e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraPermission is hereby granted, free of charge, to any person obtaining 79e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuuraa copy of this software and associated documentation files (the 89e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura"Software"), to deal in the Software without restriction, including 99e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuurawithout limitation the rights to use, copy, modify, merge, publish, 109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuuradistribute, sublicense, and/or sell copies of the Software, and to 119e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuurapermit persons to whom the Software is furnished to do so, subject to 129e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuurathe following conditions: 139e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 149e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraThe above copyright notice and this permission notice shall be 159e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuuraincluded in all copies or substantial portions of the Software. 169e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 179e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 189e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 199e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 209e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 219e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 229e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 239e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi TuuraWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 249e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 259e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura#include "unwind_i.h" 269e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura#include "ucontext_i.h" 279e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura#include <signal.h> 280a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma#include <limits.h> 299e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura#pragma weak pthread_once 3144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura#pragma weak pthread_key_create 3244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura#pragma weak pthread_getspecific 3344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura#pragma weak pthread_setspecific 3444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 35d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura/* Initial hash table size. Table expands by 2 bits (times four). */ 36d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura#define HASH_MIN_BITS 14 379e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratypedef struct 3944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura{ 40d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura unw_tdep_frame_t *frames; 41d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura size_t log_size; 4244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura size_t used; 430a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma size_t dtor_count; /* Counts how many times our destructor has already 440a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma been called. */ 4544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura} unw_trace_cache_t; 4644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 4744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic const unw_tdep_frame_t empty_frame = { 0, UNW_X86_64_FRAME_OTHER, -1, -1, 0, -1, -1 }; 48aebba1f8a7dee9b9ae3e70128ad48de69ca90b15Tommi Rantalastatic define_lock (trace_init_lock); 4944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT; 5008077a4962c4e606598f9f0e54b515b3c882be10Arun Sharmastatic sig_atomic_t trace_cache_once_happen; 5144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic pthread_key_t trace_cache_key; 5244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic struct mempool trace_cache_pool; 530a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharmastatic __thread unw_trace_cache_t *tls_cache; 540a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharmastatic __thread int tls_cache_destroyed; 5544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 5644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura/* Free memory for a thread's trace cache. */ 5744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic void 5844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratrace_cache_free (void *arg) 599e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura{ 6044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_trace_cache_t *cache = arg; 610a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma if (++cache->dtor_count < PTHREAD_DESTRUCTOR_ITERATIONS) 620a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma { 630a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma /* Not yet our turn to get destroyed. Re-install ourselves into the key. */ 640a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma pthread_setspecific(trace_cache_key, cache); 650a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma Debug(5, "delayed freeing cache %p (%zx to go)\n", cache, 660a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma PTHREAD_DESTRUCTOR_ITERATIONS - cache->dtor_count); 670a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma return; 680a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma } 6952ca68c770e9128940748bab72a5b103057166a8Arun Sharma tls_cache_destroyed = 1; 7052ca68c770e9128940748bab72a5b103057166a8Arun Sharma tls_cache = NULL; 71d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura munmap (cache->frames, (1u << cache->log_size) * sizeof(unw_tdep_frame_t)); 7244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura mempool_free (&trace_cache_pool, cache); 7344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug(5, "freed cache %p\n", cache); 7444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura} 7544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 7644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura/* Initialise frame tracing for threaded use. */ 7744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic void 7844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratrace_cache_init_once (void) 7944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura{ 8044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura pthread_key_create (&trace_cache_key, &trace_cache_free); 81d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); 8208077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma trace_cache_once_happen = 1; 8344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura} 8444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 8544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic unw_tdep_frame_t * 86d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuuratrace_cache_buckets (size_t n) 8744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura{ 88d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura unw_tdep_frame_t *frames; 8944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura size_t i; 9044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 91d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura GET_MEMORY(frames, n * sizeof (unw_tdep_frame_t)); 92890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala if (likely(frames != NULL)) 93d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura for (i = 0; i < n; ++i) 9444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura frames[i] = empty_frame; 9544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 9644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return frames; 9744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura} 9844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 9944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura/* Allocate and initialise hash table for frame cache lookups. 10044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Returns the cache initialised with (1u << HASH_LOW_BITS) hash 10144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura buckets, or NULL if there was a memory allocation problem. */ 10244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic unw_trace_cache_t * 10344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratrace_cache_create (void) 10444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura{ 10544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_trace_cache_t *cache; 10644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 1070a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma if (tls_cache_destroyed) 1080a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma { 1090a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma /* The current thread is in the process of exiting. Don't recreate 1100a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma cache, as we wouldn't have another chance to free it. */ 1110a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma Debug(5, "refusing to reallocate cache: " 1120a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma "thread-locals are being deallocated\n"); 1130a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma return NULL; 1140a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma } 1150a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma 11644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura if (! (cache = mempool_alloc(&trace_cache_pool))) 11744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 11844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug(5, "failed to allocate cache\n"); 1190a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma return NULL; 12044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 1219e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 122d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura if (! (cache->frames = trace_cache_buckets(1u << HASH_MIN_BITS))) 12344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 12444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug(5, "failed to allocate buckets\n"); 12544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura mempool_free(&trace_cache_pool, cache); 1260a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma return NULL; 12744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 1289e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 129d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura cache->log_size = HASH_MIN_BITS; 13044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura cache->used = 0; 1310a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma cache->dtor_count = 0; 1320a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma tls_cache_destroyed = 0; /* Paranoia: should already be 0. */ 13344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug(5, "allocated cache %p\n", cache); 13444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return cache; 1359e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura} 1369e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 13744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura/* Expand the hash table in the frame cache if possible. This always 13844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura quadruples the hash size, and clears all previous frame entries. */ 13944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic int 14044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratrace_cache_expand (unw_trace_cache_t *cache) 1419e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura{ 142d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura size_t old_size = (1u << cache->log_size); 143d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura size_t new_log_size = cache->log_size + 2; 144d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura unw_tdep_frame_t *new_frames = trace_cache_buckets (1u << new_log_size); 145d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura 146d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura if (unlikely(! new_frames)) 14744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 148d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura Debug(5, "failed to expand cache to 2^%lu buckets\n", new_log_size); 14944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return -UNW_ENOMEM; 15044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 15144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 152d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura Debug(5, "expanded cache from 2^%lu to 2^%lu buckets\n", cache->log_size, new_log_size); 153d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura munmap(cache->frames, old_size * sizeof(unw_tdep_frame_t)); 154d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura cache->frames = new_frames; 155d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura cache->log_size = new_log_size; 156f1ea02be58c2127cc655ef3fd6a385a1bd22cdcdLassi Tuura cache->used = 0; 1579e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura return 0; 1589e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura} 1599e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 16008077a4962c4e606598f9f0e54b515b3c882be10Arun Sharmastatic unw_trace_cache_t * 16108077a4962c4e606598f9f0e54b515b3c882be10Arun Sharmatrace_cache_get_unthreaded (void) 16208077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma{ 16308077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma unw_trace_cache_t *cache; 16408077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma intrmask_t saved_mask; 165890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala static unw_trace_cache_t *global_cache = NULL; 16608077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma lock_acquire (&trace_init_lock, saved_mask); 16708077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma if (! global_cache) 16808077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma { 16908077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); 17008077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma global_cache = trace_cache_create (); 17108077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma } 17208077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma cache = global_cache; 17308077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma lock_release (&trace_init_lock, saved_mask); 17408077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma Debug(5, "using cache %p\n", cache); 17508077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma return cache; 17608077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma} 17708077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma 17844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura/* Get the frame cache for the current thread. Create it if there is none. */ 17944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuurastatic unw_trace_cache_t * 18044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuuratrace_cache_get (void) 18144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura{ 18244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_trace_cache_t *cache; 183890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala if (likely (pthread_once != NULL)) 18444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 18544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura pthread_once(&trace_cache_once, &trace_cache_init_once); 18608077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma if (!trace_cache_once_happen) 18708077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma { 18808077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma return trace_cache_get_unthreaded(); 18908077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma } 19015f182828d88ea51d419d94b3daabb7a69181c78Arun Sharma if (! (cache = tls_cache)) 19144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 19244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura cache = trace_cache_create(); 19344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura pthread_setspecific(trace_cache_key, cache); 19415f182828d88ea51d419d94b3daabb7a69181c78Arun Sharma tls_cache = cache; 19544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 19644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug(5, "using cache %p\n", cache); 19744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return cache; 19844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 19944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura else 20044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 20108077a4962c4e606598f9f0e54b515b3c882be10Arun Sharma return trace_cache_get_unthreaded(); 20244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 20344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura} 20444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 2059e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura/* Initialise frame properties for address cache slot F at address 2069e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura RIP using current CFA, RBP and RSP values. Modifies CURSOR to 2079e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura that location, performs one unw_step(), and fills F with what 2089e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura was discovered about the location. Returns F. 2099e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura FIXME: This probably should tell DWARF handling to never evaluate 2119e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura or use registers other than RBP, RSP and RIP in case there is 2129e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura highly unusual unwind info which uses these creatively. */ 2139e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuurastatic unw_tdep_frame_t * 2149e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuuratrace_init_addr (unw_tdep_frame_t *f, 2159e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_cursor_t *cursor, 2169e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t cfa, 2179e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rip, 2189e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rbp, 2199e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rsp) 2209e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura{ 2219e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura struct cursor *c = (struct cursor *) cursor; 2229e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura struct dwarf_cursor *d = &c->dwarf; 2239e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int ret = -UNW_EINVAL; 2249e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2259e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Initialise frame properties: unknown, not last. */ 2269e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->virtual_address = rip; 2279e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->frame_type = UNW_X86_64_FRAME_OTHER; 2289e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->last_frame = 0; 2299e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->cfa_reg_rsp = -1; 2309e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->cfa_reg_offset = 0; 2319e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->rbp_cfa_offset = -1; 2329e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->rsp_cfa_offset = -1; 2339e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2349e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Reinitialise cursor to this instruction - but undo next/prev RIP 2359e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura adjustment because unw_step will redo it - and force RIP, RBP 2369e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura RSP into register locations (=~ ucontext we keep), then set 2379e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura their desired values. Then perform the step. */ 2389e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->ip = rip + d->use_prev_instr; 2399e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->cfa = cfa; 2409e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->loc[UNW_X86_64_RIP] = DWARF_REG_LOC (d, UNW_X86_64_RIP); 2419e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->loc[UNW_X86_64_RBP] = DWARF_REG_LOC (d, UNW_X86_64_RBP); 2429e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->loc[UNW_X86_64_RSP] = DWARF_REG_LOC (d, UNW_X86_64_RSP); 2439e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura c->frame_info = *f; 2449e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 245ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(dwarf_put (d, d->loc[UNW_X86_64_RIP], rip) >= 0) 246ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura && likely(dwarf_put (d, d->loc[UNW_X86_64_RBP], rbp) >= 0) 247ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura && likely(dwarf_put (d, d->loc[UNW_X86_64_RSP], rsp) >= 0) 248ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura && likely((ret = unw_step (cursor)) >= 0)) 2499e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura *f = c->frame_info; 2509e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2519e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* If unw_step() stopped voluntarily, remember that, even if it 2529e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura otherwise could not determine anything useful. This avoids 2539e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura failing trace if we hit frames without unwind info, which is 2549e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura common for the outermost frame (CRT stuff) on many systems. 2559e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura This avoids failing trace in very common circumstances; failing 2569e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura to unw_step() loop wouldn't produce any better result. */ 2579e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura if (ret == 0) 2589e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->last_frame = -1; 2599e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2609e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (3, "frame va %lx type %d last %d cfa %s+%d rbp @ cfa%+d rsp @ cfa%+d\n", 2619e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->virtual_address, f->frame_type, f->last_frame, 2629e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->cfa_reg_rsp ? "rsp" : "rbp", f->cfa_reg_offset, 2639e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->rbp_cfa_offset, f->rsp_cfa_offset); 2649e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2659e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura return f; 2669e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura} 2679e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2689e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura/* Look up and if necessary fill in frame attributes for address RIP 2699e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura in CACHE using current CFA, RBP and RSP values. Uses CURSOR to 2709e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura perform any unwind steps necessary to fill the cache. Returns the 2719e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura frame cache slot which describes RIP. */ 2729e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuurastatic unw_tdep_frame_t * 2739e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuuratrace_lookup (unw_cursor_t *cursor, 27444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_trace_cache_t *cache, 2759e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t cfa, 2769e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rip, 2779e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rbp, 2789e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rsp) 2799e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura{ 2809e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* First look up for previously cached information using cache as 2819e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura linear probing hash table with probe step of 1. Majority of 2829e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura lookups should be completed within few steps, but it is very 2839e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura important the hash table does not fill up, or performance falls 2849e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura off the cliff. */ 285d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura uint64_t i, addr; 286d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura uint64_t cache_size = 1u << cache->log_size; 28744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura uint64_t slot = ((rip * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); 28844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_tdep_frame_t *frame; 2899e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 29044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura for (i = 0; i < 16; ++i) 2919e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 292d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura frame = &cache->frames[slot]; 29344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura addr = frame->virtual_address; 2949e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 2959e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Return if we found the address. */ 296ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(addr == rip)) 2979e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 2989e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (4, "found address after %ld steps\n", i); 29944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return frame; 3009e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 3019e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3029e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* If slot is empty, reuse it. */ 303ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(! addr)) 3049e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 3059e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3069e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Linear probe to next slot candidate, step = 1. */ 30744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura if (++slot >= cache_size) 3089e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura slot -= cache_size; 3099e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 3109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 31144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura /* If we collided after 16 steps, or if the hash is more than half 31244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura full, force the hash to expand. Fill the selected slot, whether 31344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura it's free or collides. Note that hash expansion drops previous 31444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura contents; further lookups will refill the hash. */ 31544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug (4, "updating slot %lu after %ld steps, replacing 0x%lx\n", slot, i, addr); 316ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(addr || cache->used >= cache_size / 2)) 31744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 318ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(trace_cache_expand (cache) < 0)) 3190a26727ea2b3b9afd8d019a91777f350d06dd8dcArun Sharma return NULL; 32044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 321d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura cache_size = 1u << cache->log_size; 32244a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura slot = ((rip * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); 323d2525ec9369525c4d089eeffc84b417fd9c9aea7Lassi Tuura frame = &cache->frames[slot]; 32444a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura addr = frame->virtual_address; 32544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 32644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 32744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura if (! addr) 32844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura ++cache->used; 32944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 33044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return trace_init_addr (frame, cursor, cfa, rip, rbp, rsp); 3319e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura} 3329e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3339e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura/* Fast stack backtrace for x86-64. 3349e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3355f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura This is used by backtrace() implementation to accelerate frequent 3365f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura queries for current stack, without any desire to unwind. It fills 3375f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura BUFFER with the call tree from CURSOR upwards for at most SIZE 3385f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura stack levels. The first frame, backtrace itself, is omitted. When 3395f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura called, SIZE should give the maximum number of entries that can be 3405f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura stored into BUFFER. Uses an internal thread-specific cache to 3415f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura accelerate queries. 3429e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3439e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura The caller should fall back to a unw_step() loop if this function 3449e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a 3459e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura stack frame that is too complex to be traced in the fast path. 3469e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3479e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura This function is tuned for clients which only need to walk the 3489e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura stack to get the call tree as fast as possible but without any 3499e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura other details, for example profilers sampling the stack thousands 3509e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura to millions of times per second. The routine handles the most 3519e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura common x86-64 ABI stack layouts: CFA is RBP or RSP plus/minus 3529e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura constant offset, return address is at CFA-8, and RBP and RSP are 3539e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura either unchanged or saved on stack at constant offset from the CFA; 3549e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura the signal return frame; and frames without unwind info provided 3559e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura they are at the outermost (final) frame or can conservatively be 3569e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura assumed to be frame-pointer based. 3579e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3585f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura Any other stack layout will cause the routine to give up. There 3599e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura are only a handful of relatively rarely used functions which do 3609e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura not have a stack in the standard form: vfork, longjmp, setcontext 3619e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura and _dl_runtime_profile on common linux systems for example. 3629e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3639e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura On success BUFFER and *SIZE reflect the trace progress up to *SIZE 3649e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura stack levels or the outermost frame, which ever is less. It may 3659e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura stop short of outermost frame if unw_step() loop would also do so, 3669e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura e.g. if there is no more unwind information; this is not reported 3679e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura as an error. 3689e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3699e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura The function returns a negative value for errors, -UNW_ESTOPUNWIND 3709e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura if tracing stopped because of an unusual frame unwind info. The 3719e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura BUFFER and *SIZE reflect tracing progress up to the error frame. 3729e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3739e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Callers of this function would normally look like this: 3749e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3759e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_cursor_t cur; 3765f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura unw_context_t ctx; 3779e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura void addrs[128]; 3789e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int depth = 128; 3799e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int ret; 3809e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 3819e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_getcontext(&ctx); 3829e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_init_local(&cur, &ctx); 38344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) 3849e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 3859e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura depth = 0; 3865f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura unw_getcontext(&ctx); 3875f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura unw_init_local(&cur, &ctx); 3885f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura while ((ret = unw_step(&cur)) > 0 && depth < 128) 3899e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 3909e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t ip; 3919e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_get_reg(&cur, UNW_REG_IP, &ip); 3929e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura addresses[depth++] = (void *) ip; 3939e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 3949e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 3959e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura*/ 3965f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi TuuraHIDDEN int 3975f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuuratdep_trace (unw_cursor_t *cursor, void **buffer, int *size) 3989e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura{ 3999e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura struct cursor *c = (struct cursor *) cursor; 4009e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura struct dwarf_cursor *d = &c->dwarf; 40144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura unw_trace_cache_t *cache; 4029e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_word_t rbp, rsp, rip, cfa; 4039e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int maxdepth = 0; 4049e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int depth = 0; 4059e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura int ret; 4069e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4079e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Check input parametres. */ 408ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) 4099e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura return -UNW_EINVAL; 4109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4119e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (1, "begin ip 0x%lx cfa 0x%lx\n", d->ip, d->cfa); 4129e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4139e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Tell core dwarf routines to call back to us. */ 4149e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->stash_frames = 1; 4159e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4165c2cade264010c9855c4ea5effc5b4789739e7caLassi Tuura /* Determine initial register values. These are direct access safe 4175c2cade264010c9855c4ea5effc5b4789739e7caLassi Tuura because we know they come from the initial machine context. */ 4189e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura rip = d->ip; 4199e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura rsp = cfa = d->cfa; 4205c2cade264010c9855c4ea5effc5b4789739e7caLassi Tuura ACCESS_MEM_FAST(ret, 0, d, DWARF_GET_LOC(d->loc[UNW_X86_64_RBP]), rbp); 4215c2cade264010c9855c4ea5effc5b4789739e7caLassi Tuura assert(ret == 0); 4229e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 42344a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura /* Get frame cache. */ 424ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(! (cache = trace_cache_get()))) 42544a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura { 42644a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug (1, "returning %d, cannot get trace cache\n", -UNW_ENOMEM); 42744a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura *size = 0; 42844a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura d->stash_frames = 0; 42944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura return -UNW_ENOMEM; 43044a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura } 43144a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura 4329e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Trace the stack upwards, starting from current RIP. Adjust 4339e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura the RIP address for previous/next instruction as the main 4349e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unwinding logic would also do. We undo this before calling 4359e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura back into unw_step(). */ 4369e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura while (depth < maxdepth) 4379e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 4389e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura rip -= d->use_prev_instr; 4399e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (2, "depth %d cfa 0x%lx rip 0x%lx rsp 0x%lx rbp 0x%lx\n", 4409e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura depth, cfa, rip, rsp, rbp); 4419e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4429e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* See if we have this address cached. If not, evaluate enough of 4439e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura the dwarf unwind information to fill the cache line data, or to 4449e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura decide this frame cannot be handled in fast trace mode. We 4459e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura cache negative results too to prevent unnecessary dwarf parsing 4469e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura for common failures. */ 4479e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, rip, rbp, rsp); 4489e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4499e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* If we don't have information for this frame, give up. */ 450ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(! f)) 4519e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 4529e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura ret = -UNW_ENOINFO; 4539e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 4549e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 4559e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4569e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (3, "frame va %lx type %d last %d cfa %s+%d rbp @ cfa%+d rsp @ cfa%+d\n", 4579e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->virtual_address, f->frame_type, f->last_frame, 4589e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->cfa_reg_rsp ? "rsp" : "rbp", f->cfa_reg_offset, 4599e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura f->rbp_cfa_offset, f->rsp_cfa_offset); 4609e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4619e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura assert (f->virtual_address == rip); 4629e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4639e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Stop if this was the last frame. In particular don't evaluate 4649e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura new register values as it may not be safe - we don't normally 4659e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura run with full validation on, and do not want to - and there's 4669e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura enough bad unwind info floating around that we need to trust 4679e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura what unw_step() previously said, in potentially bogus frames. */ 4689e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura if (f->last_frame) 4699e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 4709e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4719e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Evaluate CFA and registers for the next frame. */ 4729e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura switch (f->frame_type) 4739e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura { 4749e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura case UNW_X86_64_FRAME_GUESSED: 4759e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Fall thru to standard processing after forcing validation. */ 4769e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura c->validate = 1; 4779e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4789e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura case UNW_X86_64_FRAME_STANDARD: 4799e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Advance standard traceable frame. */ 4809e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset; 481ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip); 482ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(ret >= 0) && likely(f->rbp_cfa_offset != -1)) 483ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->rbp_cfa_offset, rbp); 4849e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4859e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */ 4869e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura rsp = cfa; 4879e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4889e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Next frame needs to back up for unwind info lookup. */ 4899e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->use_prev_instr = 1; 4909e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 4919e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 4929e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura case UNW_X86_64_FRAME_SIGRETURN: 4931010880548589685a27b8f63ef54a3ea78e052fcArun Sharma cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ 4941010880548589685a27b8f63ef54a3ea78e052fcArun Sharma 4951010880548589685a27b8f63ef54a3ea78e052fcArun Sharma ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RIP, rip); 496ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(ret >= 0)) 4971010880548589685a27b8f63ef54a3ea78e052fcArun Sharma ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RBP, rbp); 498ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (likely(ret >= 0)) 4991010880548589685a27b8f63ef54a3ea78e052fcArun Sharma ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RSP, rsp); 5009e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 5019e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Resume stack at signal restoration point. The stack is not 5029e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura necessarily continuous here, especially with sigaltstack(). */ 5039e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura cfa = rsp; 5049e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 5059e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* Next frame should not back up. */ 5069e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura d->use_prev_instr = 0; 5079e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 5089e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 5099e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura default: 5109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura /* We cannot trace through this frame, give up and tell the 5119e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura caller we had to stop. Data collected so far may still be 5129e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura useful to the caller, so let it know how far we got. */ 5139e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura ret = -UNW_ESTOPUNWIND; 5149e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 5159e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 5169e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 5179e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura Debug (4, "new cfa 0x%lx rip 0x%lx rsp 0x%lx rbp 0x%lx\n", 5189e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura cfa, rip, rsp, rbp); 5199e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 520ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura /* If we failed or ended up somewhere bogus, stop. */ 521ae5c1f2adf4da04235d87d024d4d942c01b2b447Lassi Tuura if (unlikely(ret < 0 || rip < 0x4000)) 5229e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura break; 5235f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura 5245f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura /* Record this address in stack trace. We skipped the first address. */ 5255f38f35d5d6c78aafa6da20845d9ceff74af00f8Lassi Tuura buffer[depth++] = (void *) (rip - d->use_prev_instr); 5269e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura } 5279e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura 5289e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura#if UNW_DEBUG 52944a14d1364abff3dc7ec49f35b7220542c4cf2b1Lassi Tuura Debug (1, "returning %d, depth %d\n", ret, depth); 5309e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura#endif 5319e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura *size = depth; 5329e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura return ret; 5339e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura} 534