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__) 31const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"}; 32#else 33const char *log_syscalls[] = {"connect", "sendto"}; 34#endif 35#elif defined(__i386__) 36#if defined(__ANDROID__) 37const char *log_syscalls[] = {"socketcall", "writev", "fcntl64", 38 "clock_gettime"}; 39#else 40const char *log_syscalls[] = {"socketcall", "time"}; 41#endif 42#elif defined(__arm__) 43#if defined(__ANDROID__) 44const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket", 45 "writev"}; 46#else 47const char *log_syscalls[] = {"connect", "gettimeofday", "send"}; 48#endif 49#elif defined(__aarch64__) 50#if defined(__ANDROID__) 51const char *log_syscalls[] = {"connect", "fcntl", "sendto", "socket", "writev"}; 52#else 53const char *log_syscalls[] = {"connect", "send"}; 54#endif 55#elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) || \ 56 defined(__sparc__) || defined(__mips__) 57const char *log_syscalls[] = {"connect", "send"}; 58#else 59#error "Unsupported platform" 60#endif 61 62const size_t log_syscalls_len = sizeof(log_syscalls)/sizeof(log_syscalls[0]); 63 64long int parse_single_constant(char *constant_str, char **endptr); 65 66int 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 75const 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 84long 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 114long 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 129char *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 141char *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