asan_linux.cc revision d55f5f8c413622db4bd28b5cca9bfeb4d61564e0
11e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===-- asan_linux.cc -----------------------------------------------------===//
21e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
31e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//                     The LLVM Compiler Infrastructure
41e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
51e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is distributed under the University of Illinois Open Source
61e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// License. See LICENSE.TXT for details.
71e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
81e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
91e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
101e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker.
111e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
121e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Linux-specific details.
131e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
14d6567c5166412f6acdde851e767c26f332d51d3dKostya Serebryany#ifdef __linux__
151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
16df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany#include "asan_interceptors.h"
171e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_internal.h"
18d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany#include "asan_lock.h"
19df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany#include "asan_procmaps.h"
20c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany#include "asan_thread.h"
211e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
22c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany#include <sys/time.h>
23c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany#include <sys/resource.h>
241e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include <sys/mman.h>
251e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include <sys/syscall.h>
26de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany#include <sys/types.h>
27de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany#include <fcntl.h>
28efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany#include <link.h>
29c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany#include <pthread.h>
30df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany#include <stdio.h>
311e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include <unistd.h>
321e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
339107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#ifndef ANDROID
349107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany// FIXME: where to get ucontext on Android?
359107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#include <sys/ucontext.h>
369107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#endif
379107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany
381e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanynamespace __asan {
391e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
401e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanyvoid *AsanDoesNotSupportStaticLinkage() {
411e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  // This will fail to link with -static.
42efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  return &_DYNAMIC;  // defined in link.h
431e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
441e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
459107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryanyvoid GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) {
469107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#ifdef ANDROID
479107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *pc = *sp = *bp = 0;
489107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#elif defined(__arm__)
499107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  ucontext_t *ucontext = (ucontext_t*)context;
509107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *pc = ucontext->uc_mcontext.arm_pc;
519107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *bp = ucontext->uc_mcontext.arm_fp;
529107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *sp = ucontext->uc_mcontext.arm_sp;
539107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany# elif defined(__x86_64__)
549107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  ucontext_t *ucontext = (ucontext_t*)context;
559107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
569107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
579107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
589107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany# elif defined(__i386__)
599107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  ucontext_t *ucontext = (ucontext_t*)context;
609107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
619107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
629107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
639107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#else
649107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany# error "Unsupported arch"
659107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany#endif
669107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany}
679107c26bd88fc9cf44a2cd7d6967eb830ac63be3Kostya Serebryany
684803ab90ead451b55a5833f0fd38b10fd1fc83ebKostya Serebryanybool AsanInterceptsSignal(int signum) {
694803ab90ead451b55a5833f0fd38b10fd1fc83ebKostya Serebryany  return signum == SIGSEGV && FLAG_handle_segv;
704803ab90ead451b55a5833f0fd38b10fd1fc83ebKostya Serebryany}
714803ab90ead451b55a5833f0fd38b10fd1fc83ebKostya Serebryany
72a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryanystatic void *asan_mmap(void *addr, size_t length, int prot, int flags,
731e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany                int fd, uint64_t offset) {
741e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany# if __WORDSIZE == 64
75de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
761e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany# else
77de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
781e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany# endif
791e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
801e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
81de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryanyvoid *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
82de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  size = RoundUpTo(size, kPageSize);
83de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  void *res = asan_mmap(0, size,
84de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany                        PROT_READ | PROT_WRITE,
85de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany                        MAP_PRIVATE | MAP_ANON, -1, 0);
86de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  if (res == (void*)-1) {
87de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany    OutOfMemoryMessageAndDie(mem_type, size);
88de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  }
89de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  return res;
90de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany}
91de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany
92a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryanyvoid *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
93a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany  return asan_mmap((void*)fixed_addr, size,
94a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   PROT_READ | PROT_WRITE,
95a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
96a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   0, 0);
97a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany}
98a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany
99a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryanyvoid *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) {
100a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany  return asan_mmap((void*)fixed_addr, size,
101a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   PROT_READ | PROT_WRITE,
102a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   MAP_PRIVATE | MAP_ANON | MAP_FIXED,
103a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   0, 0);
104a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany}
105a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany
106a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryanyvoid *AsanMprotect(uintptr_t fixed_addr, size_t size) {
107a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany  return asan_mmap((void*)fixed_addr, size,
108a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   PROT_NONE,
109a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
110a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany                   0, 0);
111a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany}
112a874fe5b5d67152e4e737498d532eec80940bdcdKostya Serebryany
113de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryanyvoid AsanUnmapOrDie(void *addr, size_t size) {
114de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  if (!addr || !size) return;
115de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  int res = syscall(__NR_munmap, addr, size);
116de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  if (res != 0) {
117de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany    Report("Failed to unmap\n");
1180ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryany    AsanDie();
119de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  }
120de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany}
121de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany
1220ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryanysize_t AsanWrite(int fd, const void *buf, size_t count) {
1230ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryany  return (size_t)syscall(__NR_write, fd, buf, count);
124de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany}
125de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany
126de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryanyint AsanOpenReadonly(const char* filename) {
127de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  return open(filename, O_RDONLY);
128de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany}
129de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany
1300ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryanysize_t AsanRead(int fd, void *buf, size_t count) {
1310ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryany  return (size_t)syscall(__NR_read, fd, buf, count);
132de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany}
133de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany
134de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryanyint AsanClose(int fd) {
135de496f451bce322b6cde100456591f1f50ab3477Kostya Serebryany  return close(fd);
1361e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
1371e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
138df499b44de81fc757a789878f07fcaf19ebb0016Kostya SerebryanyAsanProcMaps::AsanProcMaps() {
139df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  proc_self_maps_buff_len_ =
140df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
141df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany                       &proc_self_maps_buff_mmaped_size_, 1 << 20);
142df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  CHECK(proc_self_maps_buff_len_ > 0);
143df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
144df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  Reset();
145df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany}
146df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany
147df499b44de81fc757a789878f07fcaf19ebb0016Kostya SerebryanyAsanProcMaps::~AsanProcMaps() {
148df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
149df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany}
150df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany
151df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryanyvoid AsanProcMaps::Reset() {
152df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  current_ = proc_self_maps_buff_;
153df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany}
154df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany
155efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryanybool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
156efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany                        uintptr_t *offset, char filename[],
157df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany                        size_t filename_size) {
158df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
159df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  if (current_ >= last) return false;
160df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  int consumed = 0;
161df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  char flags[10];
162df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  int major, minor;
163efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  uintptr_t inode;
164df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
165df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  if (next_line == NULL)
166df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    next_line = last;
167df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  if (SScanf(current_,
168efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany             "%lx-%lx %4s %lx %x:%x %ld %n",
169df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany             start, end, flags, offset, &major, &minor,
170df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany             &inode, &consumed) != 7)
171df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    return false;
172df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  current_ += consumed;
173df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  // Skip spaces.
174df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  while (current_ < next_line && *current_ == ' ')
175df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    current_++;
176df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  // Fill in the filename.
177df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  size_t i = 0;
178df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  while (current_ < next_line) {
179df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    if (filename && i < filename_size - 1)
180df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany      filename[i++] = *current_;
181df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    current_++;
182df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  }
183df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  if (filename && i < filename_size)
184df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany    filename[i] = 0;
185df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  current_ = next_line + 1;
186df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany  return true;
187df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany}
188df499b44de81fc757a789878f07fcaf19ebb0016Kostya Serebryany
189efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryanystruct DlIterateData {
190efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  int count;
191efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  uintptr_t addr;
192efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  uintptr_t offset;
193efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  char *filename;
194efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  size_t filename_size;
195efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany};
196efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany
197efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryanystatic int dl_iterate_phdr_callback(struct dl_phdr_info *info,
198efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany                                    size_t size, void *raw_data) {
199efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  DlIterateData *data = (DlIterateData*)raw_data;
200efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  int count = data->count++;
201efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  if (info->dlpi_addr > data->addr)
202efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    return 0;
203efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  if (count == 0) {
204efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    // The first item (the main executable) does not have a so name,
205efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    // but we can just read it from /proc/self/exe.
2060ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryany    size_t path_len = readlink("/proc/self/exe",
2070ecf5eb729dd81a43f8585cb438d3cb2a35899edKostya Serebryany                               data->filename, data->filename_size - 1);
208efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    data->filename[path_len] = 0;
209efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  } else {
210efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    CHECK(info->dlpi_name);
211efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    real_strncpy(data->filename, info->dlpi_name, data->filename_size);
212efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  }
213efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  data->offset = data->addr - info->dlpi_addr;
214efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  return 1;
215efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany}
216efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany
217efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany// Gets the object name and the offset using dl_iterate_phdr.
218efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryanybool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
219efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany                                          char filename[],
220efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany                                          size_t filename_size) {
221efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  DlIterateData data;
222efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  data.count = 0;
223efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  data.addr = addr;
224efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  data.filename = filename;
225efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  data.filename_size = filename_size;
226efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) {
227efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    *offset = data.offset;
228efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    return true;
229efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  }
230efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany  return false;
231efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany}
232efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany
233c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryanyvoid AsanThread::SetThreadStackTopAndBottom() {
234c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  if (tid() == 0) {
235c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    // This is the main thread. Libpthread may not be initialized yet.
236c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    struct rlimit rl;
237c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);
238c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany
239c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    // Find the mapping that contains a stack variable.
240c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    AsanProcMaps proc_maps;
241efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    uintptr_t start, end, offset;
242efb3fa36cf421c346e8e54054cdae4fd798edab7Kostya Serebryany    uintptr_t prev_end = 0;
243c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
244c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany      if ((uintptr_t)&rl < end)
245c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany        break;
246c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany      prev_end = end;
247c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    }
248c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end);
249c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany
250c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    // Get stacksize from rlimit, but clip it so that it does not overlap
251c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    // with other mappings.
252c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    size_t stacksize = rl.rlim_cur;
253c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    if (stacksize > end - prev_end)
254c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany      stacksize = end - prev_end;
255c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    if (stacksize > kMaxThreadStackSize)
256c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany      stacksize = kMaxThreadStackSize;
257c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    stack_top_ = end;
258c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    stack_bottom_ = end - stacksize;
259c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    CHECK(AddrIsInStack((uintptr_t)&rl));
260c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    return;
261c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  }
262c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  pthread_attr_t attr;
263c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
264c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  size_t stacksize = 0;
265c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  void *stackaddr = NULL;
266c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
267c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  pthread_attr_destroy(&attr);
268c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany
269c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  stack_top_ = (uintptr_t)stackaddr + stacksize;
270c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  stack_bottom_ = (uintptr_t)stackaddr;
271c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  // When running with unlimited stack size, we still want to set some limit.
272c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  // The unlimited stack size is caused by 'ulimit -s unlimited'.
273c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
274c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  if (stacksize > kMaxThreadStackSize) {
275c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany    stack_bottom_ = stack_top_ - kMaxThreadStackSize;
276c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  }
277c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany  CHECK(AddrIsInStack((uintptr_t)&attr));
278c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany}
279c549dd7b5fa5fb97270f57067797224cee0429f2Kostya Serebryany
280d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya SerebryanyAsanLock::AsanLock(LinkerInitialized) {
281d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  // We assume that pthread_mutex_t initialized to all zeroes is a valid
282d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
283d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  // a gcc warning:
284d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  // extended initializer lists only available with -std=c++0x or -std=gnu++0x
285d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany}
286d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany
287d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryanyvoid AsanLock::Lock() {
288d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
289d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
290d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  CHECK(!owner_);
291d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  owner_ = (uintptr_t)pthread_self();
292d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany}
293d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany
294d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryanyvoid AsanLock::Unlock() {
295d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  CHECK(owner_ == (uintptr_t)pthread_self());
296d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  owner_ = 0;
297d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany  pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
298d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany}
299d55f5f8c413622db4bd28b5cca9bfeb4d61564e0Kostya Serebryany
3001e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}  // namespace __asan
301d6567c5166412f6acdde851e767c26f332d51d3dKostya Serebryany
302d6567c5166412f6acdde851e767c26f332d51d3dKostya Serebryany#endif  // __linux__
303