-
Notifications
You must be signed in to change notification settings - Fork 0
/
backtrace.cc
111 lines (89 loc) · 3.1 KB
/
backtrace.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2019, Arthus Leroy <[email protected]>
* On https://github.com/arthus-leroy/Python
* All rights reserved. */
// WARNING: need to use "sudo chmod +s /usr/bin/gdb" to allow gdb capture here
// Look at Ubuntu Wiki - Kernel hardening
# include "backtrace.hh"
# if defined(__unix) and defined(BACKTRACE)
# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/wait.h>
# include <unistd.h>
# define ERR() throw Error(strerror(errno))
void backtrace(unsigned skip)
{
char pid_buf[30];
const int pid = getpid();
sprintf(pid_buf, "--pid=%d", pid);
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)] = 0;
int p[2];
if (pipe(p) == -1)
ERR();
int child_pid = fork();
if (child_pid == -1)
ERR();
else if (child_pid == 0)
{
if (dup2(p[1], STDOUT_FILENO) == -1) // redirect stdout to in
ERR();
if (dup2(p[1], STDERR_FILENO) == -1) // redirect stderr to in
ERR();
close(p[1]); // close now useless in
close(p[0]); // and close useless out
fprintf(stdout, "stack trace for %s pid=%d\n", name_buf, pid);
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
ERR(); // exec should have replaced the program, but failed
}
else
{
char c;
waitpid(child_pid, NULL, 0); // wait for out
close(p[1]); // close in
// skip "waitpid" and "backtrace" in output
skip += 2;
unsigned skip_space = 0;
bool line = false;
int err;
while ((err = read(p[0], &c, 1)) > 0) // and read in
{
// begin delimiter
if (c == '#' && line == false)
{
if (skip == 0)
fprintf(stderr, " ");
skip_space = 0;
line = true;
}
// between '#' and '\n' after skipping X spaces and Y lines
if (line && skip == 0 && skip_space > 2)
fputc(c, stderr);
// number of spaces skipped
if (line && c == ' ')
skip_space++;
// end delimiter
if (line && c == '\n')
{
if (skip)
skip--;
line = false;
}
}
if (err == -1)
ERR();
close(p[1]);
}
throw Error("");
}
# else
void backtrace(unsigned)
{
throw Error("");
}
# endif