From a51cf490318eb1f2390bcd36b77794c92107ad52 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Mon, 5 Dec 2016 15:39:37 -0800 Subject: [PATCH] dwarf: Configurable cache size Add interface for configurable dwarf cache size * Use item size and round up to nearest power of 2. * Initial cache still exists in BSS. Without this, it means we would fail backtrace when out of memory. The test-mem test fails without this --- doc/Makefile.am | 2 + doc/libunwind.man | 14 ++++-- doc/libunwind.tex | 6 ++- doc/unw_flush_cache.man | 5 +- doc/unw_flush_cache.tex | 1 + doc/unw_set_cache_size.man | 88 ++++++++++++++++++++++++++++++++++ doc/unw_set_cache_size.tex | 59 +++++++++++++++++++++++ doc/unw_set_caching_policy.man | 5 +- doc/unw_set_caching_policy.tex | 1 + include/dwarf.h | 21 +++++--- include/libunwind-common.h.in | 2 + src/Makefile.am | 6 ++- src/dwarf/Gparser.c | 62 +++++++++++++++++------- src/mi/Gset_cache_size.c | 64 +++++++++++++++++++++++++ src/mi/Lset_cache_size.c | 5 ++ tests/check-namespace.sh.in | 2 + tests/test-flush-cache.c | 1 + tests/test-static-link-gen.c | 1 + tests/test-static-link-loc.c | 1 + 19 files changed, 314 insertions(+), 32 deletions(-) create mode 100644 doc/unw_set_cache_size.man create mode 100644 doc/unw_set_cache_size.tex create mode 100644 src/mi/Gset_cache_size.c create mode 100644 src/mi/Lset_cache_size.c diff --git a/doc/Makefile.am b/doc/Makefile.am index 25340667..577310c9 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,6 +17,7 @@ man3_MANS = libunwind.man libunwind-dynamic.man libunwind-ia64.man \ unw_destroy_addr_space.man \ unw_regname.man unw_resume.man \ unw_set_caching_policy.man \ + unw_set_cache_size.man \ unw_set_fpreg.man \ unw_set_reg.man \ unw_step.man \ @@ -41,6 +42,7 @@ EXTRA_DIST = NOTES libunwind.trans \ unw_is_signal_frame.tex \ unw_create_addr_space.tex unw_destroy_addr_space.tex \ unw_regname.tex unw_resume.tex unw_set_caching_policy.tex \ + unw_set_cache_size.tex \ unw_set_fpreg.tex \ unw_set_reg.tex \ unw_step.tex \ diff --git a/doc/libunwind.man b/doc/libunwind.man index c6046e28..02ab6b89 100644 --- a/doc/libunwind.man +++ b/doc/libunwind.man @@ -1,5 +1,5 @@ '\" t -.\" Manual page created with latex2man on Thu Aug 16 09:44:43 MDT 2007 +.\" Manual page created with latex2man on Thu Jan 12 06:50:29 PST 2017 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW @@ -10,7 +10,7 @@ .fi .. -.TH "LIBUNWIND" "3" "16 August 2007" "Programming Library " "Programming Library " +.TH "LIBUNWIND" "3" "12 January 2017" "Programming Library " "Programming Library " .SH NAME libunwind \-\- a (mostly) platform\-independent unwind API @@ -82,6 +82,11 @@ int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t); .br +int +unw_set_cache_size(unw_addr_space_t, +size_t, +int); +.br .PP const char *unw_regname(unw_regnum_t); .br @@ -428,7 +433,9 @@ UNW_CACHE_NONE, it is possible to turn off caching completely, therefore eliminating the risk of stale data alltogether (at the cost of slower execution). By default, caching is enabled for -local unwinding only. +local unwinding only. The cache size can be dynamically changed with +unw_set_cache_size(), +which also fluches the current cache. .PP .SH FILES @@ -482,6 +489,7 @@ unw_is_signal_frame(3), unw_regname(3), unw_resume(3), unw_set_caching_policy(3), +unw_set_cache_size(3), unw_set_fpreg(3), unw_set_reg(3), unw_step(3), diff --git a/doc/libunwind.tex b/doc/libunwind.tex index 534bd4db..6cbb4766 100644 --- a/doc/libunwind.tex +++ b/doc/libunwind.tex @@ -43,6 +43,8 @@ \Type{void} \Func{unw\_flush\_cache}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_word\_t});\\ \noindent \Type{int} \Func{unw\_set\_caching\_policy}(\Type{unw\_addr\_space\_t}, \Type{unw\_caching\_policy\_t});\\ +\noindent +\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t}, \Type{size\_t}, \Type{int});\\ \noindent \Type{const char *}\Func{unw\_regname}(\Type{unw\_regnum\_t});\\ @@ -293,7 +295,8 @@ object. In particular, by selecting the policy \Const{UNW\_CACHE\_NONE}, it is possible to turn off caching completely, therefore eliminating the risk of stale data alltogether (at the cost of slower execution). By default, caching is enabled for -local unwinding only. +local unwinding only. The cache size can be dynamically changed with +\Func{unw\_set\_cache\_size}(), which also fluches the current cache. \section{Files} @@ -337,6 +340,7 @@ local unwinding only. \SeeAlso{unw\_regname(3)}, \SeeAlso{unw\_resume(3)}, \SeeAlso{unw\_set\_caching\_policy(3)}, +\SeeAlso{unw\_set\_cache\_size(3)}, \SeeAlso{unw\_set\_fpreg(3)}, \SeeAlso{unw\_set\_reg(3)}, \SeeAlso{unw\_step(3)}, diff --git a/doc/unw_flush_cache.man b/doc/unw_flush_cache.man index 2c05bc23..627449ef 100644 --- a/doc/unw_flush_cache.man +++ b/doc/unw_flush_cache.man @@ -1,5 +1,5 @@ '\" t -.\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 +.\" Manual page created with latex2man on Fri Dec 2 16:09:33 PST 2016 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW @@ -10,7 +10,7 @@ .fi .. -.TH "UNW\\_FLUSH\\_CACHE" "3" "16 August 2007" "Programming Library " "Programming Library " +.TH "UNW\\_FLUSH\\_CACHE" "3" "02 December 2016" "Programming Library " "Programming Library " .SH NAME unw_flush_cache \-\- flush cached info @@ -80,6 +80,7 @@ use from a signal handler. .PP libunwind(3), unw_set_caching_policy(3) +unw_set_cache_size(3) .PP .SH AUTHOR diff --git a/doc/unw_flush_cache.tex b/doc/unw_flush_cache.tex index 9b61dfc3..32319db5 100644 --- a/doc/unw_flush_cache.tex +++ b/doc/unw_flush_cache.tex @@ -45,6 +45,7 @@ use from a signal handler. \SeeAlso{libunwind(3)}, \SeeAlso{unw\_set\_caching\_policy(3)} +\SeeAlso{unw\_set\_cache\_size(3)} \section{Author} diff --git a/doc/unw_set_cache_size.man b/doc/unw_set_cache_size.man new file mode 100644 index 00000000..34bbc539 --- /dev/null +++ b/doc/unw_set_cache_size.man @@ -0,0 +1,88 @@ +'\" t +.\" Manual page created with latex2man on Fri Jan 13 08:33:21 PST 2017 +.\" NOTE: This file is generated, DO NOT EDIT. +.de Vb +.ft CW +.nf +.. +.de Ve +.ft R + +.fi +.. +.TH "UNW\\_SET\\_CACHE\\_SIZE" "3" "13 January 2017" "Programming Library " "Programming Library " +.SH NAME +unw_set_cache_size +\-\- set unwind cache size +.PP +.SH SYNOPSIS + +.PP +#include +.br +.PP +int +unw_set_cache_size(unw_addr_space_t +as, +size_t +size, +int +flag); +.br +.PP +.SH DESCRIPTION + +.PP +The unw_set_cache_size() +routine sets the cache size of +address space as +to hold at least as many items as given by +argument size\&. +It may hold more items as determined by the +implementation. To disable caching, call +unw_set_caching_policy) +with a policy of +UNW_CACHE_NONE\&. +Flag is currently unused and must be 0. +.PP +.SH RETURN VALUE + +.PP +On successful completion, unw_set_cache_size() +returns 0. +Otherwise the negative value of one of the error\-codes below is +returned. +.PP +.SH THREAD AND SIGNAL SAFETY + +.PP +unw_set_cache_size() +is thread\-safe but \fInot\fP +safe +to use from a signal handler. +.PP +.SH ERRORS + +.PP +.TP +UNW_ENOMEM + The desired cache size could not be +established because the application is out of memory. +.PP +.SH SEE ALSO + +.PP +libunwind(3), +unw_create_addr_space(3), +unw_set_caching_policy(3), +unw_flush_cache(3) +.PP +.SH AUTHOR + +.PP +Dave Watson +.br +Email: \fBdade.watson@gmail.com\fP +.br +WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. +.\" NOTE: This file is generated, DO NOT EDIT. diff --git a/doc/unw_set_cache_size.tex b/doc/unw_set_cache_size.tex new file mode 100644 index 00000000..1bd7e00d --- /dev/null +++ b/doc/unw_set_cache_size.tex @@ -0,0 +1,59 @@ +\documentclass{article} +\usepackage[fancyhdr,pdf]{latex2man} + +\input{common.tex} + +\begin{document} + +\begin{Name}{3}{unw\_set\_cache\_size}{Dave Watson}{Programming Library}{unw\_set\_cache\_size}unw\_set\_cache\_size -- set unwind cache size +\end{Name} + +\section{Synopsis} + +\File{\#include $<$libunwind.h$>$}\\ + +\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t} \Var{as}, \Type{size\_t} \Var{size}, \Type{int} \Var{flag});\\ + +\section{Description} + +The \Func{unw\_set\_cache\_size}() routine sets the cache size of +address space \Var{as} to hold at least as many items as given by +argument \Var{size}. It may hold more items as determined by the +implementation. To disable caching, call +\Func{unw\_set\_caching\_policy}) with a policy of +\Const{UNW\_CACHE\_NONE}. Flag is currently unused and must be 0. + +\section{Return Value} + +On successful completion, \Func{unw\_set\_cache\_size}() returns 0. +Otherwise the negative value of one of the error-codes below is +returned. + +\section{Thread and Signal Safety} + +\Func{unw\_set\_cache\_size}() is thread-safe but \emph{not} safe +to use from a signal handler. + +\section{Errors} + +\begin{Description} +\item[\Const{UNW\_ENOMEM}] The desired cache size could not be + established because the application is out of memory. +\end{Description} + +\section{See Also} + +\SeeAlso{libunwind(3)}, +\SeeAlso{unw\_create\_addr\_space(3)}, +\SeeAlso{unw\_set\_caching\_policy(3)}, +\SeeAlso{unw\_flush\_cache(3)} + +\section{Author} + +\noindent +Dave Watson\\ +Email: \Email{dade.watson@gmail.com}\\ +WWW: \URL{http://www.nongnu.org/libunwind/}. +\LatexManEnd + +\end{document} diff --git a/doc/unw_set_caching_policy.man b/doc/unw_set_caching_policy.man index a21d84a6..4862ea54 100644 --- a/doc/unw_set_caching_policy.man +++ b/doc/unw_set_caching_policy.man @@ -1,5 +1,5 @@ '\" t -.\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 +.\" Manual page created with latex2man on Fri Dec 2 16:09:33 PST 2016 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW @@ -10,7 +10,7 @@ .fi .. -.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "16 August 2007" "Programming Library " "Programming Library " +.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "02 December 2016" "Programming Library " "Programming Library " .SH NAME unw_set_caching_policy \-\- set unwind caching policy @@ -105,6 +105,7 @@ established because the application is out of memory. .PP libunwind(3), unw_create_addr_space(3), +unw_set_cache_size(3), unw_flush_cache(3) .PP .SH AUTHOR diff --git a/doc/unw_set_caching_policy.tex b/doc/unw_set_caching_policy.tex index a84e0201..3a4b07e8 100644 --- a/doc/unw_set_caching_policy.tex +++ b/doc/unw_set_caching_policy.tex @@ -67,6 +67,7 @@ to use from a signal handler. \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, +\SeeAlso{unw\_set\_cache\_size(3)}, \SeeAlso{unw\_flush\_cache(3)} \section{Author} diff --git a/include/dwarf.h b/include/dwarf.h index f493de85..e29b8400 100644 --- a/include/dwarf.h +++ b/include/dwarf.h @@ -325,11 +325,11 @@ typedef struct dwarf_cursor } dwarf_cursor_t; -#define DWARF_LOG_UNW_CACHE_SIZE 7 -#define DWARF_UNW_CACHE_SIZE (1 << DWARF_LOG_UNW_CACHE_SIZE) +#define DWARF_DEFAULT_LOG_UNW_CACHE_SIZE 7 +#define DWARF_DEFAULT_UNW_CACHE_SIZE (1 << DWARF_DEFAULT_LOG_UNW_CACHE_SIZE) -#define DWARF_LOG_UNW_HASH_SIZE (DWARF_LOG_UNW_CACHE_SIZE + 1) -#define DWARF_UNW_HASH_SIZE (1 << DWARF_LOG_UNW_HASH_SIZE) +#define DWARF_DEFAULT_LOG_UNW_HASH_SIZE (DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + 1) +#define DWARF_DEFAULT_UNW_HASH_SIZE (1 << DWARF_DEFAULT_LOG_UNW_HASH_SIZE) typedef unsigned char unw_hash_index_t; @@ -339,13 +339,20 @@ struct dwarf_rs_cache unsigned short lru_head; /* index of lead-recently used rs */ unsigned short lru_tail; /* index of most-recently used rs */ + unsigned short log_size; + unsigned short prev_log_size; + /* hash table that maps instruction pointer to rs index: */ - unsigned short hash[DWARF_UNW_HASH_SIZE]; + unsigned short *hash; uint32_t generation; /* generation number */ /* rs cache: */ - dwarf_reg_state_t buckets[DWARF_UNW_CACHE_SIZE]; + dwarf_reg_state_t *buckets; + + /* default memory, loaded in BSS segment */ + unsigned short default_hash[DWARF_DEFAULT_UNW_HASH_SIZE]; + dwarf_reg_state_t default_buckets[DWARF_DEFAULT_UNW_CACHE_SIZE]; }; /* A list of descriptors for loaded .debug_frame sections. */ @@ -395,6 +402,7 @@ struct dwarf_callback_data #define dwarf_make_proc_info UNW_OBJ (dwarf_make_proc_info) #define dwarf_read_encoded_pointer UNW_OBJ (dwarf_read_encoded_pointer) #define dwarf_step UNW_OBJ (dwarf_step) +#define dwarf_flush_rs_cache UNW_OBJ (dwarf_flush_rs_cache) extern int dwarf_init (void); #ifndef UNW_REMOTE_ONLY @@ -443,5 +451,6 @@ extern int dwarf_read_encoded_pointer (unw_addr_space_t as, const unw_proc_info_t *pi, unw_word_t *valp, void *arg); extern int dwarf_step (struct dwarf_cursor *c); +extern int dwarf_flush_rs_cache (struct dwarf_rs_cache *cache); #endif /* dwarf_h */ diff --git a/include/libunwind-common.h.in b/include/libunwind-common.h.in index fa753ba1..7afd5726 100644 --- a/include/libunwind-common.h.in +++ b/include/libunwind-common.h.in @@ -225,6 +225,7 @@ unw_save_loc_t; #define unw_handle_signal_frame UNW_OBJ(handle_signal_frame) #define unw_get_proc_name UNW_OBJ(get_proc_name) #define unw_set_caching_policy UNW_OBJ(set_caching_policy) +#define unw_set_cache_size UNW_OBJ(set_cache_size) #define unw_regname UNW_ARCH_OBJ(regname) #define unw_flush_cache UNW_ARCH_OBJ(flush_cache) #define unw_strerror UNW_ARCH_OBJ(strerror) @@ -234,6 +235,7 @@ extern void unw_destroy_addr_space (unw_addr_space_t); extern unw_accessors_t *unw_get_accessors (unw_addr_space_t); extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t); extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t); +extern int unw_set_cache_size (unw_addr_space_t, size_t, int); extern const char *unw_regname (unw_regnum_t); extern int unw_init_local (unw_cursor_t *, unw_context_t *); diff --git a/src/Makefile.am b/src/Makefile.am index 5d874755..8dd6d286 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -109,7 +109,8 @@ libunwind_la_SOURCES_generic = \ mi/Gput_dynamic_unwind_info.c mi/Gdestroy_addr_space.c \ mi/Gget_reg.c mi/Gset_reg.c \ mi/Gget_fpreg.c mi/Gset_fpreg.c \ - mi/Gset_caching_policy.c + mi/Gset_caching_policy.c \ + mi/Gset_cache_size.c if SUPPORT_CXX_EXCEPTIONS libunwind_la_SOURCES_local_unwind = \ @@ -137,7 +138,8 @@ libunwind_la_SOURCES_local_nounwind = \ mi/Lput_dynamic_unwind_info.c mi/Ldestroy_addr_space.c \ mi/Lget_reg.c mi/Lset_reg.c \ mi/Lget_fpreg.c mi/Lset_fpreg.c \ - mi/Lset_caching_policy.c + mi/Lset_caching_policy.c \ + mi/Lset_cache_size.c libunwind_la_SOURCES_local = \ $(libunwind_la_SOURCES_local_nounwind) \ diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index 5336a2a6..1831a58c 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -23,13 +23,17 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "dwarf_i.h" #include "libunwind_i.h" +#include +#include #define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool)) #define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs)) +#define DWARF_UNW_CACHE_SIZE(log_size) (1 << log_size) +#define DWARF_UNW_HASH_SIZE(log_size) (1 << (log_size + 1)) + static inline int read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, unw_word_t *valp, void *arg) @@ -508,15 +512,37 @@ parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr) return 0; } -static inline void -flush_rs_cache (struct dwarf_rs_cache *cache) +HIDDEN int +dwarf_flush_rs_cache (struct dwarf_rs_cache *cache) { int i; - cache->lru_head = DWARF_UNW_CACHE_SIZE - 1; + if (cache->log_size == DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + || !cache->hash) { + cache->hash = cache->default_hash; + cache->buckets = cache->default_buckets; + cache->log_size = DWARF_DEFAULT_LOG_UNW_CACHE_SIZE; + } else { + if (cache->hash && cache->hash != cache->default_hash) + munmap(cache->hash, DWARF_UNW_HASH_SIZE(cache->prev_log_size)); + if (cache->buckets && cache->buckets != cache->default_buckets) + munmap(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->prev_log_size)); + GET_MEMORY(cache->hash, DWARF_UNW_HASH_SIZE(cache->log_size) + * sizeof (cache->hash[0])); + GET_MEMORY(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->log_size) + * sizeof (cache->buckets[0])); + if (!cache->hash || !cache->buckets) + { + Debug (1, "Unable to allocate cache memory"); + return -UNW_ENOMEM; + } + cache->prev_log_size = cache->log_size; + } + + cache->lru_head = DWARF_UNW_CACHE_SIZE(cache->log_size) - 1; cache->lru_tail = 0; - for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i) + for (i = 0; i < DWARF_UNW_CACHE_SIZE(cache->log_size); ++i) { if (i > 0) cache->buckets[i].lru_chain = (i - 1); @@ -524,8 +550,10 @@ flush_rs_cache (struct dwarf_rs_cache *cache) cache->buckets[i].ip = 0; cache->buckets[i].valid = 0; } - for (i = 0; ilog_size); ++i) cache->hash[i] = -1; + + return 0; } static inline struct dwarf_rs_cache * @@ -543,9 +571,11 @@ get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp) lock_acquire (&cache->lock, *saved_maskp); } - if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation)) + if ((atomic_read (&as->cache_generation) != atomic_read (&cache->generation)) + || !cache->hash) { - flush_rs_cache (cache); + if (dwarf_flush_rs_cache (cache) < 0) + return NULL; cache->generation = as->cache_generation; } @@ -564,12 +594,12 @@ put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache, } static inline unw_hash_index_t CONST_ATTR -hash (unw_word_t ip) +hash (unw_word_t ip, unsigned short log_size) { /* based on (sqrt(5)/2-1)*2^64 */ # define magic ((unw_word_t) 0x9e3779b97f4a7c16ULL) - return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE); + return ip * magic >> ((sizeof(unw_word_t) * 8) - (log_size + 1)); } static inline long @@ -592,8 +622,8 @@ rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c) if (cache_match (rs, ip)) return rs; - index = cache->hash[hash (ip)]; - if (index >= DWARF_UNW_CACHE_SIZE) + index = cache->hash[hash (ip, cache->log_size)]; + if (index >= DWARF_UNW_CACHE_SIZE(cache->log_size)) return NULL; rs = cache->buckets + index; @@ -606,7 +636,7 @@ rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c) (rs - cache->buckets); return rs; } - if (rs->coll_chain >= DWARF_UNW_HASH_SIZE) + if (rs->coll_chain >= DWARF_UNW_HASH_SIZE(cache->log_size)) return NULL; rs = cache->buckets + rs->coll_chain; } @@ -630,7 +660,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) /* remove the old rs from the hash table (if it's there): */ if (rs->ip) { - index = hash (rs->ip); + index = hash (rs->ip, cache->log_size); tmp = cache->buckets + cache->hash[index]; prev = NULL; while (1) @@ -645,7 +675,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) } else prev = tmp; - if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE) + if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE(cache->log_size)) /* old rs wasn't in the hash-table */ break; tmp = cache->buckets + tmp->coll_chain; @@ -653,7 +683,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) } /* enter new rs in the hash table */ - index = hash (c->ip); + index = hash (c->ip, cache->log_size); rs->coll_chain = cache->hash[index]; cache->hash[index] = rs - cache->buckets; diff --git a/src/mi/Gset_cache_size.c b/src/mi/Gset_cache_size.c new file mode 100644 index 00000000..2f06deb3 --- /dev/null +++ b/src/mi/Gset_cache_size.c @@ -0,0 +1,64 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2014 + Contributed by Milian Wolff + and Dave Watson + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_set_cache_size (unw_addr_space_t as, size_t size, int flag) +{ + size_t power = 1; + unsigned short log_size = 0; + + if (!tdep_init_done) + tdep_init (); + + if (flag != 0) + return -1; + + /* Round up to next power of two, slowly but portably */ + while(power < size) + { + power *= 2; + log_size++; + /* Largest size currently supported by rs_cache */ + if (log_size >= 15) + break; + } + + if (log_size == as->global_cache.log_size) + return 0; /* no change */ + + as->global_cache.log_size = log_size; + + /* Ensure caches are empty (and initialized). */ + unw_flush_cache (as, 0, 0); +#ifdef __ia64__ + return 0; +#else + /* Synchronously purge cache, to ensure memory is allocated */ + return dwarf_flush_rs_cache(&as->global_cache); +#endif +} diff --git a/src/mi/Lset_cache_size.c b/src/mi/Lset_cache_size.c new file mode 100644 index 00000000..670f64d3 --- /dev/null +++ b/src/mi/Lset_cache_size.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gset_cache_size.c" +#endif diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in index 1ef74abb..1ae81212 100644 --- a/tests/check-namespace.sh.in +++ b/tests/check-namespace.sh.in @@ -103,6 +103,7 @@ check_local_unw_abi () { match _UL${plat}_local_addr_space match _UL${plat}_resume match _UL${plat}_set_caching_policy + match _UL${plat}_set_cache_size match _UL${plat}_set_reg match _UL${plat}_set_fpreg match _UL${plat}_step @@ -199,6 +200,7 @@ check_generic_unw_abi () { match _U${plat}_regname match _U${plat}_resume match _U${plat}_set_caching_policy + match _U${plat}_set_cache_size match _U${plat}_set_fpreg match _U${plat}_set_reg match _U${plat}_step diff --git a/tests/test-flush-cache.c b/tests/test-flush-cache.c index 592162c1..1611cf48 100644 --- a/tests/test-flush-cache.c +++ b/tests/test-flush-cache.c @@ -46,6 +46,7 @@ f257 (void) for (i = 0; i < n; ++i) printf ("[%d] ip=%p\n", i, buffer[i]); + unw_set_cache_size (unw_local_addr_space, 1023, 0); unw_flush_cache (unw_local_addr_space, 0, 0); if (verbose) diff --git a/tests/test-static-link-gen.c b/tests/test-static-link-gen.c index 32464169..d61e7a51 100644 --- a/tests/test-static-link-gen.c +++ b/tests/test-static-link-gen.c @@ -43,6 +43,7 @@ static void *funcs[] = (void *) &unw_get_accessors, (void *) &unw_flush_cache, (void *) &unw_set_caching_policy, + (void *) &unw_set_cache_size, (void *) &unw_regname, (void *) &unw_get_proc_info, (void *) &unw_get_save_loc, diff --git a/tests/test-static-link-loc.c b/tests/test-static-link-loc.c index 4e47e45f..1c7aa037 100644 --- a/tests/test-static-link-loc.c +++ b/tests/test-static-link-loc.c @@ -61,6 +61,7 @@ static void *funcs[] = (void *) &unw_get_accessors, (void *) &unw_flush_cache, (void *) &unw_set_caching_policy, + (void *) &unw_set_cache_size, (void *) &unw_regname, (void *) &unw_get_proc_info, (void *) &unw_get_save_loc,