1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <ctype.h> 7 #include <stdio.h> 8 #include <string.h> 9 10 #include "util.h" 11 12 #include "libconstants.h" 13 #include "libsyscalls.h" 14 15 /* 16 * These are syscalls used by the syslog() C library call. You can find them 17 * by running a simple test program. See below for x86_64 behavior: 18 * $ cat test.c 19 * #include <syslog.h> 20 * main() { syslog(0, "foo"); } 21 * $ gcc test.c -static 22 * $ strace ./a.out 23 * ... 24 * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection 25 * connect(...) <- important 26 * sendto(...) <- important 27 * exit_group(0) <- finish! 28 */ 29 #if defined(__x86_64__) 30 #if defined(__ANDROID__) 31 const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"}; 32 #else 33 const char *log_syscalls[] = {"connect", "sendto"}; 34 #endif 35 #elif defined(__i386__) 36 #if defined(__ANDROID__) 37 const char *log_syscalls[] = {"socketcall", "writev", "fcntl64", 38 "clock_gettime"}; 39 #else 40 const char *log_syscalls[] = {"socketcall", "time"}; 41 #endif 42 #elif defined(__arm__) 43 #if defined(__ANDROID__) 44 const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket", 45 "writev"}; 46 #else 47 const char *log_syscalls[] = {"connect", "gettimeofday", "send"}; 48 #endif 49 #elif defined(__aarch64__) 50 #if defined(__ANDROID__) 51 const char *log_syscalls[] = {"connect", "fcntl", "sendto", "socket", "writev"}; 52 #else 53 const char *log_syscalls[] = {"connect", "send"}; 54 #endif 55 #elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) || \ 56 defined(__sparc__) || defined(__mips__) 57 const char *log_syscalls[] = {"connect", "send"}; 58 #else 59 #error "Unsupported platform" 60 #endif 61 62 const size_t log_syscalls_len = sizeof(log_syscalls)/sizeof(log_syscalls[0]); 63 64 long int parse_single_constant(char *constant_str, char **endptr); 65 66 int lookup_syscall(const char *name) 67 { 68 const struct syscall_entry *entry = syscall_table; 69 for (; entry->name && entry->nr >= 0; ++entry) 70 if (!strcmp(entry->name, name)) 71 return entry->nr; 72 return -1; 73 } 74 75 const char *lookup_syscall_name(int nr) 76 { 77 const struct syscall_entry *entry = syscall_table; 78 for (; entry->name && entry->nr >= 0; ++entry) 79 if (entry->nr == nr) 80 return entry->name; 81 return NULL; 82 } 83 84 long int parse_constant(char *constant_str, char **endptr) 85 { 86 long int value = 0; 87 char *group, *lastpos = constant_str; 88 char *original_constant_str = constant_str; 89 90 /* 91 * Try to parse constants separated by pipes. Note that since 92 * |constant_str| is an atom, there can be no spaces between the 93 * constant and the pipe. Constants can be either a named constant 94 * defined in libconstants.gen.c or a number parsed with strtol. 95 * 96 * If there is an error parsing any of the constants, the whole process 97 * fails. 98 */ 99 while ((group = tokenize(&constant_str, "|")) != NULL) { 100 char *end = group; 101 value |= parse_single_constant(group, &end); 102 if (end == group) { 103 lastpos = original_constant_str; 104 value = 0; 105 break; 106 } 107 lastpos = end; 108 } 109 if (endptr) 110 *endptr = lastpos; 111 return value; 112 } 113 114 long int parse_single_constant(char *constant_str, char **endptr) 115 { 116 const struct constant_entry *entry = constant_table; 117 for (; entry->name; ++entry) { 118 if (!strcmp(entry->name, constant_str)) { 119 if (endptr) 120 *endptr = constant_str + strlen(constant_str); 121 122 return entry->value; 123 } 124 } 125 126 return strtol(constant_str, endptr, 0); 127 } 128 129 char *strip(char *s) 130 { 131 char *end; 132 while (*s && isblank(*s)) 133 s++; 134 end = s + strlen(s) - 1; 135 while (end >= s && *end && (isblank(*end) || *end == '\n')) 136 end--; 137 *(end + 1) = '\0'; 138 return s; 139 } 140 141 char *tokenize(char **stringp, const char *delim) 142 { 143 char *ret = NULL; 144 145 /* If the string is NULL or empty, there are no tokens to be found. */ 146 if (stringp == NULL || *stringp == NULL || **stringp == '\0') 147 return NULL; 148 149 /* 150 * If the delimiter is NULL or empty, 151 * the full string makes up the only token. 152 */ 153 if (delim == NULL || *delim == '\0') { 154 ret = *stringp; 155 *stringp = NULL; 156 return ret; 157 } 158 159 char *found; 160 while (**stringp != '\0') { 161 found = strstr(*stringp, delim); 162 163 if (!found) { 164 /* 165 * The delimiter was not found, so the full string 166 * makes up the only token, and we're done. 167 */ 168 ret = *stringp; 169 *stringp = NULL; 170 break; 171 } 172 173 if (found != *stringp) { 174 /* There's a non-empty token before the delimiter. */ 175 *found = '\0'; 176 ret = *stringp; 177 *stringp = found + strlen(delim); 178 break; 179 } 180 181 /* 182 * The delimiter was found at the start of the string, 183 * skip it and keep looking for a non-empty token. 184 */ 185 *stringp += strlen(delim); 186 } 187 188 return ret; 189 } 190