diff options
author | Adeel <3840695+am11@users.noreply.github.com> | 2022-06-29 19:13:56 +0300 |
---|---|---|
committer | Stephen M. Webb <stephen.webb@bregmasoft.ca> | 2022-07-08 15:59:28 -0400 |
commit | 4640cd26d5e045b738bacc20ed92a7cf8e801c0f (patch) | |
tree | 9340c3756e6e732a9bbb7f3824b8eb40e65fe044 | |
parent | cfcf3d193a4425f58ed9556ec54b6d7ab0557330 (diff) | |
download | libunwind-4640cd26d5e045b738bacc20ed92a7cf8e801c0f.tar.gz |
Expose get_proc_info_in_range API
-rw-r--r-- | doc/Makefile.am | 2 | ||||
-rw-r--r-- | doc/unw_get_proc_info_in_range.man | 109 | ||||
-rw-r--r-- | doc/unw_get_proc_info_in_range.tex | 70 | ||||
-rw-r--r-- | include/libunwind-common.h.in | 61 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/mi/Gget_proc_info_in_range.c | 111 | ||||
-rw-r--r-- | src/mi/Lget_proc_info_in_range.c | 5 | ||||
-rw-r--r-- | tests/check-namespace.sh.in | 2 |
9 files changed, 337 insertions, 27 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am index f79d8c54..8a654b32 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -7,6 +7,7 @@ man3_MANS = libunwind.man libunwind-dynamic.man libunwind-ia64.man \ unw_get_accessors.man \ unw_get_proc_info.man \ unw_get_proc_info_by_ip.man \ + unw_get_proc_info_in_range.man \ unw_get_proc_name.man \ unw_get_proc_name_by_ip.man \ unw_get_fpreg.man \ @@ -38,6 +39,7 @@ EXTRA_DIST = NOTES libunwind.trans \ unw_get_accessors.tex \ unw_get_proc_info.tex \ unw_get_proc_info_by_ip.tex \ + unw_get_proc_info_in_range.tex \ unw_get_proc_name.tex \ unw_get_proc_name_by_ip.tex \ unw_get_fpreg.tex \ diff --git a/doc/unw_get_proc_info_in_range.man b/doc/unw_get_proc_info_in_range.man new file mode 100644 index 00000000..6b883660 --- /dev/null +++ b/doc/unw_get_proc_info_in_range.man @@ -0,0 +1,109 @@ +.\" *********************************** start of \input{common.tex} +.\" *********************************** end of \input{common.tex} +'\" t +.\" Manual page created with latex2man on Wed Jun 29 18:53:42 2022 +.\" NOTE: This file is generated, DO NOT EDIT. +.de Vb +.ft CW +.nf +.. +.de Ve +.ft R + +.fi +.. +.TH "UNW\\_GET\\_PROC\\_INFO\\_IN\\_RANGE" "3" "29 June 2022" "Programming Library " "Programming Library " +.SH NAME +unw_get_proc_info_in_range +\-\- get procedure info in IP range and a frame index table +.PP +.SH SYNOPSIS + +.PP +#include <libunwind.h> +.br +.PP +int +unw_get_proc_info_in_range(unw_word_t start_ip, +unw_word_t end_ip, +unw_word_t eh_frame_table, +unw_word_t eh_frame_table_len, +unw_word_t exidx_frame_table, +unw_word_t exidx_frame_table_len,, +unw_addr_space_t *as, +void *arg); +.br +.PP +.SH DESCRIPTION + +.PP +The unw_get_proc_info_in_range() +routine returns the same +kind of auxiliary information about a procedure as +unw_get_proc_info_by_ip(), +except that the info is looked up in +instruction\-pointer (IP) range and frame table instead of just at IP. This +is equally flexible because it is possible to look up the info for an arbitrary +procedure, even if it is not part of the current call\-chain. However, since it +is more flexible, it also tends to run slower (and often much slower) +than unw_get_proc_info(). +.PP +.SH RETURN VALUE + +.PP +On successful completion, unw_get_proc_info_in_range() +returns 0. Otherwise the negative value of one of the error\-codes +below is returned. +.PP +.SH THREAD AND SIGNAL SAFETY + +.PP +unw_get_proc_info_in_range() +is thread\-safe. If the local +address\-space is passed in argument as, +this routine is also +safe to use from a signal handler. +.PP +.SH ERRORS + +.PP +.TP +UNW_EUNSPEC + An unspecified error occurred. +.TP +UNW_ENOINFO + Libunwind +was unable to locate +unwind\-info for the procedure. +.TP +UNW_EBADVERSION + The unwind\-info for the procedure has +version or format that is not understood by libunwind\&. +.TP +UNW_EINVAL + An unsupported table encoding was specified. +.PP +In addition, unw_get_proc_info_by_ip() +may return any +error returned by the access_mem() +call\-back (see +unw_create_addr_space(3)). +.PP +.SH SEE ALSO + +.PP +libunwind(3), +unw_get_proc_info_in_range(3), +unw_create_addr_space(3), +unw_get_proc_name(3), +unw_get_proc_info(3) +.PP +.SH AUTHOR + +.PP +David Mosberger\-Tang +.br +Email: \fBdmosberger@gmail.com\fP +.br +WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. +.\" NOTE: This file is generated, DO NOT EDIT. diff --git a/doc/unw_get_proc_info_in_range.tex b/doc/unw_get_proc_info_in_range.tex new file mode 100644 index 00000000..8caaea85 --- /dev/null +++ b/doc/unw_get_proc_info_in_range.tex @@ -0,0 +1,70 @@ +\documentclass{article} +\usepackage[fancyhdr,pdf]{latex2man} + +\input{common.tex} + +\begin{document} + +\begin{Name}{3}{unw\_get\_proc\_info\_in\_range}{David Mosberger-Tang}{Programming Library}{unw\_get\_proc\_info\_in\_range}unw\_get\_proc\_info\_in\_range -- get procedure info in IP range and a frame index table +\end{Name} + +\section{Synopsis} + +\File{\#include $<$libunwind.h$>$}\\ + +\Type{int} \Func{unw\_get\_proc\_info\_in\_range}(\Type{unw\_word\_t~}\Var{start_ip}, \Type{unw\_word\_t~}\Var{end_ip}, \Type{unw\_word\_t~}\Var{eh_frame_table}, \Type{unw\_word\_t~}\Var{eh_frame_table_len}, \Type{unw\_word\_t~}\Var{exidx_frame_table}, \Type{unw\_word\_t~}\Var{exidx_frame_table_len,}, \Type{unw\_addr\_space\_t~*}\Var{as}, \Type{void~*}\Var{arg});\\ + +\section{Description} + +The \Func{unw\_get\_proc\_info\_in\_range}() routine returns the same +kind of auxiliary information about a procedure as +\Func{unw\_get\_proc\_info\_by\_ip}(), except that the info is looked up in +instruction-pointer (IP) range and frame table instead of just at IP. This +is equally flexible because it is possible to look up the info for an arbitrary +procedure, even if it is not part of the current call-chain. However, since it +is more flexible, it also tends to run slower (and often much slower) +than \Func{unw\_get\_proc\_info}(). + +\section{Return Value} + +On successful completion, \Func{unw\_get\_proc\_info\_in\_range}() +returns 0. Otherwise the negative value of one of the error-codes +below is returned. + +\section{Thread and Signal Safety} + +\Func{unw\_get\_proc\_info\_in\_range}() is thread-safe. If the local +address-space is passed in argument \Var{as}, this routine is also +safe to use from a signal handler. + +\section{Errors} + +\begin{Description} +\item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. +\item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate + unwind-info for the procedure. +\item[\Const{UNW\_EBADVERSION}] The unwind-info for the procedure has + version or format that is not understood by \Prog{libunwind}. +\item[\Const{UNW\_EINVAL}] An unsupported table encoding was specified. +\end{Description} +In addition, \Func{unw\_get\_proc\_info\_by\_ip}() may return any +error returned by the \Func{access\_mem}() call-back (see +\Func{unw\_create\_addr\_space}(3)). + +\section{See Also} + +\SeeAlso{libunwind(3)}, +\SeeAlso{unw\_get\_proc\_info\_in\_range(3)}, +\SeeAlso{unw\_create\_addr\_space(3)}, +\SeeAlso{unw\_get\_proc\_name(3)}, +\SeeAlso{unw\_get\_proc\_info(3)} + +\section{Author} + +\noindent +David Mosberger-Tang\\ +Email: \Email{dmosberger@gmail.com}\\ +WWW: \URL{http://www.nongnu.org/libunwind/}. +\LatexManEnd + +\end{document} diff --git a/include/libunwind-common.h.in b/include/libunwind-common.h.in index c9bea854..9d62aa91 100644 --- a/include/libunwind-common.h.in +++ b/include/libunwind-common.h.in @@ -251,33 +251,34 @@ unw_save_loc_t; /* These routines work both for local and remote unwinding. */ -#define unw_local_addr_space UNW_OBJ(local_addr_space) -#define unw_create_addr_space UNW_OBJ(create_addr_space) -#define unw_destroy_addr_space UNW_OBJ(destroy_addr_space) -#define unw_get_accessors UNW_ARCH_OBJ(get_accessors) -#define unw_get_accessors_int UNW_ARCH_OBJ(get_accessors_int) -#define unw_init_local UNW_OBJ(init_local) -#define unw_init_local2 UNW_OBJ(init_local2) -#define unw_init_remote UNW_OBJ(init_remote) -#define unw_step UNW_OBJ(step) -#define unw_resume UNW_OBJ(resume) -#define unw_get_proc_info UNW_OBJ(get_proc_info) -#define unw_get_proc_info_by_ip UNW_OBJ(get_proc_info_by_ip) -#define unw_reg_states_iterate UNW_OBJ(reg_states_iterate) -#define unw_apply_reg_state UNW_OBJ(apply_reg_state) -#define unw_get_reg UNW_OBJ(get_reg) -#define unw_set_reg UNW_OBJ(set_reg) -#define unw_get_fpreg UNW_OBJ(get_fpreg) -#define unw_set_fpreg UNW_OBJ(set_fpreg) -#define unw_get_save_loc UNW_OBJ(get_save_loc) -#define unw_is_signal_frame UNW_OBJ(is_signal_frame) -#define unw_get_proc_name UNW_OBJ(get_proc_name) -#define unw_get_proc_name_by_ip UNW_OBJ(get_proc_name_by_ip) -#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) +#define unw_local_addr_space UNW_OBJ(local_addr_space) +#define unw_create_addr_space UNW_OBJ(create_addr_space) +#define unw_destroy_addr_space UNW_OBJ(destroy_addr_space) +#define unw_get_accessors UNW_ARCH_OBJ(get_accessors) +#define unw_get_accessors_int UNW_ARCH_OBJ(get_accessors_int) +#define unw_init_local UNW_OBJ(init_local) +#define unw_init_local2 UNW_OBJ(init_local2) +#define unw_init_remote UNW_OBJ(init_remote) +#define unw_step UNW_OBJ(step) +#define unw_resume UNW_OBJ(resume) +#define unw_get_proc_info UNW_OBJ(get_proc_info) +#define unw_get_proc_info_by_ip UNW_OBJ(get_proc_info_by_ip) +#define unw_get_proc_info_in_range UNW_OBJ(get_proc_info_in_range) +#define unw_reg_states_iterate UNW_OBJ(reg_states_iterate) +#define unw_apply_reg_state UNW_OBJ(apply_reg_state) +#define unw_get_reg UNW_OBJ(get_reg) +#define unw_set_reg UNW_OBJ(set_reg) +#define unw_get_fpreg UNW_OBJ(get_fpreg) +#define unw_set_fpreg UNW_OBJ(set_fpreg) +#define unw_get_save_loc UNW_OBJ(get_save_loc) +#define unw_is_signal_frame UNW_OBJ(is_signal_frame) +#define unw_get_proc_name UNW_OBJ(get_proc_name) +#define unw_get_proc_name_by_ip UNW_OBJ(get_proc_name_by_ip) +#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) extern unw_addr_space_t unw_create_addr_space (unw_accessors_t *, int); extern void unw_destroy_addr_space (unw_addr_space_t); @@ -296,6 +297,12 @@ extern int unw_resume (unw_cursor_t *); extern int unw_get_proc_info (unw_cursor_t *, unw_proc_info_t *); extern int unw_get_proc_info_by_ip (unw_addr_space_t, unw_word_t, unw_proc_info_t *, void *); +extern int unw_get_proc_info_in_range (unw_word_t, unw_word_t, + unw_word_t, unw_word_t, + unw_word_t, unw_word_t, + unw_addr_space_t, unw_word_t, + unw_proc_info_t *, int, + void *); extern int unw_reg_states_iterate (unw_cursor_t *, unw_reg_states_callback, void *); extern int unw_apply_reg_state (unw_cursor_t *, void *); extern int unw_get_reg (unw_cursor_t *, int, unw_word_t *); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b7d1446..b63f5b31 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,7 @@ SET(libunwind_la_SOURCES_generic # the source is excluded here to prevent name clash #mi/Gget_accessors.c mi/Gget_proc_info_by_ip.c mi/Gget_proc_name.c + mi/Gget_proc_info_in_range.c 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 @@ -136,6 +137,7 @@ SET(libunwind_la_SOURCES_local_nounwind mi/Ldyn-extract.c mi/Lfind_dynamic_proc_info.c mi/Lget_accessors.c mi/Lget_proc_info_by_ip.c mi/Lget_proc_name.c + mi/Lget_proc_info_in_range.c 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 diff --git a/src/Makefile.am b/src/Makefile.am index a730fb39..cf788f27 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,6 +107,7 @@ libunwind_la_SOURCES_generic = \ mi/Gdyn-extract.c mi/Gdyn-remote.c mi/Gfind_dynamic_proc_info.c \ mi/Gget_accessors.c \ mi/Gget_proc_info_by_ip.c mi/Gget_proc_name.c \ + mi/Gget_proc_info_in_range.c \ 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 \ @@ -136,6 +137,7 @@ libunwind_la_SOURCES_local_nounwind = \ mi/Ldyn-extract.c mi/Lfind_dynamic_proc_info.c \ mi/Lget_accessors.c \ mi/Lget_proc_info_by_ip.c mi/Lget_proc_name.c \ + mi/Lget_proc_info_in_range.c \ 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 \ diff --git a/src/mi/Gget_proc_info_in_range.c b/src/mi/Gget_proc_info_in_range.c new file mode 100644 index 00000000..b9a369ba --- /dev/null +++ b/src/mi/Gget_proc_info_in_range.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2022 Hewlett-Packard Co. + Contributed by David Mosberger-Tang <davidm@hpl.hp.com>. +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 <stddef.h> +#include "libunwind_i.h" +#include "dwarf-eh.h" +#include "dwarf_i.h" + +int +unw_get_proc_info_in_range (unw_word_t start_ip, unw_word_t end_ip, + unw_word_t eh_frame_table, unw_word_t eh_frame_table_len, + unw_word_t exidx_frame_table, unw_word_t exidx_frame_table_len, + unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, + void *arg) +{ + int ret = 0; + + unw_dyn_info_t di; + memset(&di, 0, sizeof(di)); + + di.start_ip = start_ip; + di.end_ip = end_ip; + di.gp = pi->gp; + di.u.rti.name_ptr = 0; + +#if UNW_TARGET_ARM + if (exidx_frame_table != 0) { + di.format = UNW_INFO_FORMAT_ARM_EXIDX; + di.u.rti.table_data = exidx_frame_table; + di.u.rti.table_len = exidx_frame_table_len; + di.u.rti.segbase = 0; + } + else +#endif + if (eh_frame_table != 0) { + unw_accessors_t *a = unw_get_accessors_int (as); + + unw_word_t hdr; + if ((*a->access_mem)(as, eh_frame_table, &hdr, 0, arg) < 0) { + return -UNW_EINVAL; + } + struct dwarf_eh_frame_hdr* exhdr = (struct dwarf_eh_frame_hdr*)&hdr; + + if (exhdr->version != DW_EH_VERSION) { + Debug (1, "Unexpected version %d\n", exhdr->version); + return -UNW_EBADVERSION; + } + unw_word_t addr = eh_frame_table + offsetof(struct dwarf_eh_frame_hdr, eh_frame); + unw_word_t eh_frame_start; + unw_word_t fde_count; + + /* read eh_frame_ptr */ + if ((ret = dwarf_read_encoded_pointer(as, a, &addr, exhdr->eh_frame_ptr_enc, pi, &eh_frame_start, arg)) < 0) { + return ret; + } + + /* read fde_count */ + if ((ret = dwarf_read_encoded_pointer(as, a, &addr, exhdr->fde_count_enc, pi, &fde_count, arg)) < 0) { + return ret; + } + + // If there are no frame table entries + if (fde_count == 0) { + Debug(1, "No frame table entries\n"); + return -UNW_ENOINFO; + } + + if (exhdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { + Debug (1, "Table encoding not supported %x\n", exhdr->table_enc); + return -UNW_EINVAL; + } + + di.format = UNW_INFO_FORMAT_REMOTE_TABLE; + di.u.rti.table_data = addr; + di.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); + di.u.rti.segbase = eh_frame_table; + } + else { + Debug (1, "No frame table data\n"); + return -UNW_ENOINFO; + } + + ret = tdep_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg); + if (ret < 0) { + return ret; + } + + if (ip < pi->start_ip || ip >= pi->end_ip) { + Debug (1, "ip %p not in range start_ip %p end_ip %p\n", ip, pi->start_ip, pi->end_ip); + return -UNW_ENOINFO; + } + return UNW_ESUCCESS; +} diff --git a/src/mi/Lget_proc_info_in_range.c b/src/mi/Lget_proc_info_in_range.c new file mode 100644 index 00000000..da670090 --- /dev/null +++ b/src/mi/Lget_proc_info_in_range.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info_in_range.c" +#endif diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in index a5613927..cf1426db 100644 --- a/tests/check-namespace.sh.in +++ b/tests/check-namespace.sh.in @@ -107,6 +107,7 @@ check_local_unw_abi () { match _UL${plat}_get_fpreg match _UL${plat}_get_proc_info match _UL${plat}_get_proc_info_by_ip + match _UL${plat}_get_proc_info_in_range match _UL${plat}_get_proc_name match _UL${plat}_get_proc_name_by_ip match _UL${plat}_get_reg @@ -235,6 +236,7 @@ check_generic_unw_abi () { match _U${plat}_get_fpreg match _U${plat}_get_proc_info match _U${plat}_get_proc_info_by_ip + match _U${plat}_get_proc_info_in_range match _U${plat}_get_proc_name match _U${plat}_get_proc_name_by_ip match _U${plat}_get_reg |