summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdeel <3840695+am11@users.noreply.github.com>2022-06-29 19:13:56 +0300
committerStephen M. Webb <stephen.webb@bregmasoft.ca>2022-07-08 15:59:28 -0400
commit4640cd26d5e045b738bacc20ed92a7cf8e801c0f (patch)
tree9340c3756e6e732a9bbb7f3824b8eb40e65fe044
parentcfcf3d193a4425f58ed9556ec54b6d7ab0557330 (diff)
downloadlibunwind-4640cd26d5e045b738bacc20ed92a7cf8e801c0f.tar.gz
Expose get_proc_info_in_range API
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/unw_get_proc_info_in_range.man109
-rw-r--r--doc/unw_get_proc_info_in_range.tex70
-rw-r--r--include/libunwind-common.h.in61
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/mi/Gget_proc_info_in_range.c111
-rw-r--r--src/mi/Lget_proc_info_in_range.c5
-rw-r--r--tests/check-namespace.sh.in2
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