00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: Process.cpp 1197 2014-10-14 22:26:11Z sella $";
00010
00011 #include "Process.h"
00012 #include "CommonMacro.h"
00013 #include "String.h"
00014
00015 #include <limits.h>
00016 #include <libgen.h>
00017 #include <unistd.h>
00018 #include <sys/types.h>
00019 #include <execinfo.h>
00020 #include <stdlib.h>
00021 #include <sys/prctl.h>
00022
00023 #ifdef __GNUG__
00024 #include <cxxabi.h>
00025 #endif
00026
00027 #define BUFFER_SIZE (1024 * 32)
00028
00029 using namespace sella::util;
00030
00031 std::string Process::getBaseName(void) throw () {
00032 std::string path = getPath();
00033
00034 if (path.empty()) {
00035 return path;
00036 }
00037
00038 return path.substr(path.rfind('/') + 1);
00039 }
00040
00041 std::string Process::getDirName(void) throw () {
00042 std::string path = getPath();
00043
00044 if (path.empty()) {
00045 return path;
00046 }
00047
00048 return path.substr(0, path.rfind('/'));
00049 }
00050
00051 std::string Process::getPath(void) throw () {
00052 std::string path;
00053 char *buf = (char*) malloc(PATH_MAX);
00054
00055 if (buf != NULL) {
00056 memset(buf, 0, PATH_MAX);
00057
00058 if (readlink("/proc/self/exe", buf, PATH_MAX - 1) != -1) {
00059 path = buf;
00060 }
00061
00062 SAFE_FREE(buf);
00063 }
00064
00065 return path;
00066 }
00067
00068 void Process::setName(const std::string &name) throw (ProcessException) {
00069 #ifdef PR_SET_NAME
00070 char buf[17];
00071
00072 memset(buf, 0, sizeof(buf));
00073 strncpy(buf, name.c_str(), sizeof(buf) - 1);
00074
00075 if (prctl(PR_SET_NAME, (unsigned long) buf, 0, 0, 0) != 0) {
00076 THROW2(ProcessException, "prctl");
00077 }
00078 #endif
00079 }
00080
00081 std::string Process::getName(void) throw (ProcessException) {
00082 char buf[17];
00083
00084 #ifdef PR_GET_NAME
00085 memset(buf, 0, sizeof(buf));
00086
00087 if (prctl(PR_GET_NAME, (unsigned long) buf, 0, 0, 0) != 0) {
00088 THROW2(ProcessException, "prctl");
00089 }
00090 #endif
00091
00092 return std::string(buf);
00093 }
00094
00095 void Process::setTitle(const std::string &title) throw (ProcessException) {
00096
00097 }
00098
00099 pid_t Process::getPID(void) throw () {
00100 return getpid();
00101 }
00102
00103 pid_t Process::getParentPID(void) throw () {
00104 return getppid();
00105 }
00106
00107 std::string Process::runCommand(const std::string &command) throw (ProcessException) {
00108 std::string output;
00109 FILE *fp;
00110
00111 if ((fp = popen(command.c_str(), "r"))) {
00112 char buf[4096];
00113
00114 while (fgets(buf, sizeof(buf) - 1, fp)) {
00115 output += buf;
00116 }
00117
00118 pclose(fp);
00119 } else {
00120 THROW2(ProcessException, "popen");
00121 }
00122
00123 return output;
00124 }
00125
00126 std::string Process::stackTrace(const std::string &executableFilename) throw () {
00127 size_t maxFrames = 63;
00128 void *frames[maxFrames + 1];
00129 int size = backtrace(frames, sizeof(frames) / sizeof(frames[0]));
00130 char **symbols = backtrace_symbols(frames, size);
00131
00132 std::string stack;
00133 size_t funcnamesize = 256;
00134 char* funcname = (char*) malloc(funcnamesize);
00135
00136 for (int i = 1; i < size; i++) {
00137 char *begin_name = 0, *begin_offset = 0, *end_offset = 0, *begin_address = 0, *end_address = 0;
00138
00139 for (char *p = symbols[i]; *p; ++p) {
00140 if (*p == '(') {
00141 begin_name = p;
00142 } else if (*p == '+') {
00143 begin_offset = p;
00144 } else if (*p == ')') {
00145 end_offset = p;
00146 } else if (*p == '[' && end_offset) {
00147 begin_address = p;
00148 } else if (*p == '[') {
00149 begin_address = p;
00150 begin_offset = p - 3;
00151 } else if (*p == ']' && begin_address) {
00152 end_address = p;
00153
00154 break;
00155 }
00156 }
00157
00158 if (begin_name && begin_offset && end_offset && begin_address && end_address && begin_name < begin_offset) {
00159 *begin_name++ = '\0';
00160 *begin_offset++ = '\0';
00161 *end_offset = '\0';
00162 *begin_address++ = '\0';
00163 *end_address = '\0';
00164
00165 void *ptr = (void*) strtol(begin_address + 2, NULL, 16);
00166 FILE *fp;
00167 std::string command = String::sprintf("/usr/bin/addr2line -i -s -e %s %s 2> /dev/null", executableFilename.c_str(), begin_address);
00168 std::vector<std::string> matches;
00169
00170 if ((fp = popen(command.c_str(), "r"))) {
00171 char buf[1024] = { 0 };
00172
00173 while (fgets(buf, sizeof(buf) - 1, fp)) { }
00174 String::regex_match(buf, "^([^:]+):([1-9][0-9]*).*?$", matches);
00175
00176 pclose(fp);
00177 }
00178
00179 int status = -2;
00180 #ifdef __GNUG__
00181 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
00182 #else
00183 char* ret = NULL;
00184 #endif
00185
00186 if (status == 0) {
00187 funcname = ret;
00188
00189 if (matches.empty()) {
00190 stack += String::sprintf("#%-2d %012p in %s from %s\n", i, ptr, funcname, symbols[i]);
00191 } else {
00192 stack += String::sprintf("#%-2d %012p in %s at %s:%s\n", i, ptr, funcname, matches[1].c_str(), matches[2].c_str());
00193 }
00194 } else {
00195 if (matches.empty()) {
00196 stack += String::sprintf("#%-2d %012p in %s() from %s\n", i, ptr, begin_name, symbols[i]);
00197 } else {
00198 stack += String::sprintf("#%-2d %012p in %s() at %s:%s\n", i, ptr, begin_name, matches[1].c_str(), matches[2].c_str());
00199 }
00200 }
00201 } else if (begin_name && begin_address && end_address) {
00202 *begin_name++ = '\0';
00203 *begin_address++ = '\0';
00204 *end_address = '\0';
00205
00206 void *ptr = (void*) strtol(begin_address + 2, NULL, 16);
00207
00208 stack += String::sprintf("#%-2d %012p in \?\?() from %s\n", i, ptr, symbols[i]);
00209 } else {
00210 stack += String::sprintf("#%-2d %012p in %s\n", i, 0, symbols[i]);
00211 }
00212 }
00213
00214 stack.erase(stack.size() - 1);
00215
00216 free(funcname);
00217 free(symbols);
00218
00219 return stack;
00220 }
00221
00222
00223
00224