Adjust security-manager tests
[platform/core/test/security-tests.git] / tests / framework / src / gdbbacktrace.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 /*
18  * @file        gdbbacktrace.cpp
19  * @author      Pawel Broda (p.broda@partner.samsung.com)
20  * @version     1.0
21  * @brief       API providing backtrace
22  */
23
24 #include <fcntl.h>
25 #include <iomanip>
26 #include <iostream>
27 #include <sstream>
28 #include <sys/wait.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31
32 #include <dpl/gdbbacktrace.h>
33
34 namespace {
35 const size_t MAX_BACKTRACE_LINE_LENGTH = 1024;
36 const std::string COLOUR_CODE_RED("\033[31m");
37 const std::string COLOUR_CODE_RESET("\033[0m");
38
39 const std::string FRAME_PATTERN_WAITPID("#0  ");
40 const std::string FRAME_PATTERN_BACKTRACE("#1  ");
41 const std::string FRAME_PATTERN_DPL("in DPL::Test");
42
43 void print_colour(const std::string& err)
44 {
45     std::cerr << COLOUR_CODE_RED << err << COLOUR_CODE_RESET << std::endl;
46 }
47
48 bool backtrace_parse_line(const std::string& line, std::ostream& result, size_t line_number)
49 {
50     if (line.empty() || line[0] != '#')
51         return false;
52
53     // backtrace info - omit waitpid(), backtrace() and DPL frames
54     if (line.find(FRAME_PATTERN_WAITPID) == 0)
55         return false;
56
57     if (line.find(FRAME_PATTERN_BACKTRACE) == 0)
58         return false;
59
60     if (line.find(FRAME_PATTERN_DPL) != std::string::npos)
61         return false;
62
63     // example std::string line content:
64     // "#5  0x000000000040198d in main () at ../src/backtrace.cpp:105"
65     // should result in (i.e. would be written into char line_formatted):
66     // "main () at ../src/backtrace.cpp:105"
67
68     char line_formatted[MAX_BACKTRACE_LINE_LENGTH];
69     line_formatted[0] = '\0';
70     sscanf(line.c_str(), "%*s %*s %[^\n]", line_formatted);
71     if (line_formatted[0] != '\0') {
72         result << "#" << std::left << std::setw(2) << line_number << " " << line_formatted <<
73                   std::endl;
74         return true;
75     }
76
77     return false;
78 }
79
80 std::string backtrace_read(int fd)
81 {
82     FILE *bt_fd = fdopen(fd, "r");
83     char read_buffer[MAX_BACKTRACE_LINE_LENGTH];
84     std::ostringstream result;
85
86     result << std::endl;
87     size_t line_number = 1;
88     while (fgets(read_buffer, sizeof(read_buffer) - 1, bt_fd) != NULL) {
89         if (backtrace_parse_line(read_buffer, result, line_number))
90             ++line_number;
91     }
92
93     fclose(bt_fd);
94
95     // check if gdbbacktrace() called directly from the test
96     if (line_number == 2)
97         return "";
98
99     return result.str();
100 }
101 } // anonymous backtrace namespace end
102
103 std::string gdbbacktrace(void)
104 {
105     std::string pid_buf = std::to_string(getpid());
106     int pipe_fd[2];
107     pipe(pipe_fd);
108
109     int child_pid = fork();
110     if (child_pid == -1)
111     {
112         print_colour("fork needed to run gdb in batch mode failed...");
113         return "";
114     }
115
116     if (child_pid == 0) {
117         int devnull = open("/dev/null", O_WRONLY);
118         if (dup2(devnull, 2) == -1)
119             exit(2);
120         if (dup2(pipe_fd[1], 1) == -1)
121             exit(2);
122         execlp("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", "--pid",
123                pid_buf.c_str(), NULL);
124         // gdb failed to start...
125         exit(1);
126     }
127
128     int status;
129     int waitpid_res = waitpid(child_pid, &status, 0);
130
131     close(pipe_fd[1]);
132
133     std::string result;
134     if (waitpid_res == -1) {
135         print_colour("Backtrace not available (waitpid failed)");
136     } else if (status == 2) {
137         print_colour("Error: file descriptor duplication failed... failed to start gdb...");
138     } else if (status != 0) {
139         print_colour("Error: no gdb or failed to start gdb...");
140     } else {
141         result.append(backtrace_read(pipe_fd[0]));
142     }
143
144     close(pipe_fd[0]);
145
146     return result;
147 }