├── .gitignore ├── LICENSE ├── README.md ├── hw1 ├── Makefile ├── README.md └── hw1.cpp ├── hw2 ├── Makefile ├── README.md ├── fsmon.cpp ├── fsmon.hpp ├── logger.hpp └── typestring.hpp ├── hw3 ├── Makefile ├── README.md ├── alarm1.c ├── alarm2.c ├── alarm3.c ├── jmp1.c ├── libmini.c ├── libmini.h ├── libmini64.asm ├── start.asm ├── test.c ├── testlib │ ├── alarm1.c │ ├── alarm2.c │ ├── alarm3.c │ └── jmp1.c ├── testmini.c └── tmp │ ├── libmini.c │ ├── libmini.h │ └── libmini64.asm └── hw4 ├── Makefile ├── README.md ├── elftool.cpp ├── elftool.hpp ├── sample ├── guess └── hello64 ├── sdb.cpp └── sdb.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Si-Chen Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unix Programming 2 | 3 | - Fundamental tools and shell programming 4 | - Files and directories 5 | - File I/O and standard I/O 6 | - System data files and information 7 | - Process environment 8 | - Process control 9 | - Signals 10 | - Assembly language integration 11 | - Threads 12 | - Daemon processes 13 | - Advanced I/O 14 | - Inter-process communication 15 | - Network I/O 16 | - Other Topics 17 | -------------------------------------------------------------------------------- /hw1/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -Wall -g -std=c++17 3 | 4 | PROGS = hw1 5 | 6 | all: $(PROGS) 7 | 8 | %: %.cpp 9 | $(CXX) -o $@ $(CXXFLAGS) $< 10 | 11 | .PHONY: clean test 12 | 13 | clean: 14 | rm -f *~ $(PROGS) 15 | 16 | test: $(PROGS) 17 | sudo ./$< 18 | -------------------------------------------------------------------------------- /hw1/README.md: -------------------------------------------------------------------------------- 1 | # Implement a 'netstat -nap'-like program 2 | In this homework, you have to implement a 'netstat -nap' tool by yourself. You have to list all the existing TCP and UDP connections. For each identified connection (socket descriptor), find the corresponding process name and its command lines that creates the connection (socket descriptor). **You have to implement all the features by yourself and cannot make calls to the system built-in netstat program nor parse output from 'netstat -nap'.** Your codes must be implemented in C and/or C++. 3 | 4 | To provide more flexibilities, your program have to accept several predefined options, including 5 | 6 | - -t or --tcp: list only TCP connections. 7 | - -u or --udp: list only UDP connections. 8 | - An optional string to list only command lines that containing the string. 9 | 10 | You have to handle the additional options using getopt_long function. In short, the synopsis of homework #1 would be: 11 | 12 | ```$ ./hw1 [-t|--tcp] [-u|--udp] [filter-string]``` 13 | 14 | When no argument is passed, your program should output all identified connections. You may test your program with a root account so that your program would be able to access /proc files owned by other users. 15 | -------------------------------------------------------------------------------- /hw1/hw1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define PB push_back 17 | 18 | using namespace std; 19 | 20 | typedef vector VS; 21 | typedef vector VI; 22 | 23 | char optstring[] = "tu"; 24 | 25 | struct option longopts[] = { 26 | {"tcp", no_argument, NULL, 't'}, 27 | {"udp", no_argument, NULL, 'u'}, 28 | {NULL, no_argument, NULL, 0} 29 | }; 30 | 31 | bool is_v6 = false; 32 | bool is_tcp = true; 33 | 34 | string nettype[] = {"udp", "udp6", "tcp", "tcp6"}; 35 | 36 | struct netstat { 37 | int ty; 38 | VS s; 39 | void print() { 40 | cout << setiosflags(ios::left) << setw(6) 41 | << nettype[ty] 42 | << setw(24) 43 | << s[0] + ":" + s[1] 44 | << setw(24) 45 | << s[2] + ":" + s[3] 46 | << s[4] + "/" + s[5] << endl; 47 | } 48 | }; 49 | 50 | vector tcps, udps; 51 | // inode, pid 52 | map map2pid; 53 | // pid, cmd 54 | map map2cmd; 55 | string filter; 56 | 57 | void list(const string name) { 58 | cout << "List of " << name << " connections:" << endl; 59 | cout << setiosflags(ios::left) << setw(6) 60 | << "Proto" << setw(24) 61 | << "Local Address" << setw(24) 62 | << "Foreign Address" 63 | << "PID/Program name and arguments" << endl; 64 | } 65 | 66 | VS split(const string &s, const char d = '\0') { 67 | VS res; 68 | stringstream ss(s); 69 | string item; 70 | if (d) 71 | while (getline(ss, item, d)) res.PB(item); 72 | else 73 | while (ss >> item) res.PB(item); 74 | return res; 75 | } 76 | 77 | void h2i(const string &s, auto &x) { 78 | stringstream ss; 79 | ss << hex << s; 80 | ss >> x; 81 | } 82 | 83 | bool recmp(const string &s, const string &pat) { 84 | regex re(pat); 85 | return regex_search(s, re); 86 | } 87 | 88 | string get_addr(const string &s) { 89 | if (is_v6) { 90 | struct sockaddr_in6 sa; 91 | for (int i = 0; i < 4; i++) { 92 | h2i(s.substr(i * 8, 8), sa.sin6_addr.s6_addr32[i]); 93 | } 94 | char str[INET6_ADDRSTRLEN + 1] = {0}; 95 | inet_ntop(AF_INET6, &(sa.sin6_addr), str, INET6_ADDRSTRLEN); 96 | return str; 97 | } 98 | else { 99 | struct sockaddr_in sa; 100 | h2i(s, sa.sin_addr.s_addr); 101 | char str[INET_ADDRSTRLEN + 1] = {0}; 102 | inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); 103 | return str; 104 | } 105 | } 106 | 107 | string get_port(const string &s) { 108 | int port; 109 | h2i(s, port); 110 | return port ? to_string(port) : "*"; 111 | } 112 | 113 | VS convert(const string &s) { 114 | VS tmp = split(s, ':'), res; 115 | res.PB(get_addr(tmp[0])); 116 | res.PB(get_port(tmp[1])); 117 | return res; 118 | } 119 | 120 | VS list_dir(const string &path) { 121 | VS res; 122 | DIR *dirp = opendir(path.c_str()); 123 | if (dirp == NULL) return res; 124 | struct dirent *dp; 125 | while ((dp = readdir(dirp)) != NULL) { 126 | res.PB(dp->d_name); 127 | } 128 | closedir(dirp); 129 | return res; 130 | } 131 | 132 | int get_sockinode(const string &path) { 133 | struct stat sb; 134 | if (stat(path.c_str(), &sb) == -1) { 135 | return -1; 136 | } 137 | return (sb.st_mode & S_IFMT) == S_IFSOCK ? sb.st_ino : -1; 138 | } 139 | 140 | string get_cmd(const string &path) { 141 | ifstream fin(path); 142 | string cmd; 143 | getline(fin, cmd); 144 | for (auto &x : cmd) { 145 | if (x == '\0') x = ' '; 146 | } 147 | fin.close(); 148 | return cmd; 149 | } 150 | 151 | void build_map() { 152 | string proc = "/proc/"; 153 | VS pids = list_dir(proc); 154 | for (auto &pid : pids) { 155 | string fd_path = proc + pid + "/fd/"; 156 | string cmd = get_cmd(proc + pid + "/cmdline"); 157 | if (cmd == "") continue; 158 | map2cmd[pid] = cmd; 159 | VS items = list_dir(fd_path); 160 | for (auto &x : items) { 161 | int inode = get_sockinode(fd_path + x); 162 | if (inode != -1) { 163 | map2pid[to_string(inode)] = pid; 164 | } 165 | } 166 | } 167 | } 168 | 169 | void parse(const string &path) { 170 | ifstream fin(path); 171 | string tmp; 172 | getline(fin, tmp); // don't need the first line 173 | while (getline(fin, tmp)) { 174 | VS v = split(tmp); 175 | VS lo = convert(v[1]), fo = convert(v[2]); 176 | string pid = map2pid[v[9]]; 177 | string cmd = map2cmd[pid]; 178 | netstat n{(is_tcp << 1) | is_v6, {lo[0], lo[1], fo[0], fo[1], pid, cmd}}; 179 | is_tcp ? tcps.PB(n) : udps.PB(n); 180 | } 181 | fin.close(); 182 | } 183 | 184 | void list_tcp() { 185 | is_tcp = true; 186 | is_v6 = false; 187 | parse("/proc/net/tcp"); 188 | is_v6 = true; 189 | parse("/proc/net/tcp6"); 190 | list("TCP"); 191 | for (auto &x : tcps) { 192 | if (filter == "" || recmp(x.s[5], filter)) 193 | x.print(); 194 | } 195 | cout << endl; 196 | } 197 | 198 | void list_udp() { 199 | is_tcp = false; 200 | is_v6 = false; 201 | parse("/proc/net/udp"); 202 | is_v6 = true; 203 | parse("/proc/net/udp6"); 204 | list("UDP"); 205 | for (auto &x : udps) { 206 | if (filter == "" || recmp(x.s[5], filter)) 207 | x.print(); 208 | } 209 | cout << endl; 210 | } 211 | 212 | int main(int argc, char* argv[]) { 213 | bool list_t = false, list_u = false; 214 | int c; 215 | while ((c = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) { 216 | switch (c) { 217 | case 't': 218 | list_t = true; 219 | break; 220 | case 'u': 221 | list_u = true; 222 | break; 223 | default: 224 | cout << "Usage: ./hw1 [-t|--tcp] [-u|--udp] [filter-string]" << endl; 225 | return 1; 226 | } 227 | } 228 | argc -= optind; 229 | argv += optind; 230 | if (argv[0] != NULL) filter = argv[0]; 231 | build_map(); 232 | if (list_t | list_u) { 233 | if (list_t) list_tcp(); 234 | if (list_u) list_udp(); 235 | } 236 | else { 237 | list_tcp(); 238 | list_udp(); 239 | } 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /hw2/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -shared -fPIC -std=c++17 3 | LDL = -ldl 4 | 5 | PROGS = fsmon.so 6 | 7 | all: $(PROGS) 8 | 9 | %.so: %.cpp 10 | $(CXX) -o $@ $(CXXFLAGS) $^ $(LDL) 11 | 12 | .PHONY: clean 13 | 14 | clean: 15 | rm -f *~ $(PROGS) 16 | -------------------------------------------------------------------------------- /hw2/README.md: -------------------------------------------------------------------------------- 1 | # Monitor File and Directory Activities of Dynamically Linked Programs 2 | 3 | In this homework, we are going to practice library injection and API hijacking. Please implement a "library call monitor" (LCM) program that is able to show the activities of an arbitrary binary running on a Linux operating system. You have to implement your LCM as a shared library and inject the shared library into a process by using LD_PRELOAD. You have to dump the library calls as well as the passed parameters and the returned values. Please monitor file and directory relevant functions listed in the section "Minimum Requirements" below. The result should be output to either stderr or a filename, e.g., "**fsmon.log**". By default, the output is written to stderr. But you may write the output to a filename specified by an environment variable "**MONITOR_OUTPUT**". 4 | 5 | You have to compile your source codes and generate a shared object. You don't have to implement any monitored program by yourself. Instead, you should work with those binaries already installed in the system, or the test cases provided by the instructor. 6 | 7 | ## Minimum Requirements 8 | 9 | The minimum list of monitored library calls is shown below. It covers almost all the functions we have introduced in the class. 10 | 11 | **closedir opendir readdir creat open read write dup** 12 | 13 | **dup2 close lstat stat pwrite fopen fclose fread** 14 | 15 | **fwrite fgetc fgets fscanf fprintf chdir chown chmod** 16 | 17 | **remove rename link unlink readlink symlink mkdir rmdir** 18 | 19 | If you would like to monitor more, please read the function lists from the following manual pages: (ordered alphabetically) 20 | 21 | 1. [dirent.h(P)](http://man7.org/linux/man-pages/man0/dirent.h.0p.html) 22 | 2. [fcntl.h(P)](http://man7.org/linux/man-pages/man0/fcntl.h.0p.html) 23 | 3. [stdio.h(P)](http://man7.org/linux/man-pages/man0/stdio.h.0p.html) 24 | 4. [stdlib.h(P)](http://man7.org/linux/man-pages/man0/stdlib.h.0p.html) 25 | 5. [sys_socket.h(7POSIX)](http://man7.org/linux/man-pages/man0/sys_socket.h.0p.html) (network functions) 26 | 6. [unistd.h(P)](http://man7.org/linux/man-pages/man0/unistd.h.0p.html) 27 | 7. [sys_stat.h(7POSIX)](http://man7.org/linux/man-pages/man0/sys_stat.h.0p.html) 28 | 29 | ## Display Function Call Parameters and Return Values 30 | 31 | You will get a basic score if you only print out the raw value of monitored function calls. For example, the primitive data types **char**, **int**, **short**, **long**, **long long**, **float**, and **double**. For pointers, you can also print out its raw values. If you would like to get higher scores, you should output comprehensible outputs for the user. Here are additional explanations for the comprehensible output format. 32 | 33 | 1. For **char*** data type, you may optionally print it out as a string. 34 | 2. For file descriptors (passed as an **int**), **FILE***, and **DIR*** pointers, you can convert them to corresponding file names. 35 | 3. For **struct stat** or its pointer, retrieve meaningful information from the structure. For example, file type, file size, and permissions. 36 | -------------------------------------------------------------------------------- /hw2/fsmon.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "fsmon.hpp" 9 | #include "logger.hpp" 10 | #include "typestring.hpp" 11 | 12 | using namespace std; 13 | 14 | bool islog = true; 15 | FILE * logfile = NULL; 16 | 17 | void output(const char *format, ...) { 18 | va_list args; 19 | va_start(args, format); 20 | vfprintf(logfile, format, args); 21 | va_end(args); 22 | } 23 | 24 | string readlinkfd(const int &x) { 25 | char tmp[4096] = {0}; 26 | string s = "/proc/self/fd/" + to_string(x); 27 | islog = false; 28 | readlink(s.c_str(), tmp, sizeof(tmp)); 29 | islog = true; 30 | return tmp; 31 | } 32 | 33 | void initlog() { 34 | if (logfile != NULL) return; 35 | islog = false; 36 | char *fname = getenv("MONITOR_OUTPUT"); 37 | if (fname != NULL) logfile = fopen(fname, "w"); 38 | else logfile = stderr; 39 | islog = true; 40 | } 41 | 42 | __attribute__((destructor)) void finlog() { 43 | islog = false; 44 | char *fname = getenv("MONITOR_OUTPUT"); 45 | if (fname != NULL) fclose(logfile); 46 | islog = true; 47 | } 48 | 49 | template 50 | void getfunc(T &old_func, const char* sym) { 51 | void *handle = dlopen(LIBC, RTLD_LAZY); 52 | if (handle != NULL) { 53 | old_func = (T) dlsym(handle, sym); 54 | } 55 | } 56 | 57 | template 58 | auto hook(T func, const char* sym, TS ... args) { 59 | static T old_func = NULL; 60 | getfunc(old_func, sym); 61 | if (old_func != NULL) { 62 | return old_func(args...); 63 | } 64 | } 65 | 66 | extern "C" { 67 | HOOKOP(FD, open, const char *, pathname, int, flags, mode_t, mode); 68 | HOOKST(int ,__xstat, const char *, pathname, struct stat *, statbuf); 69 | HOOKST(int ,__lxstat, const char *, pathname, struct stat *, statbuf); 70 | HOOKVA(int, __isoc99_fscanf, FILE *, stream, const char *, format, vfscanf); 71 | HOOKVA(int, fprintf, FILE *, stream, const char *, format, vfprintf); 72 | HOOK1(int, closedir, DIR *, dirp); 73 | HOOK1(DIR *, opendir, const char *, name); 74 | HOOK1(struct dirent *, readdir, DIR *, dirp); 75 | HOOK2(FD, creat, const char *, pathname, mode_t, mode); 76 | HOOK3(ssize_t, read, FD, fd, void *, buf, size_t, count); 77 | HOOK3(ssize_t, write, FD, fd, const void *, buf, size_t, count); 78 | HOOK1(FD, dup, FD, oldfd); 79 | HOOK2(FD, dup2, FD, oldfd, FD, newfd); 80 | HOOK1(int, close, FD, fd); 81 | HOOK4(ssize_t, pwrite, FD, fd, const void *, buf, size_t, count, off_t, offset); 82 | HOOK2(FILE *, fopen, const char *, pathname, const char *, mode); 83 | HOOK1(int, fclose, FILE *, stream); 84 | HOOK4(size_t, fread, void *, ptr, size_t, size, size_t, nmemb, FILE *, stream); 85 | HOOK4(size_t, fwrite, const void *, ptr, size_t, size, size_t, nmemb, FILE *, stream); 86 | HOOK1(int, fgetc, FILE *, stream); 87 | HOOK3(char *, fgets, char *, s, int, size, FILE *, stream); 88 | HOOK1(int, chdir, const char *, path); 89 | HOOK3(int, chown, const char *, pathname, uid_t, owner, gid_t, group); 90 | HOOK2(int, chmod, const char *, pathname, mode_t, mode); 91 | HOOK1(int, remove, const char *, pathname); 92 | HOOK2(int, rename, const char *, oldpath, const char *, newpath); 93 | HOOK2(int, link, const char *, oldpath, const char *, newpath); 94 | HOOK1(int, unlink, const char *, pathname); 95 | HOOK3(ssize_t, readlink, const char *, pathname, char *, buf, size_t, bufsiz); 96 | HOOK2(int, symlink, const char *, target, const char *, linkpath); 97 | HOOK2(int, mkdir, const char *, pathname, mode_t, mode); 98 | HOOK1(int, rmdir, const char *, pathname); 99 | } 100 | -------------------------------------------------------------------------------- /hw2/fsmon.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | typedef int FD; 8 | 9 | #define LIBC "libc.so.6" 10 | 11 | #define __OPEN_NEEDS_MODE(oflag) (((oflag) & 0100) != 0) 12 | 13 | #define FNclosedir "closedir" 14 | #define FNopendir "opendir" 15 | #define FNreaddir "readdir" 16 | #define FNcreat "creat" 17 | #define FNopen "open" 18 | #define FNread "read" 19 | #define FNwrite "write" 20 | #define FNdup "dup" 21 | #define FNdup2 "dup2" 22 | #define FNclose "close" 23 | #define FN__lxstat "lstat" 24 | #define FN__xstat "stat" 25 | #define FNpwrite "pwrite" 26 | #define FNfopen "fopen" 27 | #define FNfclose "fclose" 28 | #define FNfread "fread" 29 | #define FNfwrite "fwrite" 30 | #define FNfgetc "fgetc" 31 | #define FNfgets "fgets" 32 | #define FN__isoc99_fscanf "fscanf" 33 | #define FNfprintf "fprintf" 34 | #define FNchdir "chdir" 35 | #define FNchown "chown" 36 | #define FNchmod "chmod" 37 | #define FNremove "remove" 38 | #define FNrename "rename" 39 | #define FNlink "link" 40 | #define FNunlink "unlink" 41 | #define FNreadlink "readlink" 42 | #define FNsymlink "symlink" 43 | #define FNmkdir "mkdir" 44 | #define FNrmdir "rmdir" 45 | 46 | #define HOOK1(ret, sym, t1, p1) \ 47 | ret sym(t1 p1) { \ 48 | ret tmp; \ 49 | if (islog) { \ 50 | initlog(); \ 51 | Logger l(FN##sym, false); \ 52 | if (FN##sym == FNclose || FN##sym == FNfclose || FN##sym == FNclosedir || FN##sym == FNdup) { \ 53 | l = l.add(#t1, p1); \ 54 | tmp = hook(sym, #sym, p1); \ 55 | l.addret(#ret, tmp).log(); \ 56 | } \ 57 | else { \ 58 | tmp = hook(sym, #sym, p1); \ 59 | l.add(#t1, p1).addret(#ret, tmp).log(); \ 60 | } \ 61 | } \ 62 | return tmp; \ 63 | } 64 | 65 | #define HOOK2(ret, sym, t1, p1, t2, p2) \ 66 | ret sym(t1 p1, t2 p2) { \ 67 | ret tmp; \ 68 | if (islog) { \ 69 | initlog(); \ 70 | Logger l(FN##sym, false); \ 71 | if (FN##sym == FNdup2) { \ 72 | l = l.add(#t1, p1); \ 73 | tmp = hook(sym, #sym, p1, p2); \ 74 | l.add(#t2, p2).addret(#ret, tmp).log(); \ 75 | } \ 76 | else { \ 77 | tmp = hook(sym, #sym, p1, p2); \ 78 | l.add(#t1, p1).add(#t2, p2).addret(#ret, tmp).log(); \ 79 | } \ 80 | } \ 81 | return tmp; \ 82 | } 83 | 84 | #define HOOK3(ret, sym, t1, p1, t2, p2, t3, p3) \ 85 | ret sym(t1 p1, t2 p2, t3 p3) { \ 86 | ret tmp = hook(sym, #sym, p1, p2, p3); \ 87 | if (islog) { \ 88 | initlog(); \ 89 | Logger l(FN##sym, false); \ 90 | l.add(#t1, p1).add(#t2, p2).add(#t3, p3).addret(#ret, tmp).log(); \ 91 | } \ 92 | return tmp; \ 93 | } 94 | 95 | #define HOOK4(ret, sym, t1, p1, t2, p2, t3, p3, t4, p4) \ 96 | ret sym(t1 p1, t2 p2, t3 p3, t4 p4) { \ 97 | ret tmp = hook(sym, #sym, p1, p2, p3, p4); \ 98 | if (islog) { \ 99 | initlog(); \ 100 | Logger l(FN##sym, false); \ 101 | l.add(#t1, p1).add(#t2, p2).add(#t3, p3).add(#t4, p4).addret(#ret, tmp).log(); \ 102 | } \ 103 | return tmp; \ 104 | } 105 | 106 | #define HOOKVA(ret, sym, t1, p1, t2, p2, func) \ 107 | ret sym(t1 p1, t2 p2, ...) { \ 108 | va_list args; \ 109 | va_start(args, p2); \ 110 | ret tmp = func(p1, p2, args); \ 111 | if (islog) { \ 112 | initlog(); \ 113 | Logger l(FN##sym, true); \ 114 | l.add(#t1, p1).add(#t2, p2).addret(#ret, tmp).log(); \ 115 | } \ 116 | va_end(args); \ 117 | return tmp; \ 118 | } 119 | 120 | #define HOOKST(ret, sym, t1, p1, t2, p2) \ 121 | ret sym(int ver, t1 p1, t2 p2) { \ 122 | ret tmp = hook(sym, #sym, 1, p1, p2); \ 123 | if (islog) { \ 124 | initlog(); \ 125 | Logger l(FN##sym, false); \ 126 | l.add(#t1, p1).add(#t2, p2).addret(#ret, tmp).log(); \ 127 | } \ 128 | return tmp; \ 129 | } 130 | 131 | #define HOOKOP(ret, sym, t1, p1, t2, p2, t3, p3) \ 132 | ret sym(t1 p1, t2 p2, t3 p3 = 04) { \ 133 | ret tmp = hook(sym, #sym, p1, p2, p3); \ 134 | if (islog) { \ 135 | initlog(); \ 136 | Logger l(FN##sym, false); \ 137 | l = l.add(#t1, p1).add(#t2, p2); \ 138 | if (__OPEN_NEEDS_MODE(p2)) l = l.add(#t3, p3); \ 139 | l.addret(#ret, tmp).log(); \ 140 | } \ 141 | return tmp; \ 142 | } 143 | 144 | void output(const char *format, ...); 145 | string readlinkfd(const int &x); 146 | -------------------------------------------------------------------------------- /hw2/logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "fsmon.hpp" 6 | #include "typestring.hpp" 7 | 8 | using namespace std; 9 | 10 | class Logger { 11 | public: 12 | Logger(const string &n, const bool iv) 13 | : name(n), isva(iv) { 14 | } 15 | Logger add(const string &t, auto &x) const { 16 | Logger l = *this; 17 | l.argv.push_back(auto2s(t, x)); 18 | return l; 19 | } 20 | Logger addret(const string &t, auto &x) const { 21 | Logger l = *this; 22 | l.ret = auto2s(t, x); 23 | return l; 24 | } 25 | void log() { 26 | bool isfir = true; 27 | output("# %s(", name.c_str()); 28 | for (auto &x : argv) { 29 | if (isfir) { 30 | output("%s", x.c_str()); 31 | isfir = false; 32 | continue; 33 | } 34 | output(", %s", x.c_str()); 35 | } 36 | output(isva ? ", ...) = %s\n" : ") = %s\n", ret.c_str()); 37 | } 38 | private: 39 | bool isva; 40 | string name, ret; 41 | vector argv; 42 | }; 43 | -------------------------------------------------------------------------------- /hw2/typestring.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "fsmon.hpp" 8 | 9 | using namespace std; 10 | 11 | string fd2name(const int &x) { 12 | if (x == fileno(stdin)) return "\"\""; 13 | if (x == fileno(stdout)) return "\"\""; 14 | if (x == fileno(stderr)) return "\"\""; 15 | string tmp = readlinkfd(x); 16 | return "\"" + tmp + "\""; 17 | } 18 | 19 | string i2h(auto &x) { 20 | string tmp; 21 | stringstream ss; 22 | ss << hex << x; 23 | ss >> tmp; 24 | return "0x" + tmp; 25 | } 26 | 27 | string i2o(auto &x) { 28 | string tmp; 29 | stringstream ss; 30 | ss << oct << x; 31 | ss >> tmp; 32 | return "0" + tmp; 33 | } 34 | 35 | string auto2s(const string &t, const void *x) { 36 | if (x == NULL) return "NULL"; 37 | auto tmp = (long long unsigned int) x; 38 | return i2h(tmp); 39 | } 40 | 41 | string auto2s(const string &t, const char *x) { 42 | if (x == NULL) return "NULL"; 43 | string tmp(x); 44 | return "\"" + tmp + "\""; 45 | } 46 | 47 | string auto2s(const string &t, FILE *x) { 48 | if (x == NULL) return "NULL"; 49 | return fd2name(fileno(x)); 50 | } 51 | 52 | string auto2s(const string &t, DIR *x) { 53 | if (x == NULL) return "NULL"; 54 | return fd2name(dirfd(x)); 55 | } 56 | 57 | string auto2s(const string &t, struct dirent *x) { 58 | if (x == NULL) return "NULL"; 59 | string tmp(x->d_name); 60 | return "\"" + tmp + "\""; 61 | } 62 | 63 | string auto2s(const string &t, struct stat *x) { 64 | if (x == NULL) return "NULL"; 65 | auto tmp = (unsigned long) x->st_mode; 66 | string mode = i2o(tmp); 67 | string sz = to_string((long long) x->st_size); 68 | string addr = auto2s(t, (void *) x); 69 | return addr + " {mode=" + mode + ", size=" + sz + "}"; 70 | } 71 | 72 | string auto2s(const string &t, int x) { 73 | if (t == "FD") return fd2name(x); 74 | return to_string(x); 75 | } 76 | 77 | string auto2s(const string &t, unsigned int x) { 78 | if (t == "mode_t") return i2o(x); 79 | return to_string(x); 80 | } 81 | 82 | string auto2s(const string &t, long int x) { 83 | return to_string(x); 84 | } 85 | 86 | string auto2s(const string &t, long unsigned int x) { 87 | return to_string(x); 88 | } 89 | -------------------------------------------------------------------------------- /hw3/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | ASM64 = yasm -f elf64 -DYASM -D__x86_64__ -DPIC 3 | 4 | CFLAGS = -g -Wall -fno-stack-protector 5 | 6 | PROGS = libmini.so 7 | 8 | all: $(PROGS) 9 | 10 | libmini.so: libmini64.asm libmini.c 11 | $(ASM64) $< -o libmini64.o 12 | $(CC) -c $(CFLAGS) -fPIC -nostdlib libmini.c 13 | ld -shared libmini64.o libmini.o -o $@ 14 | 15 | .PHONY: test clean 16 | 17 | test: start.asm test.c 18 | $(ASM64) $< -o start.o 19 | $(CC) -c $(CFLAGS) -nostdlib -I. -I.. -DUSEMINI test.c 20 | ld -m elf_x86_64 --dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test test.o start.o -L. -L.. -lmini 21 | LD_LIBRARY_PATH=. ./test 22 | 23 | clean: 24 | rm -f a.out test *.o $(PROGS) peda-* 25 | 26 | -------------------------------------------------------------------------------- /hw3/README.md: -------------------------------------------------------------------------------- 1 | # Extend the Mini Lib C to Handle Signals 2 | 3 | In this homework, you have to extend the mini C library introduced in the class to support signal relevant system calls. You have to implement the following C library functions in Assembly and C using the syntax supported by yasm x86_64 assembler. 4 | 5 | 1. setjmp: prepare for long jump by saving the current CPU state. In addition, preserve the signal mask of the current process. 6 | 2. longjmp: perform the long jump by restoring a saved CPU state. In addition, restore the preserved signal mask. 7 | 3. signal and sigaction: setup the handler of a signal. 8 | 4. sigprocmask: can be used to block/unblock signals, and get/set the current signal mask. 9 | 5. sigpending: check if there is any pending signal. 10 | 6. alarm: setup a timer for the current process. 11 | 7. functions to handle sigset_t data type: sigemptyset, sigfillset, sigaddset, sigdelset, and sigismember. 12 | 13 | The API interface is the same to what we have in the standard C library. However, because we are attempting to replace the standard C library, our test codes will only be linked against the library implemented in this homework. We will use the following commands to assemble, compile, link, and test your implementation. 14 | 15 | ``` 16 | $ yasm -f elf64 -DYASM -D__x86_64__ -DPIC libmini64.asm -o libmini64.o 17 | $ gcc -c -g -Wall -fno-stack-protector -fPIC -nostdlib libmini.c 18 | $ ld -shared -o libmini.so libmini64.o libmini.o 19 | $ yasm -f elf64 -DYASM -D__x86_64__ -DPIC start.asm -o start.o 20 | $ gcc -c -g -Wall -fno-stack-protector -nostdlib -I. -I.. -DUSEMINI test.c 21 | $ ld -m elf_x86_64 --dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test test.o start.o -L. -L.. -lmini 22 | ``` 23 | 24 | Where *libmini64.asm* and *libmini.c* is your extended Assembly and C implmentation for this homework, respectively, and *test.c* is the testing code prepared by the TAs. The start.o file is the program [start routine](https://people.cs.nctu.edu.tw/~chuang/courses/unixprog/resources/hw3_sigasm/start.asm) we have introduced in the class. Please notice that there is a *-nostdlib* parameter passed to the compiler, which means that you could not use any existing functions implemented in the standard C library. Only the functions you have implemented in the *libmini64.asm* and *libmini.c* file can be used. In addition to your library source code, you also have to provide a corresponding *libmini.h* file. The testing codes will include this file and use the function prototypes and data types defined in the header file. 25 | 26 | To ensure that your library can handle signals properly, your implemented setjmp function *must save the signal mask* of the current process in your customized jmp_buf data structure. The saved signal mask *must be restored* by the longjmp function. *This requirement is different from the default setjmp/longjmp implementation*. 27 | -------------------------------------------------------------------------------- /hw3/alarm1.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | int main() { 3 | alarm(3); 4 | pause(); 5 | return 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /hw3/alarm2.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | int main() { 4 | sigset_t s; 5 | sigemptyset(&s); 6 | sigaddset(&s, SIGALRM); 7 | sigprocmask(SIG_BLOCK, &s, NULL); 8 | alarm(3); 9 | sleep(5); 10 | if(sigpending(&s) < 0) perror("sigpending"); 11 | if(sigismember(&s, SIGALRM)) { 12 | char m[] = "sigalrm is pending.\n"; 13 | write(1, m, sizeof(m)); 14 | } else { 15 | char m[] = "sigalrm is not pending.\n"; 16 | write(1, m, sizeof(m)); 17 | } 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /hw3/alarm3.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | void handler(int s) { /* do nothing */ } 4 | 5 | int main() { 6 | sigset_t s; 7 | sigemptyset(&s); 8 | sigaddset(&s, SIGALRM); 9 | sigprocmask(SIG_BLOCK, &s, NULL); 10 | signal(SIGALRM, SIG_IGN); 11 | signal(SIGINT, handler); 12 | alarm(1); 13 | pause(); 14 | if(sigpending(&s) < 0) perror("sigpending"); 15 | if(sigismember(&s, SIGALRM)) { 16 | char m[] = "sigalrm is pending.\n"; 17 | write(1, m, sizeof(m)); 18 | } else { 19 | char m[] = "sigalrm is not pending.\n"; 20 | write(1, m, sizeof(m)); 21 | } 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /hw3/jmp1.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | typedef void (*proc_t)(); 4 | static jmp_buf jb; 5 | 6 | #define FUNBODY(m, from) { write(1, m, strlen(m)); longjmp(jb, from); } 7 | 8 | void a() FUNBODY("This is function a().\n", 1); 9 | void b() FUNBODY("This is function b().\n", 2); 10 | void c() FUNBODY("This is function c().\n", 3); 11 | void d() FUNBODY("This is function d().\n", 4); 12 | void e() FUNBODY("This is function e().\n", 5); 13 | void f() FUNBODY("This is function f().\n", 6); 14 | void g() FUNBODY("This is function g().\n", 7); 15 | void h() FUNBODY("This is function h().\n", 8); 16 | void i() FUNBODY("This is function i().\n", 9); 17 | void j() FUNBODY("This is function j().\n", 10); 18 | 19 | proc_t funs[] = { a, b, c, d, e, f, g, h, i, j }; 20 | 21 | int main() { 22 | volatile int i = 0; 23 | if(setjmp(jb) != 0) { 24 | i++; 25 | } 26 | if(i < 10) funs[i](); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /hw3/libmini.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | long errno; 4 | 5 | #define WRAPPER_RETval(type) errno = 0; if(ret < 0) { errno = -ret; return -1; } return ((type) ret); 6 | #define WRAPPER_RETptr(type) errno = 0; if(ret < 0) { errno = -ret; return NULL; } return ((type) ret); 7 | 8 | ssize_t read(int fd, char *buf, size_t count) { 9 | long ret = sys_read(fd, buf, count); 10 | WRAPPER_RETval(ssize_t); 11 | } 12 | 13 | ssize_t write(int fd, const void *buf, size_t count) { 14 | long ret = sys_write(fd, buf, count); 15 | WRAPPER_RETval(ssize_t); 16 | } 17 | 18 | /* open is implemented in assembly, because of variable length arguments */ 19 | 20 | int close(unsigned int fd) { 21 | long ret = sys_close(fd); 22 | WRAPPER_RETval(int); 23 | } 24 | 25 | void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) { 26 | long ret = sys_mmap(addr, len, prot, flags, fd, off); 27 | WRAPPER_RETptr(void *); 28 | } 29 | 30 | int mprotect(void *addr, size_t len, int prot) { 31 | long ret = sys_mprotect(addr, len, prot); 32 | WRAPPER_RETval(int); 33 | } 34 | 35 | int munmap(void *addr, size_t len) { 36 | long ret = sys_munmap(addr, len); 37 | WRAPPER_RETval(int); 38 | } 39 | 40 | int pipe(int *filedes) { 41 | long ret = sys_pipe(filedes); 42 | WRAPPER_RETval(int); 43 | } 44 | 45 | int dup(int filedes) { 46 | long ret = sys_dup(filedes); 47 | WRAPPER_RETval(int); 48 | } 49 | 50 | int dup2(int oldfd, int newfd) { 51 | long ret = sys_dup2(oldfd, newfd); 52 | WRAPPER_RETval(int); 53 | } 54 | 55 | int pause() { 56 | long ret = sys_pause(); 57 | WRAPPER_RETval(int); 58 | } 59 | 60 | int nanosleep(struct timespec *rqtp, struct timespec *rmtp) { 61 | long ret = nanosleep(rqtp, rmtp); 62 | WRAPPER_RETval(int); 63 | } 64 | 65 | pid_t fork(void) { 66 | long ret = sys_fork(); 67 | WRAPPER_RETval(pid_t); 68 | } 69 | 70 | void exit(int error_code) { 71 | sys_exit(error_code); 72 | /* never returns? */ 73 | } 74 | 75 | char * getcwd(char *buf, size_t size) { 76 | long ret = sys_getcwd(buf, size); 77 | WRAPPER_RETptr(char *); 78 | } 79 | 80 | int chdir(const char *pathname) { 81 | long ret = sys_chdir(pathname); 82 | WRAPPER_RETval(int); 83 | } 84 | 85 | int rename(const char *oldname, const char *newname) { 86 | long ret = sys_rename(oldname, newname); 87 | WRAPPER_RETval(int); 88 | } 89 | 90 | int mkdir(const char *pathname, int mode) { 91 | long ret = sys_mkdir(pathname, mode); 92 | WRAPPER_RETval(int); 93 | } 94 | 95 | int rmdir(const char *pathname) { 96 | long ret = sys_rmdir(pathname); 97 | WRAPPER_RETval(int); 98 | } 99 | 100 | int creat(const char *pathname, int mode) { 101 | long ret = sys_creat(pathname, mode); 102 | WRAPPER_RETval(int); 103 | } 104 | 105 | int link(const char *oldname, const char *newname) { 106 | long ret = sys_link(oldname, newname); 107 | WRAPPER_RETval(int); 108 | } 109 | 110 | int unlink(const char *pathname) { 111 | long ret = sys_unlink(pathname); 112 | WRAPPER_RETval(int); 113 | } 114 | 115 | ssize_t readlink(const char *path, char *buf, size_t bufsz) { 116 | long ret = sys_readlink(path, buf, bufsz); 117 | WRAPPER_RETval(ssize_t); 118 | } 119 | 120 | int chmod(const char *filename, mode_t mode) { 121 | long ret = sys_chmod(filename, mode); 122 | WRAPPER_RETval(int); 123 | } 124 | 125 | int chown(const char *filename, uid_t user, gid_t group) { 126 | long ret = sys_chown(filename, user, group); 127 | WRAPPER_RETval(int); 128 | } 129 | 130 | int umask(int mask) { 131 | long ret = sys_umask(mask); 132 | WRAPPER_RETval(int); 133 | } 134 | 135 | int gettimeofday(struct timeval *tv, struct timezone *tz) { 136 | long ret = sys_gettimeofday(tv, tz); 137 | WRAPPER_RETval(int); 138 | } 139 | 140 | uid_t getuid() { 141 | long ret = sys_getuid(); 142 | WRAPPER_RETval(uid_t); 143 | } 144 | 145 | gid_t getgid() { 146 | long ret = sys_getgid(); 147 | WRAPPER_RETval(uid_t); 148 | } 149 | 150 | int setuid(uid_t uid) { 151 | long ret = sys_setuid(uid); 152 | WRAPPER_RETval(int); 153 | } 154 | 155 | int setgid(gid_t gid) { 156 | long ret = sys_setgid(gid); 157 | WRAPPER_RETval(int); 158 | } 159 | 160 | uid_t geteuid() { 161 | long ret = sys_geteuid(); 162 | WRAPPER_RETval(uid_t); 163 | } 164 | 165 | gid_t getegid() { 166 | long ret = sys_getegid(); 167 | WRAPPER_RETval(uid_t); 168 | } 169 | 170 | unsigned int alarm(unsigned int seconds) { 171 | long ret = sys_alarm(seconds); 172 | WRAPPER_RETval(unsigned int); 173 | } 174 | 175 | int sigpending(sigset_t *set) { 176 | long ret = sys_rt_sigpending(set, NSIG / 8); 177 | WRAPPER_RETval(int); 178 | } 179 | 180 | int sigemptyset(sigset_t *set) { 181 | if (set == NULL) { 182 | set_errno(EINVAL); 183 | return -1; 184 | } 185 | memset(set, 0, sizeof(sigset_t)); 186 | return 0; 187 | } 188 | 189 | int sigfillset(sigset_t *set) { 190 | if (set == NULL) { 191 | set_errno(EINVAL); 192 | return -1; 193 | } 194 | memset(set, 0xff, sizeof(sigset_t)); 195 | return 0; 196 | } 197 | 198 | int sigaddset(sigset_t *set, int signo) { 199 | if (set == NULL || signo <= 0 || signo >= NSIG) { 200 | set_errno(EINVAL); 201 | return -1; 202 | } 203 | set->val[0] |= sigmask(signo); 204 | return 0; 205 | } 206 | 207 | int sigdelset(sigset_t *set, int signo) { 208 | if (set == NULL || signo <= 0 || signo >= NSIG) { 209 | set_errno(EINVAL); 210 | return -1; 211 | } 212 | set->val[0] &= ~sigmask(signo); 213 | return 0; 214 | } 215 | 216 | int sigismember(const sigset_t *set, int signo) { 217 | if (set == NULL || signo <= 0 || signo >= NSIG) { 218 | set_errno(EINVAL); 219 | return -1; 220 | } 221 | return (set->val[0] & sigmask(signo)) != 0; 222 | } 223 | 224 | int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { 225 | long ret = sys_rt_sigprocmask(how, set, oldset, NSIG / 8); 226 | WRAPPER_RETval(int); 227 | } 228 | 229 | sighandler_t signal(int sig, sighandler_t handler) { 230 | struct sigaction act, oact; 231 | if (handler == SIG_ERR || sig <= 0 || sig >= NSIG) { 232 | set_errno(EINVAL); 233 | return SIG_ERR; 234 | } 235 | act.sa_handler = handler; 236 | sigemptyset(&act.sa_mask); 237 | sigaddset(&act.sa_mask, sig); 238 | act.sa_flags = SA_RESTART; 239 | if (sigaction(sig, &act, &oact) < 0) 240 | return SIG_ERR; 241 | return oact.sa_handler; 242 | } 243 | 244 | int sigaction(int sig, struct sigaction *act, struct sigaction *oact) { 245 | act->sa_flags |= SA_RESTORER; 246 | act->sa_restorer = myrt; 247 | long ret = sys_rt_sigaction(sig, act, oact, NSIG / 8); 248 | WRAPPER_RETval(int); 249 | } 250 | 251 | void bzero(void *s, size_t size) { 252 | char *ptr = (char *) s; 253 | while(size-- > 0) *ptr++ = '\0'; 254 | } 255 | 256 | void *memset(void *s, int val, size_t size) { 257 | char *ptr = (char *) s; 258 | while(size-- > 0) *ptr++ = val; 259 | return s; 260 | } 261 | 262 | size_t strlen(const char *s) { 263 | size_t count = 0; 264 | while(*s++) count++; 265 | return count; 266 | } 267 | 268 | #define PERRMSG_MIN 0 269 | #define PERRMSG_MAX 34 270 | 271 | static const char *errmsg[] = { 272 | "Success", 273 | "Operation not permitted", 274 | "No such file or directory", 275 | "No such process", 276 | "Interrupted system call", 277 | "I/O error", 278 | "No such device or address", 279 | "Argument list too long", 280 | "Exec format error", 281 | "Bad file number", 282 | "No child processes", 283 | "Try again", 284 | "Out of memory", 285 | "Permission denied", 286 | "Bad address", 287 | "Block device required", 288 | "Device or resource busy", 289 | "File exists", 290 | "Cross-device link", 291 | "No such device", 292 | "Not a directory", 293 | "Is a directory", 294 | "Invalid argument", 295 | "File table overflow", 296 | "Too many open files", 297 | "Not a typewriter", 298 | "Text file busy", 299 | "File too large", 300 | "No space left on device", 301 | "Illegal seek", 302 | "Read-only file system", 303 | "Too many links", 304 | "Broken pipe", 305 | "Math argument out of domain of func", 306 | "Math result not representable" 307 | }; 308 | 309 | void perror(const char *prefix) { 310 | const char *unknown = "Unknown"; 311 | long backup = errno; 312 | if(prefix) { 313 | write(2, prefix, strlen(prefix)); 314 | write(2, ": ", 2); 315 | } 316 | if(errno < PERRMSG_MIN || errno > PERRMSG_MAX) write(2, unknown, strlen(unknown)); 317 | else write(2, errmsg[backup], strlen(errmsg[backup])); 318 | write(2, "\n", 1); 319 | return; 320 | } 321 | 322 | #if 0 /* we have an equivalent implementation in assembly */ 323 | unsigned int sleep(unsigned int seconds) { 324 | long ret; 325 | struct timespec req, rem; 326 | req.tv_sec = seconds; 327 | req.tv_nsec = 0; 328 | ret = sys_nanosleep(&req, &rem); 329 | if(ret >= 0) return ret; 330 | if(ret == -EINTR) { 331 | return rem.tv_sec; 332 | } 333 | return 0; 334 | } 335 | #endif 336 | -------------------------------------------------------------------------------- /hw3/libmini.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBMINI_H__ 2 | #define __LIBMINI_H__ /* avoid reentrant */ 3 | 4 | typedef long long size_t; 5 | typedef long long ssize_t; 6 | typedef long long off_t; 7 | typedef int mode_t; 8 | typedef int uid_t; 9 | typedef int gid_t; 10 | typedef int pid_t; 11 | 12 | extern long errno; 13 | 14 | #define NULL ((void*) 0) 15 | 16 | /* from /usr/include/asm-generic/fcntl.h */ 17 | #define O_ACCMODE 00000003 18 | #define O_RDONLY 00000000 19 | #define O_WRONLY 00000001 20 | #define O_RDWR 00000002 21 | #ifndef O_CREAT 22 | #define O_CREAT 00000100 /* not fcntl */ 23 | #endif 24 | #ifndef O_EXCL 25 | #define O_EXCL 00000200 /* not fcntl */ 26 | #endif 27 | #ifndef O_NOCTTY 28 | #define O_NOCTTY 00000400 /* not fcntl */ 29 | #endif 30 | #ifndef O_TRUNC 31 | #define O_TRUNC 00001000 /* not fcntl */ 32 | #endif 33 | #ifndef O_APPEND 34 | #define O_APPEND 00002000 35 | #endif 36 | #ifndef O_NONBLOCK 37 | #define O_NONBLOCK 00004000 38 | #endif 39 | #ifndef O_DSYNC 40 | #define O_DSYNC 00010000 /* used to be O_SYNC, see below */ 41 | #endif 42 | #ifndef FASYNC 43 | #define FASYNC 00020000 /* fcntl, for BSD compatibility */ 44 | #endif 45 | #ifndef O_DIRECT 46 | #define O_DIRECT 00040000 /* direct disk access hint */ 47 | #endif 48 | #ifndef O_LARGEFILE 49 | #define O_LARGEFILE 00100000 50 | #endif 51 | #ifndef O_DIRECTORY 52 | #define O_DIRECTORY 00200000 /* must be a directory */ 53 | #endif 54 | #ifndef O_NOFOLLOW 55 | #define O_NOFOLLOW 00400000 /* don't follow links */ 56 | #endif 57 | #ifndef O_NOATIME 58 | #define O_NOATIME 01000000 59 | #endif 60 | #ifndef O_CLOEXEC 61 | #define O_CLOEXEC 02000000 /* set close_on_exec */ 62 | #endif 63 | 64 | #define set_errno(val) (errno = (val)) 65 | 66 | /* from /usr/include/asm-generic/errno-base.h */ 67 | #define EPERM 1 /* Operation not permitted */ 68 | #define ENOENT 2 /* No such file or directory */ 69 | #define ESRCH 3 /* No such process */ 70 | #define EINTR 4 /* Interrupted system call */ 71 | #define EIO 5 /* I/O error */ 72 | #define ENXIO 6 /* No such device or address */ 73 | #define E2BIG 7 /* Argument list too long */ 74 | #define ENOEXEC 8 /* Exec format error */ 75 | #define EBADF 9 /* Bad file number */ 76 | #define ECHILD 10 /* No child processes */ 77 | #define EAGAIN 11 /* Try again */ 78 | #define ENOMEM 12 /* Out of memory */ 79 | #define EACCES 13 /* Permission denied */ 80 | #define EFAULT 14 /* Bad address */ 81 | #define ENOTBLK 15 /* Block device required */ 82 | #define EBUSY 16 /* Device or resource busy */ 83 | #define EEXIST 17 /* File exists */ 84 | #define EXDEV 18 /* Cross-device link */ 85 | #define ENODEV 19 /* No such device */ 86 | #define ENOTDIR 20 /* Not a directory */ 87 | #define EISDIR 21 /* Is a directory */ 88 | #define EINVAL 22 /* Invalid argument */ 89 | #define ENFILE 23 /* File table overflow */ 90 | #define EMFILE 24 /* Too many open files */ 91 | #define ENOTTY 25 /* Not a typewriter */ 92 | #define ETXTBSY 26 /* Text file busy */ 93 | #define EFBIG 27 /* File too large */ 94 | #define ENOSPC 28 /* No space left on device */ 95 | #define ESPIPE 29 /* Illegal seek */ 96 | #define EROFS 30 /* Read-only file system */ 97 | #define EMLINK 31 /* Too many links */ 98 | #define EPIPE 32 /* Broken pipe */ 99 | #define EDOM 33 /* Math argument out of domain of func */ 100 | #define ERANGE 34 /* Math result not representable */ 101 | 102 | /* from /usr/include/x86_64-linux-gnu/asm/signal.h */ 103 | #define SIGHUP 1 104 | #define SIGINT 2 105 | #define SIGQUIT 3 106 | #define SIGILL 4 107 | #define SIGTRAP 5 108 | #define SIGABRT 6 109 | #define SIGIOT 6 110 | #define SIGBUS 7 111 | #define SIGFPE 8 112 | #define SIGKILL 9 113 | #define SIGUSR1 10 114 | #define SIGSEGV 11 115 | #define SIGUSR2 12 116 | #define SIGPIPE 13 117 | #define SIGALRM 14 118 | #define SIGTERM 15 119 | #define SIGSTKFLT 16 120 | #define SIGCHLD 17 121 | #define SIGCONT 18 122 | #define SIGSTOP 19 123 | #define SIGTSTP 20 124 | #define SIGTTIN 21 125 | #define SIGTTOU 22 126 | #define SIGURG 23 127 | #define SIGXCPU 24 128 | #define SIGXFSZ 25 129 | #define SIGVTALRM 26 130 | #define SIGPROF 27 131 | #define SIGWINCH 28 132 | #define SIGIO 29 133 | #define SIGPOLL SIGIO 134 | 135 | #define NSIG (64 + 1) 136 | 137 | #define SIG_ERR ((sighandler_t) -1) /* Error return. */ 138 | #define SIG_DFL ((sighandler_t) 0) /* Default action. */ 139 | #define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */ 140 | 141 | #define sigmask(sig) \ 142 | (((unsigned long int) 1) << (((sig) - 1))) 143 | 144 | #define SA_RESTORER 0x04000000 145 | 146 | /* from /usr/include/x86_64-linux-gnu/bits/sigaction.h */ 147 | #define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ 148 | #define SA_NOCLDWAIT 2 /* Don't create zombie on child death. */ 149 | #define SA_SIGINFO 4 /* Invoke signal-catching function with 150 | three arguments instead of one. */ 151 | # define SA_ONSTACK 0x08000000 /* Use signal stack by using `sa_restorer'. */ 152 | # define SA_RESTART 0x10000000 /* Restart syscall on signal return. */ 153 | # define SA_INTERRUPT 0x20000000 /* Historical no-op. */ 154 | # define SA_NODEFER 0x40000000 /* Don't automatically block the signal when 155 | its handler is being executed. */ 156 | # define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler. */ 157 | 158 | #define SIG_BLOCK 0 /* Block signals. */ 159 | #define SIG_UNBLOCK 1 /* Unblock signals. */ 160 | #define SIG_SETMASK 2 /* Set the set of blocked signals. */ 161 | 162 | struct timespec { 163 | long tv_sec; /* seconds */ 164 | long tv_nsec; /* nanoseconds */ 165 | }; 166 | 167 | struct timeval { 168 | long tv_sec; /* seconds */ 169 | long tv_usec; /* microseconds */ 170 | }; 171 | 172 | struct timezone { 173 | int tz_minuteswest; /* minutes west of Greenwich */ 174 | int tz_dsttime; /* type of DST correction */ 175 | }; 176 | 177 | typedef struct { 178 | unsigned long int val[1]; 179 | } sigset_t; 180 | 181 | typedef void (*sighandler_t) (int); 182 | typedef void (*sigrestore_t) (void); 183 | 184 | typedef struct jmp_buf_s { 185 | long long reg[8]; 186 | sigset_t mask; 187 | } jmp_buf[1]; 188 | 189 | struct sigaction { 190 | sighandler_t sa_handler; 191 | unsigned int sa_flags; 192 | sigrestore_t sa_restorer; 193 | sigset_t sa_mask; 194 | }; 195 | 196 | /* system calls */ 197 | long sys_read(int fd, char *buf, size_t count); 198 | long sys_write(int fd, const void *buf, size_t count); 199 | long sys_open(const char *filename, int flags, ... /*mode*/); 200 | long sys_close(unsigned int fd); 201 | long sys_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off); 202 | long sys_mprotect(void *addr, size_t len, int prot); 203 | long sys_munmap(void *addr, size_t len); 204 | long sys_pipe(int *filedes); 205 | long sys_dup(int filedes); 206 | long sys_dup2(int oldfd, int newfd); 207 | long sys_pause(); 208 | long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); 209 | long sys_fork(void); 210 | long sys_exit(int error_code) __attribute__ ((noreturn)); 211 | long sys_getcwd(char *buf, size_t size); 212 | long sys_chdir(const char *pathname); 213 | long sys_rename(const char *oldname, const char *newname); 214 | long sys_mkdir(const char *pathname, int mode); 215 | long sys_rmdir(const char *pathname); 216 | long sys_creat(const char *pathname, int mode); 217 | long sys_link(const char *oldname, const char *newname); 218 | long sys_unlink(const char *pathname); 219 | long sys_readlink(const char *path, char *buf, size_t bufsz); 220 | long sys_chmod(const char *filename, mode_t mode); 221 | long sys_chown(const char *filename, uid_t user, gid_t group); 222 | long sys_umask(int mask); 223 | long sys_gettimeofday(struct timeval *tv, struct timezone *tz); 224 | long sys_getuid(); 225 | long sys_getgid(); 226 | long sys_setuid(uid_t uid); 227 | long sys_setgid(gid_t gid); 228 | long sys_geteuid(); 229 | long sys_getegid(); 230 | 231 | long sys_alarm(unsigned int seconds); 232 | long sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize); 233 | long sys_rt_sigprocmask(int how, const sigset_t *set, sigset_t *oldset, size_t sigsetsize); 234 | long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); 235 | 236 | void myrt(); 237 | 238 | /* wrappers */ 239 | ssize_t read(int fd, char *buf, size_t count); 240 | ssize_t write(int fd, const void *buf, size_t count); 241 | int open(const char *filename, int flags, ... /*mode*/); 242 | int close(unsigned int fd); 243 | void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off); 244 | int mprotect(void *addr, size_t len, int prot); 245 | int munmap(void *addr, size_t len); 246 | int pipe(int *filedes); 247 | int dup(int filedes); 248 | int dup2(int oldfd, int newfd); 249 | int pause(); 250 | int nanosleep(struct timespec *rqtp, struct timespec *rmtp); 251 | pid_t fork(void); 252 | void exit(int error_code); 253 | char * getcwd(char *buf, size_t size); 254 | int chdir(const char *pathname); 255 | int rename(const char *oldname, const char *newname); 256 | int mkdir(const char *pathname, int mode); 257 | int rmdir(const char *pathname); 258 | int creat(const char *pathname, int mode); 259 | int link(const char *oldname, const char *newname); 260 | int unlink(const char *pathname); 261 | ssize_t readlink(const char *path, char *buf, size_t bufsz); 262 | int chmod(const char *filename, mode_t mode); 263 | int chown(const char *filename, uid_t user, gid_t group); 264 | int umask(int mask); 265 | int gettimeofday(struct timeval *tv, struct timezone *tz); 266 | uid_t getuid(); 267 | gid_t getgid(); 268 | int setuid(uid_t uid); 269 | int setgid(gid_t gid); 270 | uid_t geteuid(); 271 | gid_t getegid(); 272 | 273 | int setjmp(jmp_buf env); 274 | void longjmp(jmp_buf env, int val); 275 | sighandler_t signal(int sig, sighandler_t handler); 276 | int sigaction(int signum, struct sigaction *act, struct sigaction *oldact); 277 | int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 278 | int sigpending(sigset_t *set); 279 | unsigned int alarm(unsigned int seconds); 280 | int sigemptyset(sigset_t *set); 281 | int sigfillset(sigset_t *set); 282 | int sigaddset(sigset_t *set, int signo); 283 | int sigdelset(sigset_t *set, int signo); 284 | int sigismember(const sigset_t *set, int signo); 285 | 286 | void bzero(void *s, size_t size); 287 | void *memset(void *s, int val, size_t size); 288 | size_t strlen(const char *s); 289 | void perror(const char *prefix); 290 | unsigned int sleep(unsigned int s); 291 | 292 | #endif /* __LIBMINI_H__ */ 293 | -------------------------------------------------------------------------------- /hw3/libmini64.asm: -------------------------------------------------------------------------------- 1 | 2 | %macro gensys 2 3 | global sys_%2:function 4 | sys_%2: 5 | push r10 6 | mov r10, rcx 7 | mov rax, %1 8 | syscall 9 | pop r10 10 | ret 11 | %endmacro 12 | 13 | ; RDI, RSI, RDX, RCX, R8, R9 14 | 15 | extern errno 16 | 17 | section .data 18 | 19 | section .text 20 | gensys 0, read 21 | gensys 1, write 22 | gensys 2, open 23 | gensys 3, close 24 | gensys 9, mmap 25 | gensys 10, mprotect 26 | gensys 11, munmap 27 | gensys 22, pipe 28 | gensys 32, dup 29 | gensys 33, dup2 30 | gensys 34, pause 31 | gensys 35, nanosleep 32 | gensys 57, fork 33 | gensys 60, exit 34 | gensys 79, getcwd 35 | gensys 80, chdir 36 | gensys 82, rename 37 | gensys 83, mkdir 38 | gensys 84, rmdir 39 | gensys 85, creat 40 | gensys 86, link 41 | gensys 88, unlink 42 | gensys 89, readlink 43 | gensys 90, chmod 44 | gensys 92, chown 45 | gensys 95, umask 46 | gensys 96, gettimeofday 47 | gensys 102, getuid 48 | gensys 104, getgid 49 | gensys 105, setuid 50 | gensys 106, setgid 51 | gensys 107, geteuid 52 | gensys 108, getegid 53 | 54 | gensys 13, rt_sigaction 55 | gensys 14, rt_sigprocmask 56 | gensys 37, alarm 57 | gensys 127, rt_sigpending 58 | 59 | global setjmp:function 60 | setjmp: 61 | mov [rdi + 0 * 8], rbx 62 | mov [rdi + 1 * 8], rsp 63 | mov [rdi + 2 * 8], rbp 64 | mov [rdi + 3 * 8], r12 65 | mov [rdi + 4 * 8], r13 66 | mov [rdi + 5 * 8], r14 67 | mov [rdi + 6 * 8], r15 68 | push qword [rsp] 69 | pop qword [rdi + 7 * 8] 70 | push r8 71 | push rdi 72 | push rsi 73 | push rdx 74 | push rcx 75 | sub rsp, 8 76 | mov rdi, 0 77 | mov rsi, 0 78 | mov rdx, rsp 79 | mov rcx, 8 80 | call sys_rt_sigprocmask 81 | pop r8 82 | pop rcx 83 | pop rdx 84 | pop rsi 85 | pop rdi 86 | mov [rdi + 8 * 8], r8 87 | pop r8 88 | mov rax, 0 89 | ret 90 | 91 | global longjmp:function 92 | longjmp: 93 | mov rbx, [rdi + 0 * 8] 94 | mov rsp, [rdi + 1 * 8] 95 | mov rbp, [rdi + 2 * 8] 96 | mov r12, [rdi + 3 * 8] 97 | mov r13, [rdi + 4 * 8] 98 | mov r14, [rdi + 5 * 8] 99 | mov r15, [rdi + 6 * 8] 100 | push rdi 101 | push rsi 102 | push rdx 103 | push rcx 104 | add rdi, 8 * 8 105 | mov rsi, rdi 106 | mov rdi, 2 107 | mov rdx, 0 108 | mov rcx, 8 109 | call sys_rt_sigprocmask 110 | pop rcx 111 | pop rdx 112 | pop rsi 113 | pop rdi 114 | push qword [rdi + 7 * 8] 115 | mov rax, rsi 116 | cmp rax, 0 117 | jne longret 118 | inc rax 119 | longret: 120 | ret 121 | 122 | global myrt:function 123 | myrt: 124 | mov rax, 15 125 | syscall 126 | ret 127 | 128 | global open:function 129 | open: 130 | call sys_open 131 | cmp rax, 0 132 | jge open_success ; no error :) 133 | open_error: 134 | neg rax 135 | %ifdef NASM 136 | mov rdi, [rel errno wrt ..gotpc] 137 | %else 138 | mov rdi, [rel errno wrt ..gotpcrel] 139 | %endif 140 | mov [rdi], rax ; errno = -rax 141 | mov rax, -1 142 | jmp open_quit 143 | open_success: 144 | %ifdef NASM 145 | mov rdi, [rel errno wrt ..gotpc] 146 | %else 147 | mov rdi, [rel errno wrt ..gotpcrel] 148 | %endif 149 | mov QWORD [rdi], 0 ; errno = 0 150 | open_quit: 151 | ret 152 | 153 | global sleep:function 154 | sleep: 155 | sub rsp, 32 ; allocate timespec * 2 156 | mov [rsp], rdi ; req.tv_sec 157 | mov QWORD [rsp+8], 0 ; req.tv_nsec 158 | mov rdi, rsp ; rdi = req @ rsp 159 | lea rsi, [rsp+16] ; rsi = rem @ rsp+16 160 | call sys_nanosleep 161 | cmp rax, 0 162 | jge sleep_quit ; no error :) 163 | sleep_error: 164 | neg rax 165 | cmp rax, 4 ; rax == EINTR? 166 | jne sleep_failed 167 | sleep_interrupted: 168 | lea rsi, [rsp+16] 169 | mov rax, [rsi] ; return rem.tv_sec 170 | jmp sleep_quit 171 | sleep_failed: 172 | mov rax, 0 ; return 0 on error 173 | sleep_quit: 174 | add rsp, 32 175 | ret 176 | 177 | -------------------------------------------------------------------------------- /hw3/start.asm: -------------------------------------------------------------------------------- 1 | extern main 2 | extern exit 3 | 4 | section .text 5 | global _start 6 | _start: 7 | mov rdi, [rsp] ; argc 8 | lea rsi, [rsp+8] ; argv 9 | call main 10 | mov rdi, rax ; exit code 11 | call exit 12 | ret 13 | -------------------------------------------------------------------------------- /hw3/test.c: -------------------------------------------------------------------------------- 1 | alarm1.c -------------------------------------------------------------------------------- /hw3/testlib/alarm1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | alarm(3); 5 | pause(); 6 | return 0; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /hw3/testlib/alarm2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | sigset_t s; 7 | sigemptyset(&s); 8 | sigaddset(&s, SIGALRM); 9 | sigprocmask(SIG_BLOCK, &s, NULL); 10 | alarm(3); 11 | sleep(5); 12 | if(sigpending(&s) < 0) perror("sigpending"); 13 | if(sigismember(&s, SIGALRM)) { 14 | char m[] = "sigalrm is pending.\n"; 15 | write(1, m, sizeof(m)); 16 | } else { 17 | char m[] = "sigalrm is not pending.\n"; 18 | write(1, m, sizeof(m)); 19 | } 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /hw3/testlib/alarm3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void handler(int s) { /* do nothing */ } 6 | 7 | int main() { 8 | sigset_t s; 9 | printf("%ld\n", sizeof(s)); 10 | sigemptyset(&s); 11 | sigaddset(&s, SIGALRM); 12 | sigprocmask(SIG_BLOCK, &s, NULL); 13 | signal(SIGALRM, SIG_IGN); 14 | signal(SIGINT, handler); 15 | alarm(1); 16 | pause(); 17 | if(sigpending(&s) < 0) perror("sigpending"); 18 | if(sigismember(&s, SIGALRM)) { 19 | char m[] = "sigalrm is pending.\n"; 20 | write(1, m, sizeof(m)); 21 | } else { 22 | char m[] = "sigalrm is not pending.\n"; 23 | write(1, m, sizeof(m)); 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /hw3/testlib/jmp1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef void (*proc_t)(); 7 | static jmp_buf jb; 8 | 9 | #define FUNBODY(m, from) { write(1, m, strlen(m)); longjmp(jb, from); } 10 | 11 | void a() FUNBODY("This is function a().\n", 0); 12 | void b() FUNBODY("This is function b().\n", 2); 13 | void c() FUNBODY("This is function c().\n", 3); 14 | void d() FUNBODY("This is function d().\n", 4); 15 | void e() FUNBODY("This is function e().\n", 5); 16 | void f() FUNBODY("This is function f().\n", 6); 17 | void g() FUNBODY("This is function g().\n", 7); 18 | void h() FUNBODY("This is function h().\n", 8); 19 | void i() FUNBODY("This is function i().\n", 9); 20 | void j() FUNBODY("This is function j().\n", 10); 21 | 22 | proc_t funs[] = { a, b, c, d, e, f, g, h, i, j }; 23 | 24 | int main() { 25 | volatile int i = 0; 26 | if(setjmp(jb) != 0) { 27 | i++; 28 | } 29 | if(i < 10) funs[i](); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /hw3/testmini.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | int main() { 4 | char s[] = "sleeping for 5s ...\n"; 5 | char m[] = "hello, world!\n"; 6 | write(1, s, sizeof(s)); 7 | sleep(5); 8 | write(1, m, sizeof(m)); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /hw3/tmp/libmini.c: -------------------------------------------------------------------------------- 1 | #include "libmini.h" 2 | 3 | long errno; 4 | 5 | #define WRAPPER_RETval(type) errno = 0; if(ret < 0) { errno = -ret; return -1; } return ((type) ret); 6 | #define WRAPPER_RETptr(type) errno = 0; if(ret < 0) { errno = -ret; return NULL; } return ((type) ret); 7 | 8 | #define __set_errno(val) (errno = (val)) 9 | 10 | ssize_t read(int fd, char *buf, size_t count) { 11 | long ret = sys_read(fd, buf, count); 12 | WRAPPER_RETval(ssize_t); 13 | } 14 | 15 | ssize_t write(int fd, const void *buf, size_t count) { 16 | long ret = sys_write(fd, buf, count); 17 | WRAPPER_RETval(ssize_t); 18 | } 19 | 20 | /* open is implemented in assembly, because of variable length arguments */ 21 | 22 | int close(unsigned int fd) { 23 | long ret = sys_close(fd); 24 | WRAPPER_RETval(int); 25 | } 26 | 27 | void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) { 28 | long ret = sys_mmap(addr, len, prot, flags, fd, off); 29 | WRAPPER_RETptr(void *); 30 | } 31 | 32 | int mprotect(void *addr, size_t len, int prot) { 33 | long ret = sys_mprotect(addr, len, prot); 34 | WRAPPER_RETval(int); 35 | } 36 | 37 | int munmap(void *addr, size_t len) { 38 | long ret = sys_munmap(addr, len); 39 | WRAPPER_RETval(int); 40 | } 41 | 42 | int pipe(int *filedes) { 43 | long ret = sys_pipe(filedes); 44 | WRAPPER_RETval(int); 45 | } 46 | 47 | int dup(int filedes) { 48 | long ret = sys_dup(filedes); 49 | WRAPPER_RETval(int); 50 | } 51 | 52 | int dup2(int oldfd, int newfd) { 53 | long ret = sys_dup2(oldfd, newfd); 54 | WRAPPER_RETval(int); 55 | } 56 | 57 | int pause() { 58 | long ret = sys_pause(); 59 | WRAPPER_RETval(int); 60 | } 61 | 62 | int nanosleep(struct timespec *rqtp, struct timespec *rmtp) { 63 | long ret = nanosleep(rqtp, rmtp); 64 | WRAPPER_RETval(int); 65 | } 66 | 67 | pid_t fork(void) { 68 | long ret = sys_fork(); 69 | WRAPPER_RETval(pid_t); 70 | } 71 | 72 | void exit(int error_code) { 73 | sys_exit(error_code); 74 | /* never returns? */ 75 | } 76 | 77 | char * getcwd(char *buf, size_t size) { 78 | long ret = sys_getcwd(buf, size); 79 | WRAPPER_RETptr(char *); 80 | } 81 | 82 | int chdir(const char *pathname) { 83 | long ret = sys_chdir(pathname); 84 | WRAPPER_RETval(int); 85 | } 86 | 87 | int rename(const char *oldname, const char *newname) { 88 | long ret = sys_rename(oldname, newname); 89 | WRAPPER_RETval(int); 90 | } 91 | 92 | int mkdir(const char *pathname, int mode) { 93 | long ret = sys_mkdir(pathname, mode); 94 | WRAPPER_RETval(int); 95 | } 96 | 97 | int rmdir(const char *pathname) { 98 | long ret = sys_rmdir(pathname); 99 | WRAPPER_RETval(int); 100 | } 101 | 102 | int creat(const char *pathname, int mode) { 103 | long ret = sys_creat(pathname, mode); 104 | WRAPPER_RETval(int); 105 | } 106 | 107 | int link(const char *oldname, const char *newname) { 108 | long ret = sys_link(oldname, newname); 109 | WRAPPER_RETval(int); 110 | } 111 | 112 | int unlink(const char *pathname) { 113 | long ret = sys_unlink(pathname); 114 | WRAPPER_RETval(int); 115 | } 116 | 117 | ssize_t readlink(const char *path, char *buf, size_t bufsz) { 118 | long ret = sys_readlink(path, buf, bufsz); 119 | WRAPPER_RETval(ssize_t); 120 | } 121 | 122 | int chmod(const char *filename, mode_t mode) { 123 | long ret = sys_chmod(filename, mode); 124 | WRAPPER_RETval(int); 125 | } 126 | 127 | int chown(const char *filename, uid_t user, gid_t group) { 128 | long ret = sys_chown(filename, user, group); 129 | WRAPPER_RETval(int); 130 | } 131 | 132 | int umask(int mask) { 133 | long ret = sys_umask(mask); 134 | WRAPPER_RETval(int); 135 | } 136 | 137 | int gettimeofday(struct timeval *tv, struct timezone *tz) { 138 | long ret = sys_gettimeofday(tv, tz); 139 | WRAPPER_RETval(int); 140 | } 141 | 142 | uid_t getuid() { 143 | long ret = sys_getuid(); 144 | WRAPPER_RETval(uid_t); 145 | } 146 | 147 | gid_t getgid() { 148 | long ret = sys_getgid(); 149 | WRAPPER_RETval(uid_t); 150 | } 151 | 152 | int setuid(uid_t uid) { 153 | long ret = sys_setuid(uid); 154 | WRAPPER_RETval(int); 155 | } 156 | 157 | int setgid(gid_t gid) { 158 | long ret = sys_setgid(gid); 159 | WRAPPER_RETval(int); 160 | } 161 | 162 | uid_t geteuid() { 163 | long ret = sys_geteuid(); 164 | WRAPPER_RETval(uid_t); 165 | } 166 | 167 | gid_t getegid() { 168 | long ret = sys_getegid(); 169 | WRAPPER_RETval(uid_t); 170 | } 171 | 172 | void bzero(void *s, size_t size) { 173 | char *ptr = (char *) s; 174 | while(size-- > 0) *ptr++ = '\0'; 175 | } 176 | 177 | size_t strlen(const char *s) { 178 | size_t count = 0; 179 | while(*s++) count++; 180 | return count; 181 | } 182 | 183 | unsigned int alarm(unsigned int seconds) { 184 | long ret = sys_alarm(seconds); 185 | WRAPPER_RETval(unsigned int); 186 | } 187 | 188 | /* Return is sig is used internally. */ 189 | static inline int __is_internal_signal (int sig) { 190 | return (sig == SIGCANCEL) || (sig == SIGSETXID); 191 | } 192 | 193 | int sigprocmask(int how, const sigset_t *set, sigset_t *oset) { 194 | switch (how) { 195 | case SIG_BLOCK: 196 | case SIG_UNBLOCK: 197 | case SIG_SETMASK: 198 | break; 199 | default: 200 | __set_errno (EINVAL); 201 | return -1; 202 | } 203 | __set_errno (ENOSYS); 204 | return -1; 205 | } 206 | 207 | int sigpending(sigset_t *set) { 208 | if (set == NULL) { 209 | __set_errno (EINVAL); 210 | return -1; 211 | } 212 | __set_errno (ENOSYS); 213 | return -1; 214 | } 215 | 216 | sighandler_t signal(int sig, sighandler_t handler) { 217 | __set_errno (ENOSYS); 218 | return SIG_ERR; 219 | } 220 | 221 | int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { 222 | if (sig <= 0 || sig >= NSIG || __is_internal_signal(sig)) { 223 | __set_errno (EINVAL); 224 | return -1; 225 | } 226 | __set_errno (ENOSYS); 227 | return -1; 228 | } 229 | 230 | int sigemptyset(sigset_t *set) { 231 | if (set == NULL) { 232 | __set_errno (EINVAL); 233 | return -1; 234 | } 235 | bzero(set, sizeof (sigset_t)); 236 | return 0; 237 | } 238 | 239 | #define PERRMSG_MIN 0 240 | #define PERRMSG_MAX 133 241 | 242 | static const char *errmsg[] = { 243 | "Success", 244 | "Operation not permitted", 245 | "No such file or directory", 246 | "No such process", 247 | "Interrupted system call", 248 | "I/O error", 249 | "No such device or address", 250 | "Argument list too long", 251 | "Exec format error", 252 | "Bad file number", 253 | "No child processes", 254 | "Try again", 255 | "Out of memory", 256 | "Permission denied", 257 | "Bad address", 258 | "Block device required", 259 | "Device or resource busy", 260 | "File exists", 261 | "Cross-device link", 262 | "No such device", 263 | "Not a directory", 264 | "Is a directory", 265 | "Invalid argument", 266 | "File table overflow", 267 | "Too many open files", 268 | "Not a typewriter", 269 | "Text file busy", 270 | "File too large", 271 | "No space left on device", 272 | "Illegal seek", 273 | "Read-only file system", 274 | "Too many links", 275 | "Broken pipe", 276 | "Math argument out of domain of func", 277 | "Math result not representable", 278 | "Resource deadlock would occur", 279 | "File name too long", 280 | "No record locks available", 281 | "Invalid system call number", 282 | "Directory not empty", 283 | "Too many symbolic links encountered", 284 | "Operation would block", 285 | "No message of desired type", 286 | "Identifier removed", 287 | "Channel number out of range", 288 | "Level 2 not synchronized", 289 | "Level 3 halted", 290 | "Level 3 reset", 291 | "Link number out of range", 292 | "Protocol driver not attached", 293 | "No CSI structure available", 294 | "Level 2 halted", 295 | "Invalid exchange", 296 | "Invalid request descriptor", 297 | "Exchange full", 298 | "No anode", 299 | "Invalid request code", 300 | "Invalid slot", 301 | "Resource deadlock would occur", 302 | "Bad font file format", 303 | "Device not a stream", 304 | "No data available", 305 | "Timer expired", 306 | "Out of streams resources", 307 | "Machine is not on the network", 308 | "Package not installed", 309 | "Object is remote", 310 | "Link has been severed", 311 | "Advertise error", 312 | "Srmount error", 313 | "Communication error on send", 314 | "Protocol error", 315 | "Multihop attempted", 316 | "RFS specific error", 317 | "Not a data message", 318 | "Value too large for defined data type", 319 | "Name not unique on network", 320 | "File descriptor in bad state", 321 | "Remote address changed", 322 | "Can not access a needed shared library", 323 | "Accessing a corrupted shared library", 324 | ".lib section in a.out corrupted", 325 | "Attempting to link in too many shared libraries", 326 | "Cannot exec a shared library directly", 327 | "Illegal byte sequence", 328 | "Interrupted system call should be restarted", 329 | "Streams pipe error", 330 | "Too many users", 331 | "Socket operation on non-socket", 332 | "Destination address required", 333 | "Message too long", 334 | "Protocol wrong type for socket", 335 | "Protocol not available", 336 | "Protocol not supported", 337 | "Socket type not supported", 338 | "Operation not supported on transport endpoint", 339 | "Protocol family not supported", 340 | "Address family not supported by protocol", 341 | "Address already in use", 342 | "Cannot assign requested address", 343 | "Network is down", 344 | "Network is unreachable", 345 | "Network dropped connection because of reset", 346 | "Software caused connection abort", 347 | "Connection reset by peer", 348 | "No buffer space available", 349 | "Transport endpoint is already connected", 350 | "Transport endpoint is not connected", 351 | "Cannot send after transport endpoint shutdown", 352 | "Too many references: cannot splice", 353 | "Connection timed out", 354 | "Connection refused", 355 | "Host is down", 356 | "No route to host", 357 | "Operation already in progress", 358 | "Operation now in progress", 359 | "Stale file handle", 360 | "Structure needs cleaning", 361 | "Not a XENIX named type file", 362 | "No XENIX semaphores available", 363 | "Is a named type file", 364 | "Remote I/O error", 365 | "Quota exceeded", 366 | "No medium found", 367 | "Wrong medium type", 368 | "Operation Canceled", 369 | "Required key not available", 370 | "Key has expired", 371 | "Key has been revoked", 372 | "Key was rejected by service", 373 | "Owner died", 374 | "State not recoverable", 375 | "Operation not possible due to RF-kill", 376 | "Memory page has hardware error", 377 | }; 378 | 379 | void perror(const char *prefix) { 380 | const char *unknown = "Unknown"; 381 | long backup = errno; 382 | if(prefix) { 383 | write(2, prefix, strlen(prefix)); 384 | write(2, ": ", 2); 385 | } 386 | if(errno < PERRMSG_MIN || errno > PERRMSG_MAX) write(2, unknown, strlen(unknown)); 387 | else write(2, errmsg[backup], strlen(errmsg[backup])); 388 | write(2, "\n", 1); 389 | return; 390 | } 391 | 392 | #if 0 /* we have an equivalent implementation in assembly */ 393 | unsigned int sleep(unsigned int seconds) { 394 | long ret; 395 | struct timespec req, rem; 396 | req.tv_sec = seconds; 397 | req.tv_nsec = 0; 398 | ret = sys_nanosleep(&req, &rem); 399 | if(ret >= 0) return ret; 400 | if(ret == -EINTR) { 401 | return rem.tv_sec; 402 | } 403 | return 0; 404 | } 405 | #endif 406 | -------------------------------------------------------------------------------- /hw3/tmp/libmini.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBMINI_H__ 2 | #define __LIBMINI_H__ /* avoid reentrant */ 3 | 4 | typedef long long size_t; 5 | typedef long long ssize_t; 6 | typedef long long off_t; 7 | typedef int mode_t; 8 | typedef int uid_t; 9 | typedef int gid_t; 10 | typedef int pid_t; 11 | 12 | typedef void (*sighandler_t)(int); 13 | 14 | extern long errno; 15 | 16 | #define NULL ((void*) 0) 17 | 18 | /* from /usr/include/asm-generic/fcntl.h */ 19 | #define O_ACCMODE 00000003 20 | #define O_RDONLY 00000000 21 | #define O_WRONLY 00000001 22 | #define O_RDWR 00000002 23 | #ifndef O_CREAT 24 | #define O_CREAT 00000100 /* not fcntl */ 25 | #endif 26 | #ifndef O_EXCL 27 | #define O_EXCL 00000200 /* not fcntl */ 28 | #endif 29 | #ifndef O_NOCTTY 30 | #define O_NOCTTY 00000400 /* not fcntl */ 31 | #endif 32 | #ifndef O_TRUNC 33 | #define O_TRUNC 00001000 /* not fcntl */ 34 | #endif 35 | #ifndef O_APPEND 36 | #define O_APPEND 00002000 37 | #endif 38 | #ifndef O_NONBLOCK 39 | #define O_NONBLOCK 00004000 40 | #endif 41 | #ifndef O_DSYNC 42 | #define O_DSYNC 00010000 /* used to be O_SYNC, see below */ 43 | #endif 44 | #ifndef FASYNC 45 | #define FASYNC 00020000 /* fcntl, for BSD compatibility */ 46 | #endif 47 | #ifndef O_DIRECT 48 | #define O_DIRECT 00040000 /* direct disk access hint */ 49 | #endif 50 | #ifndef O_LARGEFILE 51 | #define O_LARGEFILE 00100000 52 | #endif 53 | #ifndef O_DIRECTORY 54 | #define O_DIRECTORY 00200000 /* must be a directory */ 55 | #endif 56 | #ifndef O_NOFOLLOW 57 | #define O_NOFOLLOW 00400000 /* don't follow links */ 58 | #endif 59 | #ifndef O_NOATIME 60 | #define O_NOATIME 01000000 61 | #endif 62 | #ifndef O_CLOEXEC 63 | #define O_CLOEXEC 02000000 /* set close_on_exec */ 64 | #endif 65 | 66 | /* from /usr/include/asm-generic/errno-base.h */ 67 | #define EPERM 1 /* Operation not permitted */ 68 | #define ENOENT 2 /* No such file or directory */ 69 | #define ESRCH 3 /* No such process */ 70 | #define EINTR 4 /* Interrupted system call */ 71 | #define EIO 5 /* I/O error */ 72 | #define ENXIO 6 /* No such device or address */ 73 | #define E2BIG 7 /* Argument list too long */ 74 | #define ENOEXEC 8 /* Exec format error */ 75 | #define EBADF 9 /* Bad file number */ 76 | #define ECHILD 10 /* No child processes */ 77 | #define EAGAIN 11 /* Try again */ 78 | #define ENOMEM 12 /* Out of memory */ 79 | #define EACCES 13 /* Permission denied */ 80 | #define EFAULT 14 /* Bad address */ 81 | #define ENOTBLK 15 /* Block device required */ 82 | #define EBUSY 16 /* Device or resource busy */ 83 | #define EEXIST 17 /* File exists */ 84 | #define EXDEV 18 /* Cross-device link */ 85 | #define ENODEV 19 /* No such device */ 86 | #define ENOTDIR 20 /* Not a directory */ 87 | #define EISDIR 21 /* Is a directory */ 88 | #define EINVAL 22 /* Invalid argument */ 89 | #define ENFILE 23 /* File table overflow */ 90 | #define EMFILE 24 /* Too many open files */ 91 | #define ENOTTY 25 /* Not a typewriter */ 92 | #define ETXTBSY 26 /* Text file busy */ 93 | #define EFBIG 27 /* File too large */ 94 | #define ENOSPC 28 /* No space left on device */ 95 | #define ESPIPE 29 /* Illegal seek */ 96 | #define EROFS 30 /* Read-only file system */ 97 | #define EMLINK 31 /* Too many links */ 98 | #define EPIPE 32 /* Broken pipe */ 99 | #define EDOM 33 /* Math argument out of domain of func */ 100 | #define ERANGE 34 /* Math result not representable */ 101 | 102 | /* from /usr/include/asm-generic/errno.h */ 103 | #define EDEADLK 35 /* Resource deadlock would occur */ 104 | #define ENAMETOOLONG 36 /* File name too long */ 105 | #define ENOLCK 37 /* No record locks available */ 106 | #define ENOSYS 38 /* Invalid system call number */ 107 | #define ENOTEMPTY 39 /* Directory not empty */ 108 | #define ELOOP 40 /* Too many symbolic links encountered */ 109 | #define EWOULDBLOCK EAGAIN /* Operation would block */ 110 | #define ENOMSG 42 /* No message of desired type */ 111 | #define EIDRM 43 /* Identifier removed */ 112 | #define ECHRNG 44 /* Channel number out of range */ 113 | #define EL2NSYNC 45 /* Level 2 not synchronized */ 114 | #define EL3HLT 46 /* Level 3 halted */ 115 | #define EL3RST 47 /* Level 3 reset */ 116 | #define ELNRNG 48 /* Link number out of range */ 117 | #define EUNATCH 49 /* Protocol driver not attached */ 118 | #define ENOCSI 50 /* No CSI structure available */ 119 | #define EL2HLT 51 /* Level 2 halted */ 120 | #define EBADE 52 /* Invalid exchange */ 121 | #define EBADR 53 /* Invalid request descriptor */ 122 | #define EXFULL 54 /* Exchange full */ 123 | #define ENOANO 55 /* No anode */ 124 | #define EBADRQC 56 /* Invalid request code */ 125 | #define EBADSLT 57 /* Invalid slot */ 126 | #define EDEADLOCK EDEADLK 127 | #define EBFONT 59 /* Bad font file format */ 128 | #define ENOSTR 60 /* Device not a stream */ 129 | #define ENODATA 61 /* No data available */ 130 | #define ETIME 62 /* Timer expired */ 131 | #define ENOSR 63 /* Out of streams resources */ 132 | #define ENONET 64 /* Machine is not on the network */ 133 | #define ENOPKG 65 /* Package not installed */ 134 | #define EREMOTE 66 /* Object is remote */ 135 | #define ENOLINK 67 /* Link has been severed */ 136 | #define EADV 68 /* Advertise error */ 137 | #define ESRMNT 69 /* Srmount error */ 138 | #define ECOMM 70 /* Communication error on send */ 139 | #define EPROTO 71 /* Protocol error */ 140 | #define EMULTIHOP 72 /* Multihop attempted */ 141 | #define EDOTDOT 73 /* RFS specific error */ 142 | #define EBADMSG 74 /* Not a data message */ 143 | #define EOVERFLOW 75 /* Value too large for defined data type */ 144 | #define ENOTUNIQ 76 /* Name not unique on network */ 145 | #define EBADFD 77 /* File descriptor in bad state */ 146 | #define EREMCHG 78 /* Remote address changed */ 147 | #define ELIBACC 79 /* Can not access a needed shared library */ 148 | #define ELIBBAD 80 /* Accessing a corrupted shared library */ 149 | #define ELIBSCN 81 /* .lib section in a.out corrupted */ 150 | #define ELIBMAX 82 /* Attempting to link in too many shared libraries */ 151 | #define ELIBEXEC 83 /* Cannot exec a shared library directly */ 152 | #define EILSEQ 84 /* Illegal byte sequence */ 153 | #define ERESTART 85 /* Interrupted system call should be restarted */ 154 | #define ESTRPIPE 86 /* Streams pipe error */ 155 | #define EUSERS 87 /* Too many users */ 156 | #define ENOTSOCK 88 /* Socket operation on non-socket */ 157 | #define EDESTADDRREQ 89 /* Destination address required */ 158 | #define EMSGSIZE 90 /* Message too long */ 159 | #define EPROTOTYPE 91 /* Protocol wrong type for socket */ 160 | #define ENOPROTOOPT 92 /* Protocol not available */ 161 | #define EPROTONOSUPPORT 93 /* Protocol not supported */ 162 | #define ESOCKTNOSUPPORT 94 /* Socket type not supported */ 163 | #define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ 164 | #define EPFNOSUPPORT 96 /* Protocol family not supported */ 165 | #define EAFNOSUPPORT 97 /* Address family not supported by protocol */ 166 | #define EADDRINUSE 98 /* Address already in use */ 167 | #define EADDRNOTAVAIL 99 /* Cannot assign requested address */ 168 | #define ENETDOWN 100 /* Network is down */ 169 | #define ENETUNREACH 101 /* Network is unreachable */ 170 | #define ENETRESET 102 /* Network dropped connection because of reset */ 171 | #define ECONNABORTED 103 /* Software caused connection abort */ 172 | #define ECONNRESET 104 /* Connection reset by peer */ 173 | #define ENOBUFS 105 /* No buffer space available */ 174 | #define EISCONN 106 /* Transport endpoint is already connected */ 175 | #define ENOTCONN 107 /* Transport endpoint is not connected */ 176 | #define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ 177 | #define ETOOMANYREFS 109 /* Too many references: cannot splice */ 178 | #define ETIMEDOUT 110 /* Connection timed out */ 179 | #define ECONNREFUSED 111 /* Connection refused */ 180 | #define EHOSTDOWN 112 /* Host is down */ 181 | #define EHOSTUNREACH 113 /* No route to host */ 182 | #define EALREADY 114 /* Operation already in progress */ 183 | #define EINPROGRESS 115 /* Operation now in progress */ 184 | #define ESTALE 116 /* Stale file handle */ 185 | #define EUCLEAN 117 /* Structure needs cleaning */ 186 | #define ENOTNAM 118 /* Not a XENIX named type file */ 187 | #define ENAVAIL 119 /* No XENIX semaphores available */ 188 | #define EISNAM 120 /* Is a named type file */ 189 | #define EREMOTEIO 121 /* Remote I/O error */ 190 | #define EDQUOT 122 /* Quota exceeded */ 191 | #define ENOMEDIUM 123 /* No medium found */ 192 | #define EMEDIUMTYPE 124 /* Wrong medium type */ 193 | #define ECANCELED 125 /* Operation Canceled */ 194 | #define ENOKEY 126 /* Required key not available */ 195 | #define EKEYEXPIRED 127 /* Key has expired */ 196 | #define EKEYREVOKED 128 /* Key has been revoked */ 197 | #define EKEYREJECTED 129 /* Key was rejected by service */ 198 | /* for robust mutexes */ 199 | #define EOWNERDEAD 130 /* Owner died */ 200 | #define ENOTRECOVERABLE 131 /* State not recoverable */ 201 | #define ERFKILL 132 /* Operation not possible due to RF-kill */ 202 | #define EHWPOISON 133 /* Memory page has hardware error */ 203 | 204 | /* from /usr/include/x86_64-linux-gnu/asm/signal.h */ 205 | #define SIGHUP 1 206 | #define SIGINT 2 207 | #define SIGQUIT 3 208 | #define SIGILL 4 209 | #define SIGTRAP 5 210 | #define SIGABRT 6 211 | #define SIGIOT 6 212 | #define SIGBUS 7 213 | #define SIGFPE 8 214 | #define SIGKILL 9 215 | #define SIGUSR1 10 216 | #define SIGSEGV 11 217 | #define SIGUSR2 12 218 | #define SIGPIPE 13 219 | #define SIGALRM 14 220 | #define SIGTERM 15 221 | #define SIGSTKFLT 16 222 | #define SIGCHLD 17 223 | #define SIGCONT 18 224 | #define SIGSTOP 19 225 | #define SIGTSTP 20 226 | #define SIGTTIN 21 227 | #define SIGTTOU 22 228 | #define SIGURG 23 229 | #define SIGXCPU 24 230 | #define SIGXFSZ 25 231 | #define SIGVTALRM 26 232 | #define SIGPROF 27 233 | #define SIGWINCH 28 234 | #define SIGIO 29 235 | #define SIGPOLL SIGIO 236 | 237 | #define SIGCANCEL 32 238 | #define SIGSETXID 33 239 | 240 | #define NSIG 64 + 1 241 | 242 | /* Fake signal functions. */ 243 | #define SIG_ERR ((sighandler_t) -1) /* Error return. */ 244 | #define SIG_DFL ((sighandler_t) 0) /* Default action. */ 245 | #define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */ 246 | 247 | /* from /usr/include/x86_64-linux-gnu/bits/sigaction.h */ 248 | #define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ 249 | #define SA_NOCLDWAIT 2 /* Don't create zombie on child death. */ 250 | #define SA_SIGINFO 4 /* Invoke signal-catching function with 251 | three arguments instead of one. */ 252 | # define SA_ONSTACK 0x08000000 /* Use signal stack by using `sa_restorer'. */ 253 | # define SA_RESTART 0x10000000 /* Restart syscall on signal return. */ 254 | # define SA_INTERRUPT 0x20000000 /* Historical no-op. */ 255 | # define SA_NODEFER 0x40000000 /* Don't automatically block the signal when 256 | its handler is being executed. */ 257 | # define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler. */ 258 | 259 | #define SIG_BLOCK 0 /* Block signals. */ 260 | #define SIG_UNBLOCK 1 /* Unblock signals. */ 261 | #define SIG_SETMASK 2 /* Set the set of blocked signals. */ 262 | 263 | struct timespec { 264 | long tv_sec; /* seconds */ 265 | long tv_nsec; /* nanoseconds */ 266 | }; 267 | 268 | struct timeval { 269 | long tv_sec; /* seconds */ 270 | long tv_usec; /* microseconds */ 271 | }; 272 | 273 | struct timezone { 274 | int tz_minuteswest; /* minutes west of Greenwich */ 275 | int tz_dsttime; /* type of DST correction */ 276 | }; 277 | 278 | typedef struct { 279 | unsigned long sig[16]; 280 | } sigset_t; 281 | 282 | typedef struct { 283 | unsigned char s[128]; 284 | } siginfo_t; 285 | 286 | struct sigaction { 287 | void (*sa_handler)(int); 288 | void (*sa_sigaction)(int, siginfo_t *, void *); 289 | sigset_t sa_mask; 290 | int sa_flags; 291 | void (*sa_restorer)(void); 292 | }; 293 | 294 | typedef struct jmp_buf_s { 295 | long long reg[8]; 296 | sigset_t mask; 297 | } jmp_buf[1]; 298 | 299 | /* system calls */ 300 | long sys_read(int fd, char *buf, size_t count); 301 | long sys_write(int fd, const void *buf, size_t count); 302 | long sys_open(const char *filename, int flags, ... /*mode*/); 303 | long sys_close(unsigned int fd); 304 | long sys_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off); 305 | long sys_mprotect(void *addr, size_t len, int prot); 306 | long sys_munmap(void *addr, size_t len); 307 | long sys_pipe(int *filedes); 308 | long sys_dup(int filedes); 309 | long sys_dup2(int oldfd, int newfd); 310 | long sys_pause(); 311 | long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); 312 | long sys_fork(void); 313 | long sys_exit(int error_code) __attribute__ ((noreturn)); 314 | long sys_getcwd(char *buf, size_t size); 315 | long sys_chdir(const char *pathname); 316 | long sys_rename(const char *oldname, const char *newname); 317 | long sys_mkdir(const char *pathname, int mode); 318 | long sys_rmdir(const char *pathname); 319 | long sys_creat(const char *pathname, int mode); 320 | long sys_link(const char *oldname, const char *newname); 321 | long sys_unlink(const char *pathname); 322 | long sys_readlink(const char *path, char *buf, size_t bufsz); 323 | long sys_chmod(const char *filename, mode_t mode); 324 | long sys_chown(const char *filename, uid_t user, gid_t group); 325 | long sys_umask(int mask); 326 | long sys_gettimeofday(struct timeval *tv, struct timezone *tz); 327 | long sys_getuid(); 328 | long sys_getgid(); 329 | long sys_setuid(uid_t uid); 330 | long sys_setgid(gid_t gid); 331 | long sys_geteuid(); 332 | long sys_getegid(); 333 | 334 | /* extend system calls */ 335 | long sys_alarm(unsigned int seconds); 336 | 337 | /* wrappers */ 338 | ssize_t read(int fd, char *buf, size_t count); 339 | ssize_t write(int fd, const void *buf, size_t count); 340 | int open(const char *filename, int flags, ... /*mode*/); 341 | int close(unsigned int fd); 342 | void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off); 343 | int mprotect(void *addr, size_t len, int prot); 344 | int munmap(void *addr, size_t len); 345 | int pipe(int *filedes); 346 | int dup(int filedes); 347 | int dup2(int oldfd, int newfd); 348 | int pause(); 349 | int nanosleep(struct timespec *rqtp, struct timespec *rmtp); 350 | pid_t fork(void); 351 | void exit(int error_code); 352 | char * getcwd(char *buf, size_t size); 353 | int chdir(const char *pathname); 354 | int rename(const char *oldname, const char *newname); 355 | int mkdir(const char *pathname, int mode); 356 | int rmdir(const char *pathname); 357 | int creat(const char *pathname, int mode); 358 | int link(const char *oldname, const char *newname); 359 | int unlink(const char *pathname); 360 | ssize_t readlink(const char *path, char *buf, size_t bufsz); 361 | int chmod(const char *filename, mode_t mode); 362 | int chown(const char *filename, uid_t user, gid_t group); 363 | int umask(int mask); 364 | int gettimeofday(struct timeval *tv, struct timezone *tz); 365 | uid_t getuid(); 366 | gid_t getgid(); 367 | int setuid(uid_t uid); 368 | int setgid(gid_t gid); 369 | uid_t geteuid(); 370 | gid_t getegid(); 371 | 372 | void bzero(void *s, size_t size); 373 | size_t strlen(const char *s); 374 | void perror(const char *prefix); 375 | unsigned int sleep(unsigned int s); 376 | 377 | /* extend wrappers */ 378 | unsigned int alarm(unsigned int seconds); 379 | int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 380 | int sigpending(sigset_t *set); 381 | sighandler_t signal(int sig, sighandler_t handler); 382 | int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); 383 | 384 | int setjmp(jmp_buf env); 385 | void longjmp(jmp_buf env, int val); 386 | int sigemptyset(sigset_t *set); 387 | int sigfillset(sigset_t *set); 388 | int sigaddset(sigset_t *set, int signum); 389 | int sigdelset(sigset_t *set, int signum); 390 | int sigismember(const sigset_t *set, int signum); 391 | 392 | #endif /* __LIBMINI_H__ */ 393 | -------------------------------------------------------------------------------- /hw3/tmp/libmini64.asm: -------------------------------------------------------------------------------- 1 | 2 | %macro gensys 2 3 | global sys_%2:function 4 | sys_%2: 5 | push r10 6 | mov r10, rcx 7 | mov rax, %1 8 | syscall 9 | pop r10 10 | ret 11 | %endmacro 12 | 13 | ; RDI, RSI, RDX, RCX, R8, R9 14 | 15 | extern errno 16 | 17 | section .data 18 | 19 | section .text 20 | 21 | gensys 0, read 22 | gensys 1, write 23 | gensys 2, open 24 | gensys 3, close 25 | gensys 9, mmap 26 | gensys 10, mprotect 27 | gensys 11, munmap 28 | gensys 22, pipe 29 | gensys 32, dup 30 | gensys 33, dup2 31 | gensys 34, pause 32 | gensys 35, nanosleep 33 | gensys 57, fork 34 | gensys 60, exit 35 | gensys 79, getcwd 36 | gensys 80, chdir 37 | gensys 82, rename 38 | gensys 83, mkdir 39 | gensys 84, rmdir 40 | gensys 85, creat 41 | gensys 86, link 42 | gensys 88, unlink 43 | gensys 89, readlink 44 | gensys 90, chmod 45 | gensys 92, chown 46 | gensys 95, umask 47 | gensys 96, gettimeofday 48 | gensys 102, getuid 49 | gensys 104, getgid 50 | gensys 105, setuid 51 | gensys 106, setgid 52 | gensys 107, geteuid 53 | gensys 108, getegid 54 | 55 | gensys 37, alarm 56 | 57 | global open:function 58 | open: 59 | call sys_open 60 | cmp rax, 0 61 | jge open_success ; no error :) 62 | open_error: 63 | neg rax 64 | %ifdef NASM 65 | mov rdi, [rel errno wrt ..gotpc] 66 | %else 67 | mov rdi, [rel errno wrt ..gotpcrel] 68 | %endif 69 | mov [rdi], rax ; errno = -rax 70 | mov rax, -1 71 | jmp open_quit 72 | open_success: 73 | %ifdef NASM 74 | mov rdi, [rel errno wrt ..gotpc] 75 | %else 76 | mov rdi, [rel errno wrt ..gotpcrel] 77 | %endif 78 | mov QWORD [rdi], 0 ; errno = 0 79 | open_quit: 80 | ret 81 | 82 | global sleep:function 83 | sleep: 84 | sub rsp, 32 ; allocate timespec * 2 85 | mov [rsp], rdi ; req.tv_sec 86 | mov QWORD [rsp+8], 0 ; req.tv_nsec 87 | mov rdi, rsp ; rdi = req @ rsp 88 | lea rsi, [rsp+16] ; rsi = rem @ rsp+16 89 | call sys_nanosleep 90 | cmp rax, 0 91 | jge sleep_quit ; no error :) 92 | sleep_error: 93 | neg rax 94 | cmp rax, 4 ; rax == EINTR? 95 | jne sleep_failed 96 | sleep_interrupted: 97 | lea rsi, [rsp+16] 98 | mov rax, [rsi] ; return rem.tv_sec 99 | jmp sleep_quit 100 | sleep_failed: 101 | mov rax, 0 ; return 0 on error 102 | sleep_quit: 103 | add rsp, 32 104 | ret 105 | 106 | -------------------------------------------------------------------------------- /hw4/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -g -Wall -std=c++17 3 | LIBS = -lelf -lcapstone 4 | 5 | PROGS = sdb 6 | 7 | all: $(PROGS) 8 | 9 | $(PROGS): $(wildcard *.cpp) 10 | $(CXX) -o $@ $(CXXFLAGS) $^ $(LIBS) 11 | 12 | .PHONY: clean 13 | 14 | clean: 15 | rm -f *~ $(PROGS) 16 | -------------------------------------------------------------------------------- /hw4/README.md: -------------------------------------------------------------------------------- 1 | # Simple Instruction Level Debugger 2 | 3 | In this homework, we are going to implement a simple instruction-level debugger that allows a user to debug a program interactively at the assembly instruction level. You can implement the debugger by using the ptrace interface. The commands you have to implement are summarized as follows: 4 | 5 | - break {instruction-address}: add a break point 6 | - cont: continue execution 7 | - delete {break-point-id}: remove a break point 8 | - disasm addr: disassemble instructions in a file or a memory region 9 | - dump addr [length]: dump memory content 10 | - exit: terminate the debugger 11 | - get reg: get a single value from a register 12 | - getregs: show registers 13 | - help: show this message 14 | - list: list break points 15 | - load {path/to/a/program}: load a program 16 | - run: run the program 17 | - vmmap: show memory layout 18 | - set reg val: get a single value to a register 19 | - si: step into instruction 20 | - start: start the program and stop at the first instruction 21 | 22 | The details of each command are explained below. In a debugging process, you have to load a program first, configure the debugger, and start debugging by running the program. A debugger command may be only used in certain "states." The states include **any**, **loaded**, and **running**. **any** means that a command can be used at any time. **loaded** means that a command can be only used when a program is loaded. **running** means that a command can be only used when the program is running. We will use brackets right after a command to enclose the list of the state(s) that should be supported by the command. 23 | 24 | 25 | 26 | - **break** or **b** [**loaded** and **running**]: Setup a break point. If a program is loaded but is not running, the address should be within the range specified by the text segment in the ELF file. When a break point is hit, you have to output a message and indicate the corresponding address and instruction. 27 | - **cont** or **c** [**running**]: continue the execution when a running program is stopped (suspended). 28 | - **delete** [**any**]: remove a break point. 29 | - **disasm** or **d** [**loaded** and **running**]: Disassemble instructions in a file or a memory region. The address should be within the range specified by the text segment in the ELF file. You only have to dump 10 instructions for each command. If **disasm** command is executed without an address, it should disassemble the codes right after the previously disassembled codes. See the demonstration section for the sample output format. 30 | - **dump** or **x** [**running**]: Dump memory content. You only have to dump 80 bytes from a given address. The output contains the addresses, the hex values, and printable ascii characters. If **dump** command is executed without an address, it should dump the region right after the previous dump. 31 | - **exit** or **q** [**any**]: Quit from the debugger. The program being debugged should be killed as well. 32 | - **get** or **g** [**running**]: Get the value of a register. Register names are all in lowercase. 33 | - **getregs** [**running**]: Get the value of all registers. 34 | - **help** or **h** [**any**]: Show the help message. 35 | - **list** or **l** [**any**]: List break points, which contains index numbers (for deletion) and addresses. 36 | - **load** [not **loaded**]: Load a program into the debugger. When a program is loaded, you have to print out the entry point, the address, the offset, and the size for the text segment. 37 | - **run** or **r** [**loaded** and **running**]: Run the program. If the program is already running, show a warning message and continue the execution. 38 | - **vmmap** or **m** [**loaded** and **running**]: Show memory layout for a running program. If a program is loaded but is not running, it should display the text segment address of the loaded program. 39 | - **set** or **s** [**running**]: Set the value of a register 40 | - **si** [**running**]: Run a single instruction, and step into function calls. 41 | - **start** [**loaded**]: Start the program and stop at the first instruction. 42 | 43 | 44 | 45 | For more details about the implementation, please check the demonstration section for the sample input and the corresponding output. 46 | -------------------------------------------------------------------------------- /hw4/elftool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "elftool.hpp" 11 | 12 | void elf_perror(const char *prefix) { 13 | int e = elf_errno(); 14 | fprintf(stderr, "%s: %s\n", prefix, elf_errmsg(e)); 15 | return; 16 | } 17 | 18 | static int _elf_tool_initialized = 0; 19 | 20 | int 21 | elf_init() { 22 | errno = 0; 23 | if(_elf_tool_initialized <= 0) { 24 | elf_version(1); // version must be set first 25 | } 26 | _elf_tool_initialized = 1; 27 | return 0; 28 | } 29 | 30 | elf_handle_t * 31 | elf_open(const char *filename) { 32 | int fd = -1; 33 | char *ident = NULL; 34 | size_t idsize = 0; 35 | Elf *elf = NULL; 36 | elf_handle_t *e = NULL; 37 | 38 | if((fd = open(filename, O_RDONLY)) < 0) return NULL; 39 | if((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) goto err_quit; 40 | if((ident = elf_getident(elf, &idsize)) == NULL) goto err_quit; 41 | if((e = (elf_handle_t*) malloc(sizeof(elf_handle_t))) == NULL) goto err_quit; 42 | memset(e, 0, sizeof(elf_handle_t)); 43 | e->fd = -1; 44 | 45 | if(ident[4] == 0x01) { // 32-bit 46 | e->clazz = ELFCLASS32; 47 | e->ehdr.ptr = elf32_getehdr(elf); 48 | e->phnum = e->ehdr.ptr32->e_phnum; 49 | e->shnum = e->ehdr.ptr32->e_shnum; 50 | e->shstrndx = e->ehdr.ptr32->e_shstrndx; 51 | e->entrypoint = e->ehdr.ptr32->e_entry; 52 | } else if(ident[4] == 0x02) { // 64-bit 53 | e->clazz = ELFCLASS64; 54 | e->ehdr.ptr = elf64_getehdr(elf); 55 | e->phnum = e->ehdr.ptr64->e_phnum; 56 | e->shnum = e->ehdr.ptr64->e_shnum; 57 | e->shstrndx = e->ehdr.ptr64->e_shstrndx; 58 | e->entrypoint = e->ehdr.ptr64->e_entry; 59 | } else { 60 | errno = ENOTSUP; 61 | goto err_quit; 62 | } 63 | 64 | e->fd = fd; 65 | e->elf = elf; 66 | return e; 67 | 68 | err_quit: 69 | if(elf) { elf_end(elf); elf = NULL; } 70 | if(fd >= 0) { close(fd); fd = -1; } 71 | if(e) { free(e); e = NULL; } 72 | return NULL; 73 | } 74 | 75 | int 76 | elf_close(elf_handle_t *e) { 77 | if(e == NULL) return 0; 78 | if(e->dsym) { free(e->dsym); e->dsym = NULL; } 79 | if(e->sym) { free(e->sym); e->sym = NULL; } 80 | if(e->strtab) { elf_free_strtab(e->strtab); e->strtab = NULL; } 81 | if(e->shdr) { free(e->shdr); e->shdr = NULL; } 82 | if(e->phdr) { free(e->phdr); e->phdr = NULL; } 83 | if(e->elf) { elf_end(e->elf); e->elf = NULL; } 84 | if(e->fd >= 0) { close(e->fd); e->fd = -1; } 85 | free(e); 86 | return 0; 87 | } 88 | 89 | int 90 | elf_load_all(elf_handle_t *e) { 91 | if(elf_load_phdr(e) == NULL) goto err_quit; 92 | if(elf_load_shdr(e) == NULL) goto err_quit; 93 | if(elf_load_strtab(e) == NULL) goto err_quit; 94 | elf_load_symtab(e); // optional, no check 95 | elf_load_dsymtab(e); // optional, no check 96 | return 0; 97 | err_quit: 98 | if(e->dsym) { free(e->dsym); e->dsym = NULL; } 99 | if(e->sym) { free(e->sym); e->sym = NULL; } 100 | if(e->strtab) { elf_free_strtab(e->strtab); e->strtab = NULL; } 101 | if(e->shdr) { free(e->shdr); e->shdr = NULL; } 102 | if(e->phdr) { free(e->phdr); e->phdr = NULL; } 103 | return -1; 104 | } 105 | 106 | elf_phdr_t * 107 | elf_load_phdr(elf_handle_t *e) { 108 | int i; 109 | elf_phdr_t *phdr = NULL; 110 | if(e->phdr != NULL) return e->phdr; 111 | if(e->phnum <= 0) return NULL; 112 | if(e->clazz != ELFCLASS32 && e->clazz != ELFCLASS64) return NULL; 113 | if((phdr = (elf_phdr_t*) malloc(sizeof(elf_phdr_t) * e->phnum)) == NULL) 114 | return NULL; 115 | 116 | #define ITER_PHDR(x) do { Elf##x##_Phdr *p = elf##x##_getphdr(e->elf); \ 117 | for(i = 0; i < e->phnum; i++) { \ 118 | phdr[i].type = p[i].p_type; \ 119 | phdr[i].offset = p[i].p_offset; \ 120 | phdr[i].vaddr = p[i].p_vaddr; \ 121 | phdr[i].paddr = p[i].p_paddr; \ 122 | phdr[i].filesz = p[i].p_filesz; \ 123 | phdr[i].memsz = p[i].p_memsz; \ 124 | phdr[i].flags = p[i].p_flags; \ 125 | phdr[i].align = p[i].p_align; \ 126 | } } while(0); // do it only once 127 | 128 | if(e->clazz == ELFCLASS32) { 129 | ITER_PHDR(32); 130 | } else { 131 | ITER_PHDR(64); 132 | } 133 | 134 | e->phdr = phdr; 135 | return phdr; 136 | } 137 | 138 | elf_shdr_t * 139 | elf_load_shdr(elf_handle_t *e) { 140 | Elf_Scn *scn = NULL; // section descriptor 141 | elf_shdr_t *shdr = NULL; 142 | if(e->shdr != NULL) return e->shdr; 143 | if(e->shnum <= 0) return NULL; 144 | if(e->clazz != ELFCLASS32 && e->clazz != ELFCLASS64) return NULL; 145 | if((shdr = (elf_shdr_t*) malloc(sizeof(elf_shdr_t) * e->shnum)) == NULL) 146 | return NULL; 147 | 148 | #define ASSIGN_SHDR(x) do { Elf##x##_Shdr *s = elf##x##_getshdr(scn); \ 149 | shdr[idx].name = s->sh_name; \ 150 | shdr[idx].type = s->sh_type; \ 151 | shdr[idx].flags = s->sh_flags; \ 152 | shdr[idx].addr = s->sh_addr; \ 153 | shdr[idx].offset = s->sh_offset; \ 154 | shdr[idx].size = s->sh_size; \ 155 | shdr[idx].link = s->sh_link; \ 156 | shdr[idx].info = s->sh_info; \ 157 | shdr[idx].addralign = s->sh_addralign; \ 158 | shdr[idx].entsize = s->sh_entsize; \ 159 | } while(0); // do it only once 160 | 161 | while((scn = elf_nextscn(e->elf, scn)) != NULL) { 162 | int idx = elf_ndxscn(scn) % e->shnum; 163 | if(e->clazz == ELFCLASS32) { ASSIGN_SHDR(32); } 164 | else { ASSIGN_SHDR(64); } 165 | } 166 | 167 | e->shdr = shdr; 168 | return shdr; 169 | } 170 | 171 | elf_strtab_t * 172 | elf_load_strtab(elf_handle_t *e) { 173 | int i, realerror; 174 | elf_strtab_t *strtab = NULL, *curr = NULL; 175 | if(e->strtab != NULL) return e->strtab; 176 | if(elf_load_shdr(e) == NULL) return NULL; 177 | for(i = 0; i < e->shnum; i++) { 178 | if(e->shdr[i].type != SHT_STRTAB) continue; 179 | if((curr = (elf_strtab_t*) malloc(sizeof(elf_strtab_t))) == NULL) 180 | goto err_quit; 181 | curr->id = i; 182 | curr->datasize = e->shdr[i].size; 183 | if((curr->data = (char*) malloc(e->shdr[i].size)) == NULL) 184 | goto err_quit; 185 | if(pread(e->fd, curr->data, e->shdr[i].size, e->shdr[i].offset) != e->shdr[i].size) 186 | goto err_quit; 187 | curr->next = strtab; 188 | strtab = curr; 189 | } 190 | e->strtab = strtab; 191 | return strtab; 192 | err_quit: 193 | realerror = errno; 194 | elf_free_strtab(strtab); 195 | errno = realerror; 196 | return NULL; 197 | } 198 | 199 | void 200 | elf_free_strtab(elf_strtab_t *strtab) { 201 | elf_strtab_t *curr, *nextab; 202 | for(curr = strtab; curr != NULL; curr = nextab) { 203 | nextab = curr->next; 204 | if(curr->data) free(curr->data); 205 | free(curr); 206 | } 207 | return; 208 | } 209 | 210 | static elf_symtab_t * 211 | elf_load_symtab_internal(elf_handle_t *e, elf_shdr_t *shdr) { 212 | int i, realerror; 213 | elf_strtab_t *tab = NULL; 214 | elf_symtab_t *symtab = NULL; 215 | if(shdr == NULL) return NULL; 216 | if(elf_load_shdr(e) == NULL) return NULL; 217 | if(elf_load_strtab(e) == NULL) return NULL; 218 | if((symtab = (elf_symtab_t*) malloc(sizeof(elf_symtab_t))) == NULL) return NULL; 219 | if(e->clazz != ELFCLASS32 && e->clazz != ELFCLASS64) { errno = EINVAL; return NULL; } 220 | for(tab = e->strtab; tab != NULL; tab = tab->next) { 221 | if(shdr->link == tab->id) { 222 | symtab->strtab = tab; 223 | break; 224 | } 225 | } 226 | if(symtab->strtab == NULL) { // table not found 227 | //fprintf(stderr, "! cannot find the string table (%llx,%lld)\n", shdr->type, shdr->link); 228 | realerror = ESRCH; 229 | goto err_quit; 230 | } 231 | symtab->count = (e->clazz == ELFCLASS32) ? (shdr->size/sizeof(Elf32_Sym)) : (shdr->size/sizeof(Elf64_Sym)); 232 | if((symtab->symbol = (elf_symbol_t*) malloc(sizeof(elf_symbol_t) * symtab->count + shdr->size)) == NULL) 233 | goto err_quit; 234 | if(pread(e->fd, ((unsigned char*) symtab->symbol) + (sizeof(elf_symbol_t)*symtab->count), shdr->size, shdr->offset) != shdr->size) 235 | goto err_quit; 236 | 237 | #define ASSIGN_SYM(x) do { Elf##x##_Sym *s = (Elf##x##_Sym*) (((unsigned char*) symtab->symbol) + (sizeof(elf_symbol_t)*symtab->count)); \ 238 | symtab->symbol[i].name = s[i].st_name; \ 239 | symtab->symbol[i].info = s[i].st_info; \ 240 | symtab->symbol[i].other = s[i].st_other; \ 241 | symtab->symbol[i].shndx = s[i].st_shndx; \ 242 | symtab->symbol[i].value = s[i].st_value; \ 243 | symtab->symbol[i].size = s[i].st_size; \ 244 | symtab->symbol[i].bind = ELF##x##_ST_BIND(s[i].st_info); \ 245 | symtab->symbol[i].type = ELF##x##_ST_TYPE(s[i].st_info); \ 246 | symtab->symbol[i].visibility= ELF##x##_ST_VISIBILITY(s[i].st_other); \ 247 | } while(0); // do it only once 248 | 249 | for(i = 0; i < symtab->count; i++) { 250 | if(e->clazz == ELFCLASS32) { 251 | ASSIGN_SYM(32); 252 | } else { 253 | ASSIGN_SYM(64); 254 | } 255 | } 256 | 257 | return symtab; 258 | 259 | err_quit: 260 | realerror = errno; 261 | if(symtab) free(symtab); 262 | errno = realerror; 263 | return NULL; 264 | } 265 | 266 | elf_symtab_t * 267 | elf_load_symtab(elf_handle_t *e) { 268 | int i; 269 | if(e->sym != NULL) return e->sym; 270 | if(elf_load_shdr(e) == NULL) return NULL; 271 | for(i = 0; i < e->shnum; i++) { 272 | if(e->shdr[i].type == SHT_SYMTAB) { 273 | e->sym = elf_load_symtab_internal(e, &e->shdr[i]); 274 | return e->sym; 275 | } 276 | } 277 | return NULL; 278 | } 279 | 280 | elf_symtab_t * 281 | elf_load_dsymtab(elf_handle_t *e) { 282 | int i; 283 | if(e->dsym != NULL) return e->dsym; 284 | if(elf_load_shdr(e) == NULL) return NULL; 285 | for(i = 0; i < e->shnum; i++) { 286 | if(e->shdr[i].type == SHT_DYNSYM) { 287 | e->dsym = elf_load_symtab_internal(e, &e->shdr[i]); 288 | return e->dsym; 289 | } 290 | } 291 | return NULL; 292 | } 293 | 294 | -------------------------------------------------------------------------------- /hw4/elftool.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_TOOL_H__ 2 | #define __ELF_TOOL_H__ 3 | 4 | #include 5 | 6 | typedef struct elf_phdr_s { 7 | long long type; // segment type 8 | long long offset; // file offset 9 | long long vaddr; // virtual address 10 | long long paddr; // physical address 11 | long long filesz; // size in file 12 | long long memsz; // size in memory 13 | long long flags; // flags 14 | long long align; // alignment 15 | } elf_phdr_t; 16 | 17 | typedef struct elf_shdr_s { 18 | long long name; // section name 19 | long long type; // section type 20 | long long flags; // section flags 21 | long long addr; // section virtual addr at execution 22 | long long offset; // section file offset 23 | long long size; // section size in bytes 24 | long long link; // link to another section 25 | long long info; // additional section information 26 | long long addralign; // section alignment 27 | long long entsize; // entry size if section holds table 28 | } elf_shdr_t; 29 | 30 | typedef struct elf_strtab_s { 31 | int id; 32 | int datasize; 33 | char *data; 34 | struct elf_strtab_s *next; 35 | } elf_strtab_t; 36 | 37 | typedef struct elf_symbol_s { 38 | int name; // symbol name (string table index) 39 | unsigned char info; // symbol type and binding 40 | unsigned char other; // symbol visibility 41 | int shndx; // section index 42 | long long value; // symbol value 43 | long long size; // symbol size 44 | // extra attributes 45 | unsigned char bind, type, visibility; 46 | } elf_symbol_t; 47 | 48 | typedef struct elf_symtab_s { 49 | int count; 50 | elf_strtab_t *strtab; 51 | elf_symbol_t *symbol; 52 | } elf_symtab_t; 53 | 54 | typedef struct elf_handle_s { 55 | /* real handles */ 56 | int fd; // file descriptor 57 | Elf *elf; // elf ptr from libelf 58 | 59 | /* elf header */ 60 | int clazz; 61 | int phnum; // # of phdr 62 | int shnum; // # of sections 63 | int shstrndx; // section header string table index 64 | long entrypoint; // entrypoint 65 | union { 66 | void *ptr; 67 | Elf32_Ehdr *ptr32; 68 | Elf64_Ehdr *ptr64; 69 | } ehdr; // elf header 70 | 71 | /* other headers and tables */ 72 | elf_phdr_t *phdr; // program header 73 | elf_shdr_t *shdr; // section header 74 | elf_strtab_t *strtab; // string table 75 | elf_symtab_t *sym, *dsym; // symbol table and dynamic symbol table 76 | 77 | } elf_handle_t; 78 | 79 | void elf_perror(const char *prefix); 80 | int elf_init(); 81 | int elf_close(elf_handle_t *handle); 82 | elf_handle_t * elf_open(const char *filename); 83 | 84 | int elf_load_all(elf_handle_t *e); 85 | elf_phdr_t * elf_load_phdr(elf_handle_t *e); 86 | elf_shdr_t * elf_load_shdr(elf_handle_t *e); 87 | elf_strtab_t * elf_load_strtab(elf_handle_t *e); 88 | void elf_free_strtab(elf_strtab_t *strtab); 89 | elf_symtab_t * elf_load_symtab(elf_handle_t *e); 90 | elf_symtab_t * elf_load_dsymtab(elf_handle_t *e); 91 | 92 | #endif /* __ELF_TOOL_H__ */ 93 | -------------------------------------------------------------------------------- /hw4/sample/guess: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5teven1in/Unix-Programming/bf6f132e03d1c57ee901dcba2104db102051052e/hw4/sample/guess -------------------------------------------------------------------------------- /hw4/sample/hello64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5teven1in/Unix-Programming/bf6f132e03d1c57ee901dcba2104db102051052e/hw4/sample/hello64 -------------------------------------------------------------------------------- /hw4/sdb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "elftool.hpp" 16 | #include "sdb.hpp" 17 | 18 | using namespace std; 19 | 20 | int state = NOLOAD; 21 | elf_handle_t *eh = NULL; 22 | elf_strtab_t *tab = NULL; 23 | elf_shdr_t texts = {0}; 24 | elf_phdr_t tphdr = {0}; 25 | string progpath = ""; 26 | pid_t pid = 0; 27 | LL disaddr = -1; 28 | LL dumpaddr = -1; 29 | LL bpaddr = -1; 30 | LL textbase = 0; 31 | char *code = NULL; 32 | bool ispie = false; 33 | int bpid = 0; 34 | int dislen = 10; 35 | int hitbp = -1; 36 | struct user_regs_struct regs_struct = {0}; 37 | map regs; 38 | VS reglist = {"rax", "rbx", "rcx", "rdx", 39 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 40 | "rdi", "rsi", "rbp", "rsp", "rip", "flags"}; 41 | vector bpoints; 42 | 43 | void get_code() { 44 | ifstream f(progpath.c_str(), ios::in | ios::binary | ios::ate); 45 | streampos size; 46 | size = f.tellg(); 47 | int codesz = size + 1L; 48 | code = new char [codesz]; 49 | f.seekg(0, ios::beg); 50 | f.read(code, size); 51 | code[size] = 0; 52 | f.close(); 53 | } 54 | 55 | string get_mem(const LL addr) { 56 | string s = ""; 57 | for (int i = 0; i < MAXASM / 8; i++) { 58 | auto out = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL); 59 | s += string((char*) &out, 8); 60 | } 61 | return s; 62 | } 63 | 64 | void get_regs() { 65 | ptrace(PTRACE_GETREGS, pid, NULL, ®s_struct); 66 | regs["rax"] = (LL*) ®s_struct.rax; 67 | regs["rbx"] = (LL*) ®s_struct.rbx; 68 | regs["rcx"] = (LL*) ®s_struct.rcx; 69 | regs["rdx"] = (LL*) ®s_struct.rdx; 70 | regs["rsp"] = (LL*) ®s_struct.rsp; 71 | regs["rbp"] = (LL*) ®s_struct.rbp; 72 | regs["rsi"] = (LL*) ®s_struct.rsi; 73 | regs["rdi"] = (LL*) ®s_struct.rdi; 74 | regs["rip"] = (LL*) ®s_struct.rip; 75 | regs["r8"] = (LL*) ®s_struct.r8; 76 | regs["r9"] = (LL*) ®s_struct.r9; 77 | regs["r10"] = (LL*) ®s_struct.r10; 78 | regs["r11"] = (LL*) ®s_struct.r11; 79 | regs["r12"] = (LL*) ®s_struct.r12; 80 | regs["r13"] = (LL*) ®s_struct.r13; 81 | regs["r14"] = (LL*) ®s_struct.r14; 82 | regs["r15"] = (LL*) ®s_struct.r15; 83 | regs["flags"] = (LL*) ®s_struct.eflags; 84 | } 85 | 86 | void print_reg(const string &name) { 87 | for (auto &x : reglist) { 88 | if (x == name) { 89 | LL val = *regs[name]; 90 | cerr << name << " = " << val 91 | << " (" << hex << "0x" << val << dec << ")" << endl; 92 | return; 93 | } 94 | } 95 | cerr << "** '" << name << "' does not exist." << endl; 96 | } 97 | 98 | string disone(UC *pos, LL &addr) { 99 | csh handle; 100 | cs_insn *insn; 101 | size_t count; 102 | string out = ""; 103 | if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) { 104 | cerr << "** cs open error." << endl; 105 | return ""; 106 | } 107 | count = cs_disasm(handle, pos, MAXASM, addr, 0, &insn); 108 | if (count > 0) { 109 | stringstream ss; 110 | ss << hex << setfill(' ') << setw(12) << insn[0].address << ": " 111 | << left << setfill(' ') << setw(31) << get_bytes(insn[0].bytes, insn[0].size) 112 | << left << setfill(' ') << setw(7) << insn[0].mnemonic 113 | << right << insn[0].op_str << endl << dec; 114 | addr += insn[0].size; 115 | out = ss.str(); 116 | cs_free(insn, count); 117 | } 118 | else { 119 | cerr << "** failed to disassemble given code!" << endl; 120 | } 121 | cs_close(&handle); 122 | return out; 123 | } 124 | 125 | UC patch_byte(const LL addr, UC c) { 126 | auto code = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL); 127 | ptrace(PTRACE_POKETEXT, pid, addr, (code & 0xffffffffffffff00) | (c & 0xff)); 128 | return code & 0xff; 129 | } 130 | 131 | bool isintext(const LL addr) { 132 | if (state == RUNNING && ispie) { 133 | LL fixaddr = textbase + texts.addr; 134 | return fixaddr <= addr && addr <= (fixaddr + texts.size); 135 | } 136 | return texts.addr <= addr && addr <= (texts.addr + texts.size); 137 | } 138 | 139 | bool chkat(const auto &x, unsigned int at, bool p) { 140 | if (x.size() > at) return true; 141 | if (p) cerr << "** missing argument(s)." << endl; 142 | return false; 143 | } 144 | 145 | // don't care: -1 146 | // hit breakpoint before: 0 147 | // hit breakpoint now: 1 148 | int chkst() { 149 | int status; 150 | waitpid(pid, &status, 0); 151 | if (WIFSTOPPED(status)) { 152 | if (WSTOPSIG(status) != SIGTRAP) { 153 | cerr << "** child process " << pid << " stopped by signal (code " << WSTOPSIG(status) << ")" << endl; 154 | return -1; 155 | } 156 | if (hitbp != -1) return 0; 157 | get_regs(); 158 | // hit the breakpoint or not 159 | for (auto &x : bpoints) { 160 | LL tmpaddr = x.addr; 161 | if (!x.isfix && ispie) tmpaddr += textbase; 162 | if (tmpaddr == (*regs["rip"]) - 1) { 163 | hitbp = x.id; 164 | bpaddr = tmpaddr; 165 | // show breakpoint message 166 | dislen = 1; 167 | LL addrbak = disaddr; 168 | cerr << "** breakpoint @ "; 169 | disaddr = tmpaddr; 170 | disasm(); 171 | disaddr = addrbak; 172 | dislen = 10; 173 | // restore the original value 174 | patch_byte(tmpaddr, x.ori); 175 | (*regs["rip"])--; 176 | ptrace(PTRACE_SETREGS, pid, NULL, ®s_struct); 177 | return 1; 178 | } 179 | } 180 | return -1; 181 | } 182 | if (WIFEXITED(status)) { 183 | if (WIFSIGNALED(status)) 184 | cerr << "** child process " << pid << " terminiated by signal (code " << WTERMSIG(status) << ")" << endl; 185 | else 186 | cerr << "** child process " << pid << " terminiated normally (code " << status << ")" << endl; 187 | pid = 0; 188 | state = LOADED; 189 | return -1; 190 | } 191 | return -1; 192 | } 193 | 194 | void help() { 195 | cerr << "- break {instruction-address}: add a break point" << endl; 196 | cerr << "- cont: continue execution" << endl; 197 | cerr << "- delete {break-point-id}: remove a break point" << endl; 198 | cerr << "- disasm addr: disassemble instructions in a file or a memory region" << endl; 199 | cerr << "- dump addr [length]: dump memory content" << endl; 200 | cerr << "- exit: terminate the debugger" << endl; 201 | cerr << "- get reg: get a single value from a register" << endl; 202 | cerr << "- getregs: show registers" << endl; 203 | cerr << "- help: show this message" << endl; 204 | cerr << "- list: list break points" << endl; 205 | cerr << "- load {path/to/a/program}: load a program" << endl; 206 | cerr << "- run: run the program" << endl; 207 | cerr << "- vmmap: show memory layout" << endl; 208 | cerr << "- set reg val: get a single value to a register" << endl; 209 | cerr << "- si: step into instruction" << endl; 210 | cerr << "- start: start the program and stop at the first instruction" << endl; 211 | } 212 | 213 | void quit() { 214 | if (eh) { 215 | elf_close(eh); 216 | eh = NULL; 217 | } 218 | if (code) { 219 | delete [] code; 220 | code = NULL; 221 | } 222 | if (pid) kill(pid, SIGTERM); 223 | } 224 | 225 | void load() { 226 | if (state != NOLOAD) { 227 | cerr << "** state must be NOT LOADED." << endl; 228 | return; 229 | } 230 | elf_init(); 231 | if ((eh = elf_open(progpath.c_str())) == NULL) { 232 | cerr << "** unable to open '" << progpath << "'." << endl; 233 | return; 234 | } 235 | if (elf_load_all(eh) < 0) { 236 | cerr << "** unable to load '" << progpath << "'." << endl; 237 | return; 238 | } 239 | for (tab = eh->strtab; tab != NULL; tab = tab->next) { 240 | if (tab->id == eh->shstrndx) break; 241 | } 242 | if (tab == NULL) { 243 | cerr << "** section header string table not found." << endl; 244 | return; 245 | } 246 | for (int i = 0; i < eh->shnum; i++) { 247 | if (!strcmp(&tab->data[eh->shdr[i].name], ".text")) { 248 | texts = eh->shdr[i]; 249 | cerr << "** program '" << progpath << "' loaded. " << hex 250 | << "entry point 0x" << eh->entrypoint 251 | << ", vaddr 0x" << texts.addr 252 | << ", offset 0x" << texts.offset 253 | << ", size 0x" << texts.size << endl << dec; 254 | state = LOADED; 255 | break; 256 | } 257 | } 258 | for (int i = 0; i < eh->phnum; i++) { 259 | LL end = eh->phdr[i].offset + eh->phdr[i].filesz; 260 | if (eh->phdr[i].offset <= texts.offset && texts.offset <= end) { 261 | tphdr = eh->phdr[i]; 262 | break; 263 | } 264 | } 265 | if (eh->ehdr.ptr64->e_type == ET_DYN) ispie = true; 266 | } 267 | 268 | void vmmap() { 269 | if (state == LOADED) { 270 | cerr << hex << setfill('0') << setw(16) << texts.addr << "-" 271 | << setfill('0') << setw(16) << texts.addr + texts.size << " " 272 | << flags2rwx(tphdr.flags) << " " 273 | << setfill('0') << setw(8) << texts.offset << " " 274 | << progpath << endl << dec; 275 | } 276 | else if (state == RUNNING) { 277 | ifstream f("/proc/" + to_string(pid) + "/maps"); 278 | string s; 279 | while (getline(f, s)) { 280 | VS item = split(s); 281 | VS addr = split(item[0], '-'); 282 | cerr << setfill('0') << setw(16) << addr[0] << "-" 283 | << setfill('0') << setw(16) << addr[1] << " " 284 | << item[1].substr(0, 3) << " " 285 | << item[2]; 286 | if (item.size() > 5) cerr << " " << item[5]; 287 | cerr << endl; 288 | } 289 | f.close(); 290 | } 291 | else { 292 | cerr << "** state must be LOADED or RUNNING." << endl; 293 | return; 294 | } 295 | } 296 | 297 | void start() { 298 | if (state != LOADED) { 299 | cerr << "** state must be LOADED." << endl; 300 | return; 301 | } 302 | if (pid) { 303 | cerr << "** program '" << progpath << "' is already running." << endl; 304 | return; 305 | } 306 | pid = fork(); 307 | if (pid < 0) { 308 | cerr << "** fork error." << endl; 309 | return; 310 | } 311 | else if (pid == 0) { // child process 312 | if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { 313 | cerr << "** ptrace error." << endl; 314 | } 315 | char **argv = {NULL}; 316 | execvp(progpath.c_str(), argv); 317 | } 318 | else { // parent process 319 | int status; 320 | waitpid(pid, &status, 0); 321 | // if parent is terminated, kill child 322 | ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL); 323 | // get text base address 324 | ifstream f("/proc/" + to_string(pid) + "/stat"); 325 | string s; 326 | getline(f, s); 327 | VS out = split(s); 328 | textbase = str2ll(out[25]); 329 | // set breakpoints 330 | for (auto &x : bpoints) { 331 | if (!x.isfix) { 332 | LL tmpaddr = x.addr; 333 | if (ispie) tmpaddr += textbase; 334 | UC tmp = patch_byte(tmpaddr, 0xcc); 335 | x.ori = tmp; 336 | } 337 | } 338 | cerr << "** pid " << pid << endl; 339 | state = RUNNING; 340 | } 341 | } 342 | 343 | void cont() { 344 | if (state != RUNNING) { 345 | cerr << "** state must be RUNNING." << endl; 346 | return; 347 | } 348 | // restore the breakpoint 349 | if (hitbp != -1) { 350 | si(); 351 | } 352 | ptrace(PTRACE_CONT, pid, NULL, NULL); 353 | chkst(); 354 | } 355 | 356 | void run() { 357 | if (state == RUNNING) { 358 | cerr << "** program '" << progpath << "' is already running." << endl; 359 | cont(); 360 | } 361 | else if (state == LOADED) { 362 | start(); 363 | cont(); 364 | } 365 | else { 366 | cerr << "** state must be LOADED or RUNNING." << endl; 367 | } 368 | } 369 | 370 | void si() { 371 | if (state != RUNNING) { 372 | cerr << "** state must be RUNNING." << endl; 373 | return; 374 | } 375 | ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL); 376 | // restore the breakpoint 377 | if (chkst() == 0 && hitbp != -1) { 378 | for (auto &x : bpoints) { 379 | if (x.id == hitbp) { 380 | UC tmp = patch_byte(bpaddr, 0xcc); 381 | x.ori = tmp; 382 | hitbp = -1; 383 | break; 384 | } 385 | } 386 | } 387 | } 388 | 389 | void get(const string ®) { 390 | if (state != RUNNING) { 391 | cerr << "** state must be RUNNING." << endl; 392 | return; 393 | } 394 | get_regs(); 395 | print_reg(reg); 396 | } 397 | 398 | void getregs() { 399 | if (state != RUNNING) { 400 | cerr << "** state must be RUNNING." << endl; 401 | return; 402 | } 403 | get_regs(); 404 | for (auto &x : reglist) { 405 | print_reg(x); 406 | } 407 | } 408 | 409 | void set(const string ®, LL val) { 410 | if (state != RUNNING) { 411 | cerr << "** state must be RUNNING." << endl; 412 | return; 413 | } 414 | get_regs(); 415 | *regs[reg] = val; 416 | ptrace(PTRACE_SETREGS, pid, NULL, ®s_struct); 417 | } 418 | 419 | void list() { 420 | for (auto &x : bpoints) { 421 | cerr << setfill(' ') << setw(3) << x.id << ":" 422 | << setfill(' ') << setw(8) << hex << x.addr 423 | << endl << dec; 424 | } 425 | } 426 | 427 | void bp(const LL addr) { 428 | if (state == LOADED) { 429 | if (!isintext(addr)) { 430 | cerr << "** address must be in the text segment. (LOADED state)" << endl; 431 | return; 432 | } 433 | bpoints.PB({bpid++, addr, 0, false}); 434 | } 435 | else if (state == RUNNING) { 436 | UC tmp = patch_byte(addr, 0xcc); 437 | bpoints.PB({bpid++, addr, tmp, true}); 438 | } 439 | else { 440 | cerr << "** state must be LOADED or RUNNING." << endl; 441 | } 442 | } 443 | 444 | void del(int id) { 445 | bool chk = false; 446 | for (auto itr = bpoints.begin(); itr != bpoints.end(); itr++) { 447 | if (id == (*itr).id) { 448 | patch_byte((*itr).addr, (*itr).ori); 449 | bpoints.erase(itr); 450 | chk = true; 451 | break; 452 | } 453 | } 454 | if (chk) cerr << "** breakpoint " << id << " deleted." << endl; 455 | else cerr << "** no breakpoint number " << id << "." << endl; 456 | } 457 | 458 | void disasm() { 459 | if (state != LOADED && state != RUNNING) { 460 | cerr << "** state must be LOADED or RUNNING." << endl; 461 | return; 462 | } 463 | if (disaddr == -1) { 464 | cerr << "** no addr is given." << endl; 465 | return; 466 | } 467 | if (code == NULL) get_code(); 468 | if (state == LOADED) { 469 | for (int i = 0; i < dislen; i++) { 470 | auto pos = (UC*) code + texts.offset + (disaddr - texts.addr); 471 | LL tmpaddr = disaddr; 472 | string out = disone(pos, tmpaddr); 473 | if (out == "" || tmpaddr > texts.addr + texts.size) break; 474 | else { 475 | disaddr = tmpaddr; 476 | cerr << out; 477 | } 478 | } 479 | return; 480 | } 481 | if (state == RUNNING) { 482 | for (int i = 0; i < dislen; i++) { 483 | if (isintext(disaddr)) { 484 | LL offset; 485 | if (ispie) offset = disaddr - textbase; 486 | else offset = texts.offset + (disaddr - texts.addr); 487 | auto pos = (UC*) code + offset; 488 | string out = disone(pos, disaddr); 489 | cerr << out; 490 | } 491 | else { 492 | string s = get_mem(disaddr); 493 | auto pos = (UC*) s.c_str(); 494 | string out = disone(pos, disaddr); 495 | cerr << out; 496 | } 497 | } 498 | } 499 | } 500 | 501 | void dump(int sz) { 502 | if (state != RUNNING) { 503 | cerr << "** state must be RUNNING." << endl; 504 | return; 505 | } 506 | if (dumpaddr == -1) { 507 | cerr << "** no addr is given." << endl; 508 | return; 509 | } 510 | int nline = sz / 16, nbytes = sz % 16; 511 | int n = nline + (nbytes != 0); 512 | for (int i = 0; i < n; i++) { 513 | string hexout = ""; 514 | for (int j = 0; j < 2; j++) { 515 | auto out = ptrace(PTRACE_PEEKTEXT, pid, dumpaddr, NULL); 516 | hexout += string((char*) &out, 8); 517 | dumpaddr += 8; 518 | } 519 | cerr << hex << setfill(' ') << setw(12) << dumpaddr - 16 << ": " 520 | << left << setfill(' ') << setw(49) << get_bytes((UC*) hexout.c_str(), 16) 521 | << right << get_printable(hexout) << endl << dec; 522 | } 523 | } 524 | 525 | int main(int argc, char *argv[]) { 526 | if (argc > 1) { 527 | progpath = argv[1]; 528 | load(); 529 | } 530 | while (true) { 531 | cerr << "sdb> "; 532 | string s; 533 | getline(cin, s); 534 | VS line = split(s); 535 | if (line.empty()) continue; 536 | string cmd = line[0]; 537 | if (cmd == "break" || cmd == "b") { 538 | if (chkat(line, 1, true)) bp(str2ll(line[1])); 539 | } 540 | else if (cmd == "cont" || cmd == "c") { 541 | cont(); 542 | } 543 | else if (cmd == "delete") { 544 | if (chkat(line, 1, true)) del(stoi(line[1])); 545 | } 546 | else if (cmd == "disasm" || cmd == "d") { 547 | if (chkat(line, 1, false)) disaddr = str2ll(line[1]); 548 | disasm(); 549 | } 550 | else if (cmd == "dump" || cmd == "x") { 551 | if (chkat(line, 1, false)) dumpaddr = str2ll(line[1]); 552 | if (chkat(line, 2, false)) dump(str2ll(line[2])); 553 | else dump(); 554 | } 555 | else if (cmd == "exit" || cmd == "q") { 556 | quit(); 557 | break; 558 | } 559 | else if (cmd == "get" || cmd == "g") { 560 | if (chkat(line, 1, true)) get(line[1]); 561 | } 562 | else if (cmd == "getregs") { 563 | getregs(); 564 | } 565 | else if (cmd == "help" || cmd == "h") { 566 | help(); 567 | } 568 | else if (cmd == "list" || cmd == "l") { 569 | list(); 570 | } 571 | else if (cmd == "load") { 572 | if (chkat(line, 1, true)) progpath = line[1]; 573 | load(); 574 | } 575 | else if (cmd == "run" || cmd == "r") { 576 | run(); 577 | } 578 | else if (cmd == "vmmap" || cmd == "m") { 579 | vmmap(); 580 | } 581 | else if (cmd == "set" || cmd == "s") { 582 | if (chkat(line, 2, true)) set(line[1], str2ll(line[2])); 583 | } 584 | else if (cmd == "si") { 585 | si(); 586 | } 587 | else if (cmd == "start") { 588 | start(); 589 | } 590 | else { 591 | cerr << "Undefined command: \"" << cmd << "\". Try \"help\"." << endl; 592 | } 593 | } 594 | return 0; 595 | } 596 | -------------------------------------------------------------------------------- /hw4/sdb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define PB push_back 8 | #define NOLOAD 0 9 | #define LOADED 1 10 | #define RUNNING 2 11 | #define MAXASM 0x100 12 | 13 | using namespace std; 14 | 15 | typedef vector VS; 16 | typedef long long LL; 17 | typedef unsigned char UC; 18 | 19 | struct breakpoint { 20 | int id; 21 | LL addr; 22 | UC ori; 23 | bool isfix; 24 | breakpoint(int _i = -1, LL _a = 0, UC _o = '\0', bool _f = false) 25 | : id(_i), addr(_a), ori(_o), isfix(_f) { 26 | } 27 | }; 28 | 29 | VS split(const string &s, const char d = '\0') { 30 | VS res; 31 | stringstream ss(s); 32 | string item; 33 | if (d) 34 | while (getline(ss, item, d)) res.PB(item); 35 | else 36 | while (ss >> item) res.PB(item); 37 | return res; 38 | } 39 | 40 | string get_byte(const UC *byte) { 41 | stringstream ss; 42 | ss << hex << setfill('0') << setw(2) << (int) *byte; 43 | string tmp; 44 | ss >> tmp; 45 | return tmp; 46 | } 47 | 48 | string get_bytes(const UC *bytes, int n) { 49 | string out = ""; 50 | bool fir = true; 51 | for (int i = 0; i < n; i++) { 52 | if (!fir) out += " "; 53 | fir = false; 54 | out += get_byte(bytes + i); 55 | } 56 | return out; 57 | } 58 | 59 | string get_printable(const string &s) { 60 | string out = "|"; 61 | for (auto &x : s) { 62 | int tmp = x; 63 | if (tmp < 32 || tmp > 126) out += "."; 64 | else out += x; 65 | } 66 | out += "|"; 67 | return out; 68 | } 69 | 70 | string flags2rwx(const LL flags) { 71 | string per = "xwr", tmp = ""; 72 | for (int i = 2; i >= 0; i--) { 73 | if (flags & (1 << i)) tmp += per[i]; 74 | else tmp += "-"; 75 | } 76 | return tmp; 77 | } 78 | 79 | LL str2ll(const string &s) { 80 | if (s.find("0x") == 0 || s.find("0X") == 0) { 81 | return stoll(s, NULL, 16); 82 | } 83 | else if (s.find("0") == 0) { 84 | return stoll(s, NULL, 8); 85 | } 86 | else { 87 | return stoll(s); 88 | } 89 | } 90 | 91 | void get_code(); 92 | void get_regs(); 93 | string get_mem(const LL addr); 94 | void print_reg(const string &name); 95 | UC patch_byte(const LL addr, UC c); 96 | bool isintext(const LL addr); 97 | bool chkat(const auto &x, unsigned int at, bool p); 98 | int chkst(); 99 | string disone(UC *pos, LL &addr); 100 | 101 | void bp(const LL addr); 102 | void cont(); 103 | void del(int id); 104 | void disasm(); 105 | void dump(int sz = 80); 106 | void quit(); 107 | void get(const string ®); 108 | void getregs(); 109 | void help(); 110 | void list(); 111 | void load(); 112 | void run(); 113 | void vmmap(); 114 | void set(const string ®, LL val); 115 | void si(); 116 | void start(); 117 | --------------------------------------------------------------------------------