blob: 118038834604650ca188f1d9a47d06ddafe0c48d [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#ifndef RR_THREADDB_H_
#define RR_THREADDB_H_
#include "remote_ptr.h"
#include <map>
#include <set>
#include <string>
extern "C" {
#include <thread_db.h>
}
namespace rr {
class ThreadGroup;
class ThreadDb;
}
// This is declared as incomplete by the libthread_db API and is
// expected to be defined by the API user. We define it to hold just
// pointers back to the thread group and to the ThreadDb object.
struct ps_prochandle {
rr::ThreadGroup* thread_group;
rr::ThreadDb* db;
pid_t tgid;
};
namespace rr {
/**
* This provides an interface to libthread_db.so to help with TLS
* lookup. In principle there could be one instance per process, but we only
* support one instance for the GdbServer's target process.
*
* The overall approach is that a libthread_db.so is loaded into rr
* when this class is initialized (see |load_library|). This provides
* the GdbServer with a list of symbols whose addresses might be
* needed in order to resolve TLS accesses.
*
* Then, when the address of a TLS variable is requested by the
* debugger, GdbServer calls |get_tls_address|. This uses the
* libthread_db "new" function ("td_ta_new"); if this succeeds then
* ThreadDb proceeds to use other APIs to find the desired address.
*
* ThreadDb works on a callback model, using symbols provided by the
* hosting application. These are all defined in ThreadDb.cc.
*/
class ThreadDb {
public:
explicit ThreadDb(pid_t tgid);
~ThreadDb();
/**
* Return a set of the names of all the symbols that might be needed
* by libthread_db. Also clears the current mapping of symbol names
* to addresses.
*/
const std::set<std::string> get_symbols_and_clear_map(
ThreadGroup* thread_group);
/**
* Note that the symbol |name| has the given address.
*/
void register_symbol(const std::string& name, remote_ptr<void> address);
/**
* Look up the symbol |name|. If found, set |*address| and return
* true. If not found, return false.
*/
bool query_symbol(const char* name, remote_ptr<void>* address);
/**
* Look up a TLS address for thread |rec_tid|. |offset| and
* |load_module| are as specified in the qGetTLSAddr packet. If the
* address is found, set |*result| and return true. Otherwise,
* return false.
*/
bool get_tls_address(ThreadGroup* thread_group, pid_t rec_tid, size_t offset,
remote_ptr<void> load_module, remote_ptr<void>* result);
private:
bool load_library();
bool initialize();
ThreadDb(ThreadDb&) = delete;
ThreadDb operator=(ThreadDb&) = delete;
// True if libthread_db has been successfully initialized, if all
// the functions exist, and if the list of needed symbol names has
// been computed.
bool loaded;
// The external handle for this thread, for libthread_db.
struct ps_prochandle prochandle;
// The internal handle for this thread, from libthread_db.
td_thragent_t* internal_handle;
// Handle on the libthread_db library itself.
void* thread_db_library;
// Functions from libthread_db.
decltype(td_ta_delete)* td_ta_delete_fn;
decltype(td_thr_tls_get_addr)* td_thr_tls_get_addr_fn;
decltype(td_ta_map_lwp2thr)* td_ta_map_lwp2thr_fn;
decltype(td_ta_new)* td_ta_new_fn;
// Set of all symbol names.
std::set<std::string> symbol_names;
// Map from symbol names to addresses.
std::map<std::string, remote_ptr<void>> symbols;
};
} // namespace rr
#endif // RR_THREADDB_H_