summaryrefslogtreecommitdiff
path: root/src/x86_64/Gstep.c
diff options
context:
space:
mode:
authorkent-cheung-arm <40630626+kent-cheung-arm@users.noreply.github.com>2022-08-13 14:45:07 +0100
committerGitHub <noreply@github.com>2022-08-13 09:45:07 -0400
commit9afaef970b69c8f7e9194bb9956ba57215e97a4a (patch)
tree0af60207fc0b4f1d1df94e4a2e528aef1213b227 /src/x86_64/Gstep.c
parent67fb02721cbd846c8cc13a18e071cbf9c4dd1c1c (diff)
downloadlibunwind-9afaef970b69c8f7e9194bb9956ba57215e97a4a.tar.gz
Add support for unwinding from the Linux vsyscall region
This change fixes unwinding from the vsyscall region. Although vsyscall has been phased out, it is still possible to call into it at an address where libunwind is unable to step out of.
Diffstat (limited to 'src/x86_64/Gstep.c')
-rw-r--r--src/x86_64/Gstep.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c
index 4216d188..1dc440e3 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -25,6 +25,10 @@ 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. */
+#ifdef HAVE_ASM_VSYSCALL_H
+#include <asm/vsyscall.h>
+#endif
+
#include "libunwind_i.h"
#include "unwind_i.h"
#include <signal.h>
@@ -53,6 +57,20 @@ is_plt_entry (struct dwarf_cursor *c)
return ret;
}
+static int
+is_vsyscall (struct dwarf_cursor *c)
+{
+#if defined(VSYSCALL_START) && defined(VSYSCALL_END)
+ return c->ip >= VSYSCALL_START && c->ip < VSYSCALL_END;
+#elif defined(VSYSCALL_ADDR)
+ /* Linux 3.16 removes `VSYSCALL_START` and `VSYSCALL_END`. Assume
+ a single page is mapped for vsyscalls. */
+ return c->ip >= VSYSCALL_ADDR && c->ip < VSYSCALL_ADDR + sysconf(_SC_PAGESIZE);
+#else
+ return 0;
+#endif
+}
+
int
unw_step (unw_cursor_t *cursor)
{
@@ -141,6 +159,15 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
c->dwarf.cfa += 8;
}
+ else if (is_vsyscall (&c->dwarf))
+ {
+ Debug (2, "in vsyscall region\n");
+ c->frame_info.cfa_reg_offset = 8;
+ c->frame_info.cfa_reg_rsp = -1;
+ c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+ c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.cfa += 8;
+ }
else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)