blob: 5f0d781a6fba20f6590982ac44c4278525c76e95 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBRARY_H__
#define LIBRARY_H__
#include <elf.h>
#include <functional>
#include <map>
#include <set>
#include <string>
#include <string.h>
#include <sys/mman.h>
#include "maps.h"
#if defined(__x86_64__)
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Sym Elf_Sym;
typedef Elf64_Addr Elf_Addr;
#elif defined(__i386__)
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Sym Elf_Sym;
typedef Elf32_Addr Elf_Addr;
#else
#error Unsupported target platform
#endif
struct SyscallTable;
namespace playground {
class Library {
friend class Maps;
public:
typedef Maps::string string;
Library();
~Library();
void setLibraryInfo(Maps* maps) {
if (!maps_) {
maps_ = maps;
}
}
void addMemoryRange(void* start, void* stop, Elf_Addr offset,
int prot, int isVDSO) {
isVDSO_ = isVDSO;
RangeMap::const_iterator iter = memory_ranges_.find(offset);
if (iter != memory_ranges_.end()) {
// It is possible to have overlapping mappings. This is particularly
// likely to happen with very small programs or libraries. If it does
// happen, we really only care about the text segment. Look for a
// mapping that is mapped executable.
if ((prot & PROT_EXEC) == 0) {
return;
}
}
memory_ranges_.insert(std::make_pair(offset, Range(start, stop, prot)));
}
char *get(Elf_Addr offset, char *buf, size_t len);
string get(Elf_Addr offset);
char *getOriginal(Elf_Addr offset, char *buf, size_t len);
string getOriginal(Elf_Addr offset);
template<class T>T* get(Elf_Addr offset, T* t) {
if (!valid_) {
memset(t, 0, sizeof(T));
return NULL;
}
return reinterpret_cast<T *>(get(offset, reinterpret_cast<char *>(t),
sizeof(T)));
}
template<class T>T* getOriginal(Elf_Addr offset, T* t) {
if (!valid_) {
memset(t, 0, sizeof(T));
return NULL;
}
return reinterpret_cast<T *>(getOriginal(offset,
reinterpret_cast<char *>(t),
sizeof(T)));
}
template<class T>bool set(void *addr, T* value) {
if (!valid_) {
return false;
}
*reinterpret_cast<T *>(addr) = *value;
return true;
}
template<class T>bool set(Elf_Addr offset, T* value) {
if (!valid_) {
return false;
}
RangeMap::const_iterator iter = memory_ranges_.lower_bound(offset);
if (iter == memory_ranges_.end()) {
return false;
}
offset -= iter->first;
if (offset >
reinterpret_cast<char *>(iter->second.stop) -
reinterpret_cast<char *>(iter->second.start) -
sizeof(T)) {
return false;
}
*reinterpret_cast<T *>(
reinterpret_cast<char *>(iter->second.start) + offset) = *value;
return true;
}
bool parseElf();
const Elf_Ehdr* getEhdr();
const Elf_Shdr* getSection(const string& section);
void makeWritable(bool state) const;
void patchSystemCalls();
void patchSystemCallsInRange(char* start, char* stop,
char** extraSpace, int* extraLength);
bool isVDSO() const { return isVDSO_; }
protected:
bool parseSymbols();
private:
class GreaterThan : public std::binary_function<Elf_Addr, Elf_Addr, bool> {
// We create the RangeMap with a GreaterThan rather than the default
// comparator, as that allows us to use lower_bound() to find memory
// mappings.
public:
bool operator() (Elf_Addr s1, Elf_Addr s2) const {
return s1 > s2;
}
};
struct Range {
Range(void* start, void* stop, int prot) :
start(start), stop(stop), prot(prot) { }
void* start;
void* stop;
int prot;
};
typedef std::map<Elf_Addr, Range, GreaterThan,
SystemAllocator<std::pair<const Elf_Addr,
Range> > > RangeMap;
typedef std::map<string, std::pair<int, Elf_Shdr>, std::less<string>,
SystemAllocator<std::pair<const string,
std::pair<int, Elf_Shdr> > > >
SectionTable;
typedef std::map<string, Elf_Sym, std::less<string>,
SystemAllocator<std::pair<const string,
Elf_Sym> > > SymbolTable;
char* getBytes(char* dst, const char* src, ssize_t len);
static bool isSafeInsn(unsigned short insn);
static char* getScratchSpace(const Maps* maps, char* near, int needed,
char** extraSpace, int* extraLength);
static void patchSystemCallsInFunction(const Maps* maps, int vsys_offset,
char* start, char* end,
char** extraSpace, int* extraLength);
int patchVSystemCalls();
void patchVDSO(char** extraSpace, int* extraLength);
RangeMap memory_ranges_;
bool valid_;
bool isVDSO_;
char* asr_offset_;
int vsys_offset_;
Elf_Ehdr ehdr_;
SectionTable section_table_;
SymbolTable symbols_;
char* image_;
size_t image_size_;
Maps* maps_;
static char* __kernel_vsyscall;
static char* __kernel_sigreturn;
static char* __kernel_rt_sigreturn;
};
} // namespace
#endif // LIBRARY_H__