mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:06:44 +00:00
[nolibc] Change internal syscall API to remove reliance on libc's errno.
This change moves to a model where the error value of a system call is potentially contained in the return value itself rather than being implicit in errno. The helper function internal_iserror can be used to extract the error value from a return value. On platforms other than Linux/x86_64 this still uses errno, but other platforms are free to port their error handling to this new model. Differential Revision: http://llvm-reviews.chandlerc.com/D756 llvm-svn: 181436
This commit is contained in:
parent
4307282de6
commit
6f4be19b57
@ -69,8 +69,8 @@ static void MaybeOpenReportFile() {
|
||||
InternalScopedBuffer<char> report_path_full(4096);
|
||||
internal_snprintf(report_path_full.data(), report_path_full.size(),
|
||||
"%s.%d", report_path_prefix, GetPid());
|
||||
fd_t fd = OpenFile(report_path_full.data(), true);
|
||||
if (fd == kInvalidFd) {
|
||||
uptr openrv = OpenFile(report_path_full.data(), true);
|
||||
if (internal_iserror(openrv)) {
|
||||
report_fd = kStderrFd;
|
||||
log_to_file = false;
|
||||
Report("ERROR: Can't open file: %s\n", report_path_full.data());
|
||||
@ -80,7 +80,7 @@ static void MaybeOpenReportFile() {
|
||||
// We're in the child. Close the parent's log.
|
||||
internal_close(report_fd);
|
||||
}
|
||||
report_fd = fd;
|
||||
report_fd = openrv;
|
||||
report_fd_pid = GetPid();
|
||||
}
|
||||
|
||||
@ -108,8 +108,9 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||
*buff_size = 0;
|
||||
// The files we usually open are not seekable, so try different buffer sizes.
|
||||
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
|
||||
fd_t fd = OpenFile(file_name, /*write*/ false);
|
||||
if (fd == kInvalidFd) return 0;
|
||||
uptr openrv = OpenFile(file_name, /*write*/ false);
|
||||
if (internal_iserror(openrv)) return 0;
|
||||
fd_t fd = openrv;
|
||||
UnmapOrDie(*buff, *buff_size);
|
||||
*buff = (char*)MmapOrDie(size, __FUNCTION__);
|
||||
*buff_size = size;
|
||||
|
@ -115,7 +115,7 @@ void SetPrintfAndReportCallback(void (*callback)(const char *));
|
||||
// Can be used to prevent mixing error reports from different sanitizers.
|
||||
extern StaticSpinMutex CommonSanitizerReportMutex;
|
||||
|
||||
fd_t OpenFile(const char *filename, bool write);
|
||||
uptr OpenFile(const char *filename, bool write);
|
||||
// Opens the file 'file_name" and reads up to 'max_len' bytes.
|
||||
// The resulting buffer is mmaped and stored in '*buff'.
|
||||
// The size of the mmaped region is stored in '*buff_size',
|
||||
|
@ -273,10 +273,12 @@ extern "C" void* _ReturnAddress(void);
|
||||
# define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
|
||||
#endif
|
||||
|
||||
#define HANDLE_EINTR(res, f) { \
|
||||
do { \
|
||||
res = (f); \
|
||||
} while (res == -1 && errno == EINTR); \
|
||||
#define HANDLE_EINTR(res, f) \
|
||||
{ \
|
||||
int rverrno; \
|
||||
do { \
|
||||
res = (f); \
|
||||
} while (internal_iserror(res, &rverrno) && rverrno == EINTR); \
|
||||
}
|
||||
|
||||
#endif // SANITIZER_DEFS_H
|
||||
|
@ -53,42 +53,45 @@ bool mem_is_zero(const char *mem, uptr size);
|
||||
|
||||
|
||||
// Memory
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset);
|
||||
int internal_munmap(void *addr, uptr length);
|
||||
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset);
|
||||
uptr internal_munmap(void *addr, uptr length);
|
||||
|
||||
// I/O
|
||||
const fd_t kInvalidFd = -1;
|
||||
const fd_t kStdinFd = 0;
|
||||
const fd_t kStdoutFd = 1;
|
||||
const fd_t kStderrFd = 2;
|
||||
int internal_close(fd_t fd);
|
||||
uptr internal_close(fd_t fd);
|
||||
int internal_isatty(fd_t fd);
|
||||
|
||||
// Use __sanitizer::OpenFile() instead.
|
||||
fd_t internal_open(const char *filename, int flags);
|
||||
fd_t internal_open(const char *filename, int flags, u32 mode);
|
||||
uptr internal_open(const char *filename, int flags);
|
||||
uptr internal_open(const char *filename, int flags, u32 mode);
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count);
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count);
|
||||
|
||||
// OS
|
||||
uptr internal_filesize(fd_t fd); // -1 on error.
|
||||
int internal_stat(const char *path, void *buf);
|
||||
int internal_lstat(const char *path, void *buf);
|
||||
int internal_fstat(fd_t fd, void *buf);
|
||||
int internal_dup2(int oldfd, int newfd);
|
||||
uptr internal_stat(const char *path, void *buf);
|
||||
uptr internal_lstat(const char *path, void *buf);
|
||||
uptr internal_fstat(fd_t fd, void *buf);
|
||||
uptr internal_dup2(int oldfd, int newfd);
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
|
||||
int internal_unlink(const char *path);
|
||||
uptr internal_unlink(const char *path);
|
||||
void NORETURN internal__exit(int exitcode);
|
||||
OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence);
|
||||
uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
|
||||
|
||||
long internal_ptrace(int request, int pid, void *addr, void *data);
|
||||
int internal_waitpid(int pid, int *status, int options);
|
||||
int internal_getppid();
|
||||
uptr internal_ptrace(int request, int pid, void *addr, void *data);
|
||||
uptr internal_waitpid(int pid, int *status, int options);
|
||||
uptr internal_getppid();
|
||||
|
||||
// Threading
|
||||
int internal_sched_yield();
|
||||
uptr internal_sched_yield();
|
||||
|
||||
// Error handling
|
||||
bool internal_iserror(uptr retval, int *rverrno = 0);
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
|
@ -72,46 +72,52 @@ extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include "sanitizer_syscall_linux_x86_64.inc"
|
||||
#else
|
||||
#include "sanitizer_syscall_generic.inc"
|
||||
#endif
|
||||
|
||||
// --------------- sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
|
||||
return internal_syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
|
||||
#else
|
||||
return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
|
||||
return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
int internal_munmap(void *addr, uptr length) {
|
||||
return syscall(__NR_munmap, addr, length);
|
||||
uptr internal_munmap(void *addr, uptr length) {
|
||||
return internal_syscall(__NR_munmap, addr, length);
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
return syscall(__NR_close, fd);
|
||||
uptr internal_close(fd_t fd) {
|
||||
return internal_syscall(__NR_close, fd);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, int flags) {
|
||||
return syscall(__NR_open, filename, flags);
|
||||
uptr internal_open(const char *filename, int flags) {
|
||||
return internal_syscall(__NR_open, filename, flags);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, int flags, u32 mode) {
|
||||
return syscall(__NR_open, filename, flags, mode);
|
||||
uptr internal_open(const char *filename, int flags, u32 mode) {
|
||||
return internal_syscall(__NR_open, filename, flags, mode);
|
||||
}
|
||||
|
||||
fd_t OpenFile(const char *filename, bool write) {
|
||||
uptr OpenFile(const char *filename, bool write) {
|
||||
return internal_open(filename,
|
||||
write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
|
||||
}
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
||||
sptr res;
|
||||
HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
|
||||
HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
|
||||
return res;
|
||||
}
|
||||
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
sptr res;
|
||||
HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
|
||||
HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, buf, count));
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -135,34 +141,34 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int internal_stat(const char *path, void *buf) {
|
||||
uptr internal_stat(const char *path, void *buf) {
|
||||
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
return syscall(__NR_stat, path, buf);
|
||||
return internal_syscall(__NR_stat, path, buf);
|
||||
#else
|
||||
struct stat64 buf64;
|
||||
int res = syscall(__NR_stat64, path, &buf64);
|
||||
int res = internal_syscall(__NR_stat64, path, &buf64);
|
||||
stat64_to_stat(&buf64, (struct stat *)buf);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
int internal_lstat(const char *path, void *buf) {
|
||||
uptr internal_lstat(const char *path, void *buf) {
|
||||
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
return syscall(__NR_lstat, path, buf);
|
||||
return internal_syscall(__NR_lstat, path, buf);
|
||||
#else
|
||||
struct stat64 buf64;
|
||||
int res = syscall(__NR_lstat64, path, &buf64);
|
||||
int res = internal_syscall(__NR_lstat64, path, &buf64);
|
||||
stat64_to_stat(&buf64, (struct stat *)buf);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
int internal_fstat(fd_t fd, void *buf) {
|
||||
uptr internal_fstat(fd_t fd, void *buf) {
|
||||
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
return syscall(__NR_fstat, fd, buf);
|
||||
return internal_syscall(__NR_fstat, fd, buf);
|
||||
#else
|
||||
struct stat64 buf64;
|
||||
int res = syscall(__NR_fstat64, fd, &buf64);
|
||||
int res = internal_syscall(__NR_fstat64, fd, &buf64);
|
||||
stat64_to_stat(&buf64, (struct stat *)buf);
|
||||
return res;
|
||||
#endif
|
||||
@ -175,27 +181,32 @@ uptr internal_filesize(fd_t fd) {
|
||||
return (uptr)st.st_size;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
return syscall(__NR_dup2, oldfd, newfd);
|
||||
uptr internal_dup2(int oldfd, int newfd) {
|
||||
return internal_syscall(__NR_dup2, oldfd, newfd);
|
||||
}
|
||||
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
return (uptr)syscall(__NR_readlink, path, buf, bufsize);
|
||||
return internal_syscall(__NR_readlink, path, buf, bufsize);
|
||||
}
|
||||
|
||||
int internal_unlink(const char *path) {
|
||||
return syscall(__NR_unlink, path);
|
||||
uptr internal_unlink(const char *path) {
|
||||
return internal_syscall(__NR_unlink, path);
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
return syscall(__NR_sched_yield);
|
||||
uptr internal_sched_yield() {
|
||||
return internal_syscall(__NR_sched_yield);
|
||||
}
|
||||
|
||||
void internal__exit(int exitcode) {
|
||||
syscall(__NR_exit_group, exitcode);
|
||||
internal_syscall(__NR_exit_group, exitcode);
|
||||
Die(); // Unreachable.
|
||||
}
|
||||
|
||||
uptr internal_execve(const char *filename, char *const argv[],
|
||||
char *const envp[]) {
|
||||
return internal_syscall(__NR_execve, filename, argv, envp);
|
||||
}
|
||||
|
||||
// ----------------- sanitizer_common.h
|
||||
bool FileExists(const char *filename) {
|
||||
struct stat st;
|
||||
@ -206,12 +217,12 @@ bool FileExists(const char *filename) {
|
||||
}
|
||||
|
||||
uptr GetTid() {
|
||||
return syscall(__NR_gettid);
|
||||
return internal_syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
u64 NanoTime() {
|
||||
kernel_timeval tv;
|
||||
syscall(__NR_gettimeofday, &tv, 0);
|
||||
internal_syscall(__NR_gettimeofday, &tv, 0);
|
||||
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
|
||||
}
|
||||
|
||||
@ -349,8 +360,10 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
|
||||
void ReExec() {
|
||||
char **argv, **envp;
|
||||
GetArgsAndEnv(&argv, &envp);
|
||||
execve("/proc/self/exe", argv, envp);
|
||||
Printf("execve failed, errno %d\n", errno);
|
||||
uptr rv = internal_execve("/proc/self/exe", argv, envp);
|
||||
int rverrno;
|
||||
CHECK_EQ(internal_iserror(rv, &rverrno), true);
|
||||
Printf("execve failed, errno %d\n", rverrno);
|
||||
Die();
|
||||
}
|
||||
|
||||
@ -616,7 +629,7 @@ void BlockingMutex::Lock() {
|
||||
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
|
||||
return;
|
||||
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
|
||||
syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
|
||||
internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
|
||||
}
|
||||
|
||||
void BlockingMutex::Unlock() {
|
||||
@ -624,7 +637,7 @@ void BlockingMutex::Unlock() {
|
||||
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
|
||||
CHECK_NE(v, MtxUnlocked);
|
||||
if (v == MtxSleeping)
|
||||
syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
|
||||
internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void BlockingMutex::CheckLocked() {
|
||||
@ -644,33 +657,37 @@ struct linux_dirent {
|
||||
};
|
||||
|
||||
// Syscall wrappers.
|
||||
long internal_ptrace(int request, int pid, void *addr, void *data) {
|
||||
return syscall(__NR_ptrace, request, pid, addr, data);
|
||||
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
|
||||
return internal_syscall(__NR_ptrace, request, pid, addr, data);
|
||||
}
|
||||
|
||||
int internal_waitpid(int pid, int *status, int options) {
|
||||
return syscall(__NR_wait4, pid, status, options, NULL /* rusage */);
|
||||
uptr internal_waitpid(int pid, int *status, int options) {
|
||||
return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
|
||||
}
|
||||
|
||||
int internal_getppid() {
|
||||
return syscall(__NR_getppid);
|
||||
uptr internal_getpid() {
|
||||
return internal_syscall(__NR_getpid);
|
||||
}
|
||||
|
||||
int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
|
||||
return syscall(__NR_getdents, fd, dirp, count);
|
||||
uptr internal_getppid() {
|
||||
return internal_syscall(__NR_getppid);
|
||||
}
|
||||
|
||||
OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence) {
|
||||
return syscall(__NR_lseek, fd, offset, whence);
|
||||
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
|
||||
return internal_syscall(__NR_getdents, fd, dirp, count);
|
||||
}
|
||||
|
||||
int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
|
||||
return syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
|
||||
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
|
||||
return internal_syscall(__NR_lseek, fd, offset, whence);
|
||||
}
|
||||
|
||||
int internal_sigaltstack(const struct sigaltstack *ss,
|
||||
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
|
||||
return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
|
||||
uptr internal_sigaltstack(const struct sigaltstack *ss,
|
||||
struct sigaltstack *oss) {
|
||||
return syscall(__NR_sigaltstack, ss, oss);
|
||||
return internal_syscall(__NR_sigaltstack, ss, oss);
|
||||
}
|
||||
|
||||
// ThreadLister implementation.
|
||||
@ -684,12 +701,13 @@ ThreadLister::ThreadLister(int pid)
|
||||
char task_directory_path[80];
|
||||
internal_snprintf(task_directory_path, sizeof(task_directory_path),
|
||||
"/proc/%d/task/", pid);
|
||||
descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
|
||||
if (descriptor_ < 0) {
|
||||
uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
|
||||
if (internal_iserror(openrv)) {
|
||||
error_ = true;
|
||||
Report("Can't open /proc/%d/task for reading.\n", pid);
|
||||
} else {
|
||||
error_ = false;
|
||||
descriptor_ = openrv;
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,7 +747,7 @@ bool ThreadLister::GetDirectoryEntries() {
|
||||
bytes_read_ = internal_getdents(descriptor_,
|
||||
(struct linux_dirent *)buffer_.data(),
|
||||
buffer_.size());
|
||||
if (bytes_read_ < 0) {
|
||||
if (internal_iserror(bytes_read_)) {
|
||||
Report("Can't read directory entries from /proc/%d/task.\n", pid_);
|
||||
error_ = true;
|
||||
return false;
|
||||
|
@ -24,9 +24,10 @@ namespace __sanitizer {
|
||||
struct linux_dirent;
|
||||
|
||||
// Syscall wrappers.
|
||||
int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
|
||||
int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
|
||||
int internal_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
|
||||
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
|
||||
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
|
||||
uptr internal_sigaltstack(const struct sigaltstack* ss,
|
||||
struct sigaltstack* oss);
|
||||
|
||||
// This class reads thread IDs from /proc/<pid>/task using only syscalls.
|
||||
class ThreadLister {
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
#include "sanitizer_syscall_generic.inc"
|
||||
|
||||
// ---------------------- sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
@ -52,19 +54,19 @@ int internal_munmap(void *addr, uptr length) {
|
||||
return munmap(addr, length);
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
uptr internal_close(fd_t fd) {
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, int flags) {
|
||||
uptr internal_open(const char *filename, int flags) {
|
||||
return open(filename, flags);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, int flags, u32 mode) {
|
||||
uptr internal_open(const char *filename, int flags, u32 mode) {
|
||||
return open(filename, flags, mode);
|
||||
}
|
||||
|
||||
fd_t OpenFile(const char *filename, bool write) {
|
||||
uptr OpenFile(const char *filename, bool write) {
|
||||
return internal_open(filename,
|
||||
write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
|
||||
}
|
||||
@ -77,15 +79,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
return write(fd, buf, count);
|
||||
}
|
||||
|
||||
int internal_stat(const char *path, void *buf) {
|
||||
uptr internal_stat(const char *path, void *buf) {
|
||||
return stat(path, (struct stat *)buf);
|
||||
}
|
||||
|
||||
int internal_lstat(const char *path, void *buf) {
|
||||
uptr internal_lstat(const char *path, void *buf) {
|
||||
return lstat(path, (struct stat *)buf);
|
||||
}
|
||||
|
||||
int internal_fstat(fd_t fd, void *buf) {
|
||||
uptr internal_fstat(fd_t fd, void *buf) {
|
||||
return fstat(fd, (struct stat *)buf);
|
||||
}
|
||||
|
||||
@ -96,7 +98,7 @@ uptr internal_filesize(fd_t fd) {
|
||||
return (uptr)st.st_size;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
uptr internal_dup2(int oldfd, int newfd) {
|
||||
return dup2(oldfd, newfd);
|
||||
}
|
||||
|
||||
@ -104,7 +106,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
return readlink(path, buf, bufsize);
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
uptr internal_sched_yield() {
|
||||
return sched_yield();
|
||||
}
|
||||
|
||||
|
@ -57,10 +57,11 @@ uptr GetThreadSelf() {
|
||||
|
||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
size = RoundUpTo(size, GetPageSizeCached());
|
||||
void *res = internal_mmap(0, size,
|
||||
uptr res = internal_mmap(0, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (res == (void*)-1) {
|
||||
int reserrno;
|
||||
if (internal_iserror(res, &reserrno)) {
|
||||
static int recursion_count;
|
||||
if (recursion_count) {
|
||||
// The Report() and CHECK calls below may call mmap recursively and fail.
|
||||
@ -70,17 +71,17 @@ void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
}
|
||||
recursion_count++;
|
||||
Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
|
||||
SanitizerToolName, size, size, mem_type, errno);
|
||||
SanitizerToolName, size, size, mem_type, reserrno);
|
||||
DumpProcessMap();
|
||||
CHECK("unable to mmap" && 0);
|
||||
}
|
||||
return res;
|
||||
return (void *)res;
|
||||
}
|
||||
|
||||
void UnmapOrDie(void *addr, uptr size) {
|
||||
if (!addr || !size) return;
|
||||
int res = internal_munmap(addr, size);
|
||||
if (res != 0) {
|
||||
uptr res = internal_munmap(addr, size);
|
||||
if (internal_iserror(res)) {
|
||||
Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
|
||||
SanitizerToolName, size, size, addr);
|
||||
CHECK("unable to unmap" && 0);
|
||||
@ -89,39 +90,41 @@ void UnmapOrDie(void *addr, uptr size) {
|
||||
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
|
||||
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
|
||||
RoundUpTo(size, PageSize),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
if (p == (void*)-1)
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno))
|
||||
Report("ERROR: "
|
||||
"%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
|
||||
SanitizerToolName, size, size, fixed_addr, errno);
|
||||
return p;
|
||||
SanitizerToolName, size, size, fixed_addr, reserrno);
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
|
||||
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
|
||||
RoundUpTo(size, PageSize),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
|
||||
-1, 0);
|
||||
if (p == (void*)-1) {
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno)) {
|
||||
Report("ERROR:"
|
||||
" %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
|
||||
SanitizerToolName, size, size, fixed_addr, errno);
|
||||
SanitizerToolName, size, size, fixed_addr, reserrno);
|
||||
CHECK("unable to mmap" && 0);
|
||||
}
|
||||
return p;
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
void *Mprotect(uptr fixed_addr, uptr size) {
|
||||
return internal_mmap((void*)fixed_addr, size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
return (void *)internal_mmap((void*)fixed_addr, size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED |
|
||||
MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
|
||||
void FlushUnneededShadowMemory(uptr addr, uptr size) {
|
||||
@ -129,14 +132,15 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
|
||||
}
|
||||
|
||||
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
|
||||
fd_t fd = OpenFile(file_name, false);
|
||||
CHECK_NE(fd, kInvalidFd);
|
||||
uptr openrv = OpenFile(file_name, false);
|
||||
CHECK(!internal_iserror(openrv));
|
||||
fd_t fd = openrv;
|
||||
uptr fsize = internal_filesize(fd);
|
||||
CHECK_NE(fsize, (uptr)-1);
|
||||
CHECK_GT(fsize, 0);
|
||||
*buff_size = RoundUpTo(fsize, GetPageSizeCached());
|
||||
void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
return (map == MAP_FAILED) ? 0 : map;
|
||||
uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
return internal_iserror(map) ? 0 : (void *)map;
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,23 +101,26 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
|
||||
// usually small.
|
||||
if (suspended_threads_list_.Contains(thread_id))
|
||||
return false;
|
||||
if (internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL) != 0) {
|
||||
int pterrno;
|
||||
if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL),
|
||||
&pterrno)) {
|
||||
// Either the thread is dead, or something prevented us from attaching.
|
||||
// Log this event and move on.
|
||||
Report("Could not attach to thread %d (errno %d).\n", thread_id, errno);
|
||||
Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
|
||||
return false;
|
||||
} else {
|
||||
if (SanitizerVerbosity > 0)
|
||||
Report("Attached to thread %d.\n", thread_id);
|
||||
// The thread is not guaranteed to stop before ptrace returns, so we must
|
||||
// wait on it.
|
||||
int waitpid_status;
|
||||
uptr waitpid_status;
|
||||
HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __WALL));
|
||||
if (waitpid_status < 0) {
|
||||
int wperrno;
|
||||
if (internal_iserror(waitpid_status, &wperrno)) {
|
||||
// Got a ECHILD error. I don't think this situation is possible, but it
|
||||
// doesn't hurt to report it.
|
||||
Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
|
||||
errno);
|
||||
wperrno);
|
||||
internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
|
||||
return false;
|
||||
}
|
||||
@ -129,14 +132,16 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
|
||||
void ThreadSuspender::ResumeAllThreads() {
|
||||
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
|
||||
pid_t tid = suspended_threads_list_.GetThreadID(i);
|
||||
if (internal_ptrace(PTRACE_DETACH, tid, NULL, NULL) == 0) {
|
||||
int pterrno;
|
||||
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
|
||||
&pterrno)) {
|
||||
if (SanitizerVerbosity > 0)
|
||||
Report("Detached from thread %d.\n", tid);
|
||||
} else {
|
||||
// Either the thread is dead, or we are already detached.
|
||||
// The latter case is possible, for instance, if this function was called
|
||||
// from a signal handler.
|
||||
Report("Could not detach from thread %d (errno %d).\n", tid, errno);
|
||||
Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,9 +335,10 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
|
||||
// must avoid using errno while the tracer thread is running.
|
||||
// At this point, any signal will either be blocked or kill us, so waitpid
|
||||
// should never return (and set errno) while the tracer thread is alive.
|
||||
int waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
|
||||
if (waitpid_status < 0)
|
||||
Report("Waiting on the tracer thread failed (errno %d).\n", errno);
|
||||
uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
|
||||
int wperrno;
|
||||
if (internal_iserror(waitpid_status, &wperrno))
|
||||
Report("Waiting on the tracer thread failed (errno %d).\n", wperrno);
|
||||
}
|
||||
// Restore the dumpable flag.
|
||||
if (!process_was_dumpable)
|
||||
@ -358,9 +364,11 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
|
||||
uptr *sp) const {
|
||||
pid_t tid = GetThreadID(index);
|
||||
regs_struct regs;
|
||||
if (internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s) != 0) {
|
||||
int pterrno;
|
||||
if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s),
|
||||
&pterrno)) {
|
||||
Report("Could not get registers from thread %d (errno %d).\n",
|
||||
tid, errno);
|
||||
tid, pterrno);
|
||||
return -1;
|
||||
}
|
||||
#if defined(__arm__)
|
||||
|
@ -148,7 +148,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
||||
// First module is the binary itself.
|
||||
uptr module_name_len = internal_readlink(
|
||||
"/proc/self/exe", module_name.data(), module_name.size());
|
||||
if (module_name_len == (uptr)-1) {
|
||||
if (internal_iserror(module_name_len)) {
|
||||
// We can't read /proc/self/exe for some reason, assume the name of the
|
||||
// binary is unknown.
|
||||
module_name_len = internal_snprintf(module_name.data(),
|
||||
|
@ -0,0 +1,24 @@
|
||||
//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Generic implementations of internal_syscall and internal_iserror.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define internal_syscall syscall
|
||||
|
||||
bool internal_iserror(uptr retval, int *rverrno) {
|
||||
if (retval == (uptr)-1) {
|
||||
if (rverrno)
|
||||
*rverrno = errno;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementations of internal_syscall and internal_iserror for Linux/x86_64.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static uptr internal_syscall(u64 nr) {
|
||||
u64 retval;
|
||||
asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1) {
|
||||
u64 retval;
|
||||
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
|
||||
"rcx", "r11");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
|
||||
u64 retval;
|
||||
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
|
||||
"S"((u64)arg2) : "rcx", "r11");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
|
||||
u64 retval;
|
||||
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
|
||||
"S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
u64 retval;
|
||||
asm volatile("mov %5, %%r10;"
|
||||
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
|
||||
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
|
||||
"rcx", "r11", "r10");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
|
||||
T5 arg5) {
|
||||
u64 retval;
|
||||
asm volatile("mov %5, %%r10;"
|
||||
"mov %6, %%r8;"
|
||||
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
|
||||
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
|
||||
"rcx", "r11", "r10", "r8");
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
|
||||
T5 arg5, T6 arg6) {
|
||||
u64 retval;
|
||||
asm volatile("mov %5, %%r10;"
|
||||
"mov %6, %%r8;"
|
||||
"mov %7, %%r9;"
|
||||
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
|
||||
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
|
||||
"r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9");
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool internal_iserror(uptr retval, int *rverrno) {
|
||||
if (retval >= (uptr)-4095) {
|
||||
if (rverrno)
|
||||
*rverrno = -retval;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -29,6 +29,8 @@
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
#include "sanitizer_syscall_generic.inc"
|
||||
|
||||
// --------------------- sanitizer_common.h
|
||||
uptr GetPageSize() {
|
||||
return 1U << 14; // FIXME: is this configurable?
|
||||
@ -217,7 +219,7 @@ int internal_munmap(void *addr, uptr length) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
uptr internal_close(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -233,7 +235,7 @@ fd_t internal_open(const char *filename, int flags, u32 mode) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
fd_t OpenFile(const char *filename, bool write) {
|
||||
uptr OpenFile(const char *filename, bool write) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -253,15 +255,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int internal_stat(const char *path, void *buf) {
|
||||
uptr internal_stat(const char *path, void *buf) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int internal_lstat(const char *path, void *buf) {
|
||||
uptr internal_lstat(const char *path, void *buf) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int internal_fstat(fd_t fd, void *buf) {
|
||||
uptr internal_fstat(fd_t fd, void *buf) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -269,7 +271,7 @@ uptr internal_filesize(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
uptr internal_dup2(int oldfd, int newfd) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -277,7 +279,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
uptr internal_sched_yield() {
|
||||
Sleep(0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -74,29 +74,31 @@ TEST(SanitizerCommon, FileOps) {
|
||||
internal_snprintf(temp_filename, sizeof(temp_filename),
|
||||
"/tmp/sanitizer_common.tmp.%d", uid);
|
||||
#endif
|
||||
fd_t fd = OpenFile(temp_filename, true);
|
||||
EXPECT_NE(fd, kInvalidFd);
|
||||
uptr openrv = OpenFile(temp_filename, true);
|
||||
EXPECT_EQ(false, internal_iserror(openrv));
|
||||
fd_t fd = openrv;
|
||||
EXPECT_EQ(len1, internal_write(fd, str1, len1));
|
||||
EXPECT_EQ(len2, internal_write(fd, str2, len2));
|
||||
internal_close(fd);
|
||||
|
||||
fd = OpenFile(temp_filename, false);
|
||||
EXPECT_NE(fd, kInvalidFd);
|
||||
openrv = OpenFile(temp_filename, false);
|
||||
EXPECT_EQ(false, internal_iserror(openrv));
|
||||
fd = openrv;
|
||||
uptr fsize = internal_filesize(fd);
|
||||
EXPECT_EQ(len1 + len2, fsize);
|
||||
|
||||
#if SANITIZER_TEST_HAS_STAT_H
|
||||
struct stat st1, st2, st3;
|
||||
EXPECT_EQ(0, internal_stat(temp_filename, &st1));
|
||||
EXPECT_EQ(0, internal_lstat(temp_filename, &st2));
|
||||
EXPECT_EQ(0, internal_fstat(fd, &st3));
|
||||
EXPECT_EQ(0u, internal_stat(temp_filename, &st1));
|
||||
EXPECT_EQ(0u, internal_lstat(temp_filename, &st2));
|
||||
EXPECT_EQ(0u, internal_fstat(fd, &st3));
|
||||
EXPECT_EQ(fsize, (uptr)st3.st_size);
|
||||
|
||||
// Verify that internal_fstat does not write beyond the end of the supplied
|
||||
// buffer.
|
||||
struct stat_and_more sam;
|
||||
memset(&sam, 0xAB, sizeof(sam));
|
||||
EXPECT_EQ(0, internal_fstat(fd, &sam.st));
|
||||
EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
|
||||
EXPECT_EQ(0xAB, sam.z);
|
||||
EXPECT_NE(0xAB, sam.st.st_size);
|
||||
EXPECT_NE(0, sam.st.st_size);
|
||||
|
@ -178,9 +178,10 @@ static void MapRodata() {
|
||||
char filename[256];
|
||||
internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%u",
|
||||
tmpdir, GetPid());
|
||||
fd_t fd = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd == kInvalidFd)
|
||||
uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (internal_iserror(openrv))
|
||||
return;
|
||||
fd_t fd = openrv;
|
||||
// Fill the file with kShadowRodata.
|
||||
const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
|
||||
InternalScopedBuffer<u64> marker(kMarkerSize);
|
||||
@ -188,9 +189,9 @@ static void MapRodata() {
|
||||
*p = kShadowRodata;
|
||||
internal_write(fd, marker.data(), marker.size());
|
||||
// Map the file into memory.
|
||||
void *page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
|
||||
if (page == MAP_FAILED) {
|
||||
uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
|
||||
if (internal_iserror(page)) {
|
||||
internal_close(fd);
|
||||
internal_unlink(filename);
|
||||
return;
|
||||
|
@ -121,10 +121,12 @@ static void BackgroundThread(void *arg) {
|
||||
InternalScopedBuffer<char> filename(4096);
|
||||
internal_snprintf(filename.data(), filename.size(), "%s.%d",
|
||||
flags()->profile_memory, GetPid());
|
||||
mprof_fd = OpenFile(filename.data(), true);
|
||||
if (mprof_fd == kInvalidFd) {
|
||||
uptr openrv = OpenFile(filename.data(), true);
|
||||
if (internal_iserror(openrv)) {
|
||||
Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
|
||||
&filename[0]);
|
||||
} else {
|
||||
mprof_fd = openrv;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,12 +38,13 @@ static char *ReadFile(const char *filename) {
|
||||
internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
|
||||
else
|
||||
internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
|
||||
fd_t fd = OpenFile(tmp.data(), false);
|
||||
if (fd == kInvalidFd) {
|
||||
uptr openrv = OpenFile(tmp.data(), false);
|
||||
if (internal_iserror(openrv)) {
|
||||
Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
|
||||
tmp.data());
|
||||
Die();
|
||||
}
|
||||
fd_t fd = openrv;
|
||||
const uptr fsize = internal_filesize(fd);
|
||||
if (fsize == (uptr)-1) {
|
||||
Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
|
||||
|
Loading…
x
Reference in New Issue
Block a user