update to ida 7.6, add builds
This commit is contained in:
88
idasdk76/dbg/linux/android.cpp
Normal file
88
idasdk76/dbg/linux/android.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Android specific functions.
|
||||
*/
|
||||
|
||||
// r_brk():
|
||||
// B0003050 70 47 BX LR
|
||||
static const uchar bxlr_thumb[] = { 0x70, 0x47 };
|
||||
|
||||
#define LINKER "/system/bin/linker"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// on android /system/bin/linker comes without any symbols.
|
||||
// Since there is no other way, we scan the data segment for
|
||||
// dcd 1, ?, r_brk, 0, 0
|
||||
// r_debug is located very close to the beginning of the data segment,
|
||||
// we should find it fine. In any case, we check only the first 4KB.
|
||||
bool linux_debmod_t::add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching)
|
||||
{
|
||||
// find read/writable linker memory range
|
||||
meminfo_vec_t::const_iterator p;
|
||||
ea_t linker_base = BADADDR;
|
||||
for ( p=miv.begin(); p != miv.end(); ++p )
|
||||
{
|
||||
if ( p->name == LINKER )
|
||||
{
|
||||
if ( linker_base == BADADDR )
|
||||
linker_base = p->start_ea;
|
||||
// assume the data segment to be readable and writable
|
||||
if ( (p->perm & 6) == 6 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( p == miv.end() )
|
||||
{
|
||||
msg("Failed to find data segment of " LINKER "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// read max 2KB
|
||||
uint32 buf[2048];
|
||||
int nbytes = qmin(p->size(), sizeof(buf));
|
||||
ea_t dataseg = p->start_ea;
|
||||
nbytes = dbg_read_memory(dataseg, buf, nbytes, NULL);
|
||||
|
||||
uint32 *ptr = buf;
|
||||
for ( int i=0; i < nbytes/4-5; i++, ptr++ )
|
||||
{
|
||||
if ( ptr[0] == 1 // version
|
||||
&& (attaching || ptr[1] == 0) // r_map, 0 at the beginning
|
||||
&& (ptr[2] & 1) != 0 && ptr[2] < dataseg // r_brk (Thumb pointer)
|
||||
&& (attaching || ptr[3] == 0) // r_state: RT_CONSISTENT
|
||||
&& ptr[4] == 0 ) // linker baseaddr: always zero?
|
||||
{
|
||||
ea_t r_brk = ptr[2] & ~1;
|
||||
// check if linker is not relocated yet
|
||||
if ( r_brk < linker_base )
|
||||
r_brk += linker_base; // adjust address
|
||||
uchar opcode[2];
|
||||
if ( dbg_read_memory(r_brk, opcode, 2, NULL) == 2
|
||||
&& memcmp(opcode, bxlr_thumb, 2) == 0 )
|
||||
{
|
||||
// found it!
|
||||
if ( add_internal_bp(shlib_bpt, r_brk+1) )
|
||||
{
|
||||
dmsg("found r_debug (r_brk=%a)\n", r_brk);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
msg("Failed to find r_debug in " LINKER "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Android reports shared objects without any path. Try to find full path.
|
||||
void linux_debmod_t::make_android_abspath(qstring *in_out_path)
|
||||
{
|
||||
if ( qisabspath(in_out_path->c_str()) )
|
||||
return;
|
||||
|
||||
// Apparently /proc didn't return an absolute path. Check /system/lib.
|
||||
// Normally we should not arrive here, this is just for safety.
|
||||
char path[QMAXPATH];
|
||||
qmakepath(path, sizeof(path), "/system/lib", in_out_path->c_str(), NULL);
|
||||
if ( qfileexist(path) )
|
||||
*in_out_path = path;
|
||||
}
|
||||
63
idasdk76/dbg/linux/android.hpp
Normal file
63
idasdk76/dbg/linux/android.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
Android specific definitions
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ANDROID_HPP
|
||||
#define __ANDROID_HPP
|
||||
|
||||
// Android NDK lacks link.h, so we have to use our own definitions
|
||||
|
||||
#include <android/api-level.h>
|
||||
#include "dbg_rpc_handler.h"
|
||||
|
||||
struct link_map
|
||||
{
|
||||
uintptr_t l_addr;
|
||||
char * l_name;
|
||||
uintptr_t l_ld;
|
||||
struct link_map * l_next;
|
||||
struct link_map * l_prev;
|
||||
};
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
int32_t r_version;
|
||||
struct link_map * r_map;
|
||||
int32_t r_brk;
|
||||
// Values for r_state
|
||||
enum
|
||||
{
|
||||
RT_CONSISTENT,
|
||||
RT_ADD,
|
||||
RT_DELETE
|
||||
};
|
||||
int32_t r_state;
|
||||
uintptr_t r_ldbase;
|
||||
};
|
||||
|
||||
// pread64 is missing
|
||||
#define pread64 pread
|
||||
|
||||
// thread_db.h lacks many definitions as well:
|
||||
|
||||
#define TD_MIN_EVENT_NUM 0
|
||||
#define TD_MAX_EVENT_NUM 16
|
||||
#define td_eventismember(set, n) (((set)->events & (1 << (n))) != 0)
|
||||
typedef void *prgregset_t;
|
||||
typedef void *prfpregset_t;
|
||||
typedef int td_thr_type_e;
|
||||
extern "C"
|
||||
{
|
||||
inline td_err_e td_init(void) { return TD_OK; }
|
||||
inline td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *) { return TD_OK; }
|
||||
inline td_err_e td_thr_setsigpending(const td_thrhandle_t *, unsigned char, const sigset_t *) { return TD_OK; }
|
||||
}
|
||||
|
||||
// Other missing definitions:
|
||||
typedef int32 __ptrace_request;
|
||||
|
||||
#define user_regs pt_regs
|
||||
|
||||
#endif // define __ANDROID_HPP
|
||||
35
idasdk76/dbg/linux/armlinux_stub.cpp
Normal file
35
idasdk76/dbg/linux/armlinux_stub.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote ARM Linux/Android debugger";
|
||||
#define DEBUGGER_NAME "armlinux"
|
||||
#define PROCESSOR_NAME "arm"
|
||||
#define DEFAULT_PLATFORM_NAME "linux"
|
||||
#define TARGET_PROCESSOR PLFM_ARM
|
||||
#define DEBUGGER_ID DEBUGGER_ID_ARM_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_SMALLBLKS \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD \
|
||||
| DBG_FLAG_PREFER_SWBPTS)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
|
||||
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "arm_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
3693
idasdk76/dbg/linux/linux_debmod.cpp
Normal file
3693
idasdk76/dbg/linux/linux_debmod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
352
idasdk76/dbg/linux/linux_debmod.h
Normal file
352
idasdk76/dbg/linux/linux_debmod.h
Normal file
@@ -0,0 +1,352 @@
|
||||
#ifndef __LINUX_DEBUGGER_MODULE__
|
||||
#define __LINUX_DEBUGGER_MODULE__
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "linuxbase_debmod.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <thread_db.h>
|
||||
}
|
||||
|
||||
#include <deque>
|
||||
|
||||
typedef int HANDLE;
|
||||
typedef uint32 DWORD;
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef std::map<ea_t, qstring> ea2name_t;
|
||||
typedef std::map<qstring, ea_t> name2ea_t;
|
||||
|
||||
#ifndef WCONTINUED
|
||||
#define WCONTINUED 8
|
||||
#endif
|
||||
|
||||
#ifndef __WALL
|
||||
#define __WALL 0x40000000
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// image information
|
||||
struct image_info_t
|
||||
{
|
||||
image_info_t() : base(BADADDR), size(0), dl_crc(0) {}
|
||||
image_info_t(
|
||||
ea_t _base,
|
||||
asize_t _size,
|
||||
const qstring &_fname,
|
||||
const qstring &_soname)
|
||||
: base(_base), size(_size), fname(_fname), soname(_soname), dl_crc(0) {}
|
||||
ea_t base;
|
||||
asize_t size; // image size, currently 0
|
||||
qstring fname;
|
||||
qstring soname;
|
||||
ea2name_t names;
|
||||
qstring buildid;
|
||||
qstring debuglink;
|
||||
uint32 dl_crc;
|
||||
};
|
||||
typedef std::map<ea_t, image_info_t> images_t; // key: image base address
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum thstate_t
|
||||
{
|
||||
RUNNING, // running
|
||||
STOPPED, // waiting to be resumed after qwait
|
||||
DYING, // we got a notification that the thread is about to die
|
||||
DEAD, // dead thread; ignore any signals from it
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// thread information
|
||||
struct thread_info_t
|
||||
{
|
||||
thread_info_t(int t)
|
||||
: tid(t), suspend_count(0), user_suspend(0), child_signum(0), single_step(false),
|
||||
state(STOPPED), waiting_sigstop(false), got_pending_status(false), pending_status(0) {}
|
||||
int tid;
|
||||
int suspend_count;
|
||||
int user_suspend;
|
||||
int child_signum;
|
||||
bool single_step;
|
||||
thstate_t state;
|
||||
bool waiting_sigstop;
|
||||
bool got_pending_status;
|
||||
int pending_status;
|
||||
qstring name; // thread name
|
||||
bool is_running(void) const
|
||||
{
|
||||
return state == RUNNING && !waiting_sigstop && !got_pending_status;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef std::map<HANDLE, thread_info_t> threads_t; // (tid -> info)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum ps_err_e
|
||||
{
|
||||
PS_OK, /* Success. */
|
||||
PS_ERR, /* Generic error. */
|
||||
PS_BADPID, /* Bad process handle. */
|
||||
PS_BADLID, /* Bad LWP id. */
|
||||
PS_BADADDR, /* Bad address. */
|
||||
PS_NOSYM, /* Symbol not found. */
|
||||
PS_NOFREGS /* FPU register set not available. */
|
||||
};
|
||||
struct ps_prochandle
|
||||
{
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
#ifndef UINT32_C
|
||||
# define UINT32_C uint32
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct internal_bpt
|
||||
{
|
||||
ea_t bpt_addr;
|
||||
uchar saved[BPT_CODE_SIZE];
|
||||
uchar nsaved;
|
||||
internal_bpt(): bpt_addr(0), nsaved(0) {} //-V730 Not all members of a class are initialized
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct mapfp_entry_t
|
||||
{
|
||||
ea_t ea1;
|
||||
ea_t ea2;
|
||||
ea_t offset;
|
||||
uint64 inode;
|
||||
char perm[8];
|
||||
char device[8];
|
||||
uint8 bitness; // Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit)
|
||||
qstring fname;
|
||||
bool empty(void) const { return ea1 >= ea2; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct chk_signal_info_t
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
int timeout_ms;
|
||||
|
||||
chk_signal_info_t(int _timeout_ms)
|
||||
{
|
||||
timeout_ms = _timeout_ms;
|
||||
pid = 0;
|
||||
status = 0;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum attach_mode_t
|
||||
{
|
||||
AMT_NO_ATTACH,
|
||||
AMT_ATTACH_NORMAL,
|
||||
AMT_ATTACH_BROKEN
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class linux_debmod_t: public linuxbase_debmod_t
|
||||
{
|
||||
typedef linuxbase_debmod_t inherited;
|
||||
|
||||
// thread_db related data and functions:
|
||||
struct ps_prochandle prochandle;
|
||||
td_thragent_t *ta;
|
||||
|
||||
internal_bpt birth_bpt; // thread created
|
||||
internal_bpt death_bpt; // thread exited
|
||||
internal_bpt shlib_bpt; // shared lib list changed
|
||||
bool complained_shlib_bpt;
|
||||
|
||||
void make_android_abspath(qstring *in_out_path);
|
||||
bool add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
|
||||
|
||||
bool add_internal_bp(internal_bpt &bp, ea_t addr);
|
||||
bool erase_internal_bp(internal_bpt &bp);
|
||||
|
||||
bool tdb_enable_event(td_event_e event, internal_bpt *bp);
|
||||
void tdb_update_threads(void);
|
||||
bool tdb_new(void);
|
||||
void tdb_delete(void);
|
||||
void tdb_handle_messages(int pid);
|
||||
void dead_thread(int tid, thstate_t state);
|
||||
void store_pending_signal(int pid, int status);
|
||||
|
||||
bool activate_multithreading();
|
||||
|
||||
// procfs
|
||||
void procfs_collect_threads(void);
|
||||
bool attach_collected_thread(unsigned long lwp);
|
||||
bool get_thread_name(qstring *thr_name, thid_t tid);
|
||||
void update_thread_names(thread_name_vec_t *thr_names);
|
||||
|
||||
// list of debug names not yet sent to IDA
|
||||
name_info_t pending_names;
|
||||
name_info_t nptl_names;
|
||||
|
||||
pid_t check_for_signal(int *status, int pid, int timeout_ms) const;
|
||||
|
||||
int find_largest_addrsize(const meminfo_vec_t &miv);
|
||||
void _import_dll(image_info_t &ii);
|
||||
void _import_symbols_from_file(name_info_t *out, image_info_t &ii);
|
||||
|
||||
public:
|
||||
easet_t dlls_to_import; // list of dlls to import information from
|
||||
images_t dlls; // list of loaded DLLs
|
||||
threads_t threads;
|
||||
qvector<thid_t> deleted_threads;
|
||||
qvector<thid_t> seen_threads; // thread was born and appeared too early
|
||||
|
||||
// debugged process information
|
||||
HANDLE process_handle;
|
||||
HANDLE thread_handle;
|
||||
bool threads_collected = false;
|
||||
|
||||
bool exited; // Did the process exit?
|
||||
|
||||
easet_t removed_bpts; // removed breakpoints
|
||||
|
||||
FILE *mapfp; // map file handle
|
||||
|
||||
int npending_signals; // number of pending signals
|
||||
bool may_run;
|
||||
bool requested_to_suspend;
|
||||
bool in_event; // IDA kernel is handling a debugger event
|
||||
|
||||
qstring interp;
|
||||
|
||||
qstring exe_path; // name of the executable file
|
||||
|
||||
ea_t nptl_base; // base of 'libpthread.so'
|
||||
|
||||
regctx_t *reg_ctx;
|
||||
|
||||
linux_debmod_t();
|
||||
~linux_debmod_t();
|
||||
|
||||
void init_reg_ctx(void);
|
||||
void term_reg_ctx(void);
|
||||
|
||||
thread_info_t &add_thread(int tid);
|
||||
void del_thread(int tid);
|
||||
thread_info_t *get_thread(thid_t tid);
|
||||
bool retrieve_pending_signal(pid_t *pid, int *status);
|
||||
int get_debug_event(debug_event_t *event, int timeout_ms);
|
||||
bool del_pending_event(event_id_t id, const char *module_name);
|
||||
void enqueue_event(const debug_event_t &ev, queue_pos_t pos);
|
||||
bool suspend_all_threads(void);
|
||||
bool resume_all_threads(void);
|
||||
int dbg_freeze_threads(thid_t tid, bool exclude=true);
|
||||
int dbg_thaw_threads(thid_t tid, bool exclude=true);
|
||||
void set_thread_state(thread_info_t &ti, thstate_t state) const;
|
||||
bool resume_app(thid_t tid);
|
||||
bool has_pending_events(void);
|
||||
bool read_asciiz(tid_t tid, ea_t ea, char *buf, size_t bufsize, bool suspend=false);
|
||||
int _read_memory(int tid, ea_t ea, void *buffer, int size, bool suspend=false);
|
||||
int _write_memory(int tid, ea_t ea, const void *buffer, int size, bool suspend=false);
|
||||
void add_dll(ea_t base, asize_t size, const char *modname, const char *soname);
|
||||
asize_t calc_module_size(const meminfo_vec_t &miv, const memory_info_t *mi) const;
|
||||
void enum_names(const char *libpath=NULL);
|
||||
bool add_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
|
||||
bool gen_library_events(int tid);
|
||||
bool emulate_retn(int tid);
|
||||
void cleanup(void);
|
||||
bool handle_process_start(pid_t pid, attach_mode_t attaching);
|
||||
drc_t get_memory_info(meminfo_vec_t &areas, bool suspend);
|
||||
bool set_hwbpts(HANDLE hThread) const;
|
||||
virtual bool refresh_hwbpts() override;
|
||||
void handle_dll_movements(const meminfo_vec_t &miv);
|
||||
bool idaapi thread_get_fs_base(thid_t tid, int reg_idx, ea_t *pea) const;
|
||||
bool read_mapping(mapfp_entry_t *me);
|
||||
bool get_soname(const char *fname, qstring *soname) const;
|
||||
ea_t find_pending_name(const char *name);
|
||||
bool handle_hwbpt(debug_event_t *event);
|
||||
bool thread_is_known(const td_thrinfo_t &info) const;
|
||||
bool listen_thread_events(const td_thrinfo_t &info, const td_thrhandle_t *th_p);
|
||||
void attach_to_thread(const td_thrinfo_t &info);
|
||||
bool attach_to_thread(int tid, ea_t ea);
|
||||
void handle_extended_wait(bool *handled, const chk_signal_info_t &csi);
|
||||
bool finish_attaching(int tid, ea_t ea, bool use_ip);
|
||||
bool check_for_new_events(chk_signal_info_t *csi, bool *event_prepared);
|
||||
|
||||
//
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
virtual drc_t idaapi dbg_detach_process(void) override;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) override;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
|
||||
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
|
||||
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) override;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
|
||||
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
|
||||
virtual bool idaapi write_registers(
|
||||
thid_t tid,
|
||||
int start,
|
||||
int count,
|
||||
const regval_t *values) override;
|
||||
virtual int dbg_freeze_threads_except(thid_t tid) override { return dbg_freeze_threads(tid); }
|
||||
virtual int dbg_thaw_threads_except(thid_t tid) override { return dbg_thaw_threads(tid); }
|
||||
|
||||
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
|
||||
virtual bool idaapi dbg_prepare_broken_connection(void) override;
|
||||
|
||||
// thread_db
|
||||
void display_thrinfo(thid_t tid);
|
||||
void display_all_threads();
|
||||
|
||||
void cleanup_breakpoints(void);
|
||||
void cleanup_signals(void);
|
||||
|
||||
bool fix_instruction_pointer(void) const;
|
||||
#ifdef __ARM__
|
||||
virtual void adjust_swbpt(ea_t *p_ea, int *p_len) override;
|
||||
#endif
|
||||
|
||||
#ifdef LDEB
|
||||
void log(thid_t tid, const char *format, ...);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
15
idasdk76/dbg/linux/linux_debmod.script
Normal file
15
idasdk76/dbg/linux/linux_debmod.script
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
global:
|
||||
PLUGIN;
|
||||
ps_pglobal_lookup;
|
||||
ps_pdread;
|
||||
ps_pdwrite;
|
||||
ps_lgetregs;
|
||||
ps_lsetregs;
|
||||
ps_lgetfpregs;
|
||||
ps_lsetfpregs;
|
||||
ps_getpid;
|
||||
ps_get_thread_area;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
66
idasdk76/dbg/linux/linux_local_impl.cpp
Normal file
66
idasdk76/dbg/linux/linux_local_impl.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <loader.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// installs or uninstalls debugger specific idc functions
|
||||
inline bool register_idc_funcs(bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rebase_if_required_to(ea_t new_base)
|
||||
{
|
||||
ea_t base = get_imagebase();
|
||||
if ( base != BADADDR && new_base != BADADDR && base != new_base )
|
||||
rebase_or_warn(base, new_base);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool init_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !init_subsystem() )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool ok = false;
|
||||
do
|
||||
{
|
||||
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
// local debugger is available if we are running under Linux
|
||||
return true;
|
||||
#else
|
||||
// for other systems only the remote debugger is available
|
||||
if ( debugger.is_remote() )
|
||||
return true;
|
||||
break; // failed
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( inf_get_filetype() != f_ELF )
|
||||
break;
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
|
||||
break;
|
||||
|
||||
ok = true;
|
||||
} while ( false );
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !ok )
|
||||
term_subsystem();
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void term_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
term_subsystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Userland linux debugger plugin.";
|
||||
34
idasdk76/dbg/linux/linux_stub.cpp
Normal file
34
idasdk76/dbg/linux/linux_stub.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote Linux debugger";
|
||||
#define DEBUGGER_NAME "linux"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define DEFAULT_PLATFORM_NAME "linux"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
|
||||
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
1355
idasdk76/dbg/linux/linux_threads.cpp
Normal file
1355
idasdk76/dbg/linux/linux_threads.cpp
Normal file
File diff suppressed because it is too large
Load Diff
26
idasdk76/dbg/linux/linux_user.cpp
Normal file
26
idasdk76/dbg/linux/linux_user.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
static const char wanted_name[] = "Local Linux debugger";
|
||||
#define DEBUGGER_NAME "linux"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <fpro.h>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "linux_debmod.h"
|
||||
|
||||
linux_debmod_t g_dbgmod;
|
||||
bool ignore_sigint = false;
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
8
idasdk76/dbg/linux/linux_wait.cpp
Normal file
8
idasdk76/dbg/linux/linux_wait.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <pro.h>
|
||||
#include "linux_debmod.h"
|
||||
//--------------------------------------------------------------------------
|
||||
pid_t linux_debmod_t::check_for_signal(int *status, int _pid, int timeout_ms) const
|
||||
{
|
||||
return qwait_timed(status, _pid, __WALL | WCONTINUED, timeout_ms);
|
||||
}
|
||||
146
idasdk76/dbg/linux/linuxbase_debmod.cpp
Normal file
146
idasdk76/dbg/linux/linuxbase_debmod.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include <fpro.h>
|
||||
#include <prodir.h>
|
||||
#include <diskio.hpp>
|
||||
#include "linuxbase_debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static inline const char *str_bitness(int bitness)
|
||||
{
|
||||
switch ( bitness )
|
||||
{
|
||||
case 8:
|
||||
return "[64]";
|
||||
case 4:
|
||||
return "[32]";
|
||||
default:
|
||||
return "[x]";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void build_process_ext_name(ext_process_info_t *pinfo)
|
||||
{
|
||||
pinfo->ext_name = str_bitness(pinfo->addrsize);
|
||||
|
||||
char buf[QMAXPATH];
|
||||
qsnprintf(buf, sizeof(buf), "/proc/%u/cmdline", pinfo->pid);
|
||||
|
||||
FILE *cmdfp = qfopen(buf, "r");
|
||||
if ( cmdfp == nullptr )
|
||||
return;
|
||||
|
||||
int size = qfread(cmdfp, buf, sizeof(buf));
|
||||
buf[size] = '\0';
|
||||
qfclose(cmdfp);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
while ( size >= 0 && buf[size] == '\0' )
|
||||
size--;
|
||||
size++;
|
||||
#endif
|
||||
|
||||
// arguments are separated by '\0'
|
||||
for ( int i=0; i < size; )
|
||||
{
|
||||
const char *in = &buf[i];
|
||||
qstring arg = in;
|
||||
quote_cmdline_arg(&arg);
|
||||
pinfo->ext_name.append(" ");
|
||||
pinfo->ext_name.append(arg);
|
||||
|
||||
i += strlen(in) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Returns the file name assciated with pid
|
||||
bool idaapi linuxbase_debmod_t::get_exec_fname(
|
||||
int _pid,
|
||||
char *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
char path[QMAXPATH];
|
||||
qsnprintf(path, sizeof(path), "/proc/%u/exe", _pid);
|
||||
int len = readlink(path, buf, bufsize-1);
|
||||
if ( len > 0 )
|
||||
{
|
||||
buf[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESXi keeps the real file name inside /proc/PID/exe (which is not a link)
|
||||
FILE *fp = qfopen(path, "r");
|
||||
if ( fp != NULL )
|
||||
{
|
||||
len = qfread(fp, buf, bufsize);
|
||||
qfclose(fp);
|
||||
if ( len > 1 && len < bufsize && buf[0] == '/' ) // sanity check
|
||||
{
|
||||
buf[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buf[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
int idaapi linuxbase_debmod_t::get_process_bitness(int _pid)
|
||||
{
|
||||
char fname[QMAXPATH];
|
||||
qsnprintf(fname, sizeof(fname), "/proc/%u/maps", _pid);
|
||||
FILE *mapfp = fopenRT(fname);
|
||||
if ( mapfp == NULL )
|
||||
return 0;
|
||||
|
||||
int bitness = 4;
|
||||
qstring line;
|
||||
while ( qgetline(&line, mapfp) >= 0 )
|
||||
{
|
||||
if ( line.empty() )
|
||||
continue;
|
||||
ea_t ea1;
|
||||
ea_t ea2;
|
||||
if ( qsscanf(line.begin(), "%a-%a ", &ea1, &ea2) == 2 )
|
||||
{
|
||||
size_t pos = line.find('-');
|
||||
if ( pos != qstring::npos && pos > 8 )
|
||||
{
|
||||
bitness = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
qfclose(mapfp);
|
||||
return bitness;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi linuxbase_debmod_t::get_process_list(procvec_t *list, qstring *)
|
||||
{
|
||||
int mypid = getpid();
|
||||
list->clear();
|
||||
qffblk64_t fb;
|
||||
for ( int code = qfindfirst("/proc/*", &fb, FA_DIREC);
|
||||
code == 0;
|
||||
code = qfindnext(&fb) )
|
||||
{
|
||||
if ( !qisdigit(fb.ff_name[0]) )
|
||||
continue;
|
||||
ext_process_info_t pinfo;
|
||||
pinfo.pid = atoi(fb.ff_name);
|
||||
if ( pinfo.pid == mypid )
|
||||
continue;
|
||||
char buf[MAXSTR];
|
||||
if ( !get_exec_fname(pinfo.pid, buf, sizeof(buf)) )
|
||||
continue; // we skip the process because we cannot debug it anyway
|
||||
pinfo.name = buf;
|
||||
pinfo.addrsize = get_process_bitness(pinfo.pid);
|
||||
build_process_ext_name(&pinfo);
|
||||
list->push_back(pinfo);
|
||||
}
|
||||
return list->size();
|
||||
}
|
||||
30
idasdk76/dbg/linux/linuxbase_debmod.h
Normal file
30
idasdk76/dbg/linux/linuxbase_debmod.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef __LINUXBASE_HPP__
|
||||
#define __LINUXBASE_HPP__
|
||||
|
||||
#include "debmod.h"
|
||||
|
||||
// Base class for linux modules
|
||||
|
||||
#ifdef __ARM__
|
||||
# define BASE_DEBUGGER_MODULE arm_debmod_t
|
||||
# include "arm_debmod.h"
|
||||
# define BPT_CODE_SIZE ARM_BPT_SIZE
|
||||
#else
|
||||
# define BASE_DEBUGGER_MODULE pc_debmod_t
|
||||
# include "pc_debmod.h"
|
||||
# define BPT_CODE_SIZE X86_BPT_SIZE
|
||||
#endif
|
||||
|
||||
class linuxbase_debmod_t: public BASE_DEBUGGER_MODULE
|
||||
{
|
||||
typedef BASE_DEBUGGER_MODULE inherited;
|
||||
protected:
|
||||
// return number of processes, -1 - not implemented
|
||||
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
|
||||
// return the file name assciated with pid
|
||||
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
|
||||
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
virtual int idaapi get_process_bitness(int pid) newapi;
|
||||
};
|
||||
|
||||
#endif
|
||||
164
idasdk76/dbg/linux/makefile
Normal file
164
idasdk76/dbg/linux/makefile
Normal file
@@ -0,0 +1,164 @@
|
||||
include ../../allmake.mak
|
||||
|
||||
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
|
||||
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
|
||||
.PHONY: $(GOALS-1)
|
||||
all: $(GOALS-1)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __LINUX__
|
||||
SERVER = linux_server$(SUFF64)
|
||||
endif
|
||||
ifdef SERVER
|
||||
SERVERS += $(call server_exe,$(SERVER))
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER = $(call module_dll,linux_user)
|
||||
ifeq ($(and $(BUILD_IDA),$(__LINUX__)),1)
|
||||
MODULES += $(USER)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# we explicitly added our module targets
|
||||
NO_DEFAULT_TARGETS = 1
|
||||
|
||||
# NOTE: all MODULES must be defined before including plugin.mak.
|
||||
include ../plugin.mak
|
||||
# NOTE: target-specific rules and dependencies that use variable
|
||||
# expansion to name the target (such as "$(MODULE): [...]") must
|
||||
# come after including plugin.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# select OBJS common to user plugin and debugger server
|
||||
ifeq ($(or $(__LINUX__),$(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__)),1)
|
||||
BUILD_LINUX:=1
|
||||
endif
|
||||
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linuxbase_debmod$(O)
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_debmod$(O)
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_wait$(O)
|
||||
|
||||
BASE_OBJS += $(BASE_OBJS-1) $(F)symelf$(O)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __LINUX__
|
||||
SERVER_LDFLAGS += -Wl,--version-script=linux_debmod.script
|
||||
SERVER_LDFLAGS += $(OUTMAP)$(F)$(@F).map
|
||||
SERVER_STDLIBS += -lthread_db -lrt -lc -lpthread -ldl
|
||||
endif
|
||||
SERVER_OBJS += $(BASE_OBJS)
|
||||
|
||||
# suppress warnings for libthread_db.c
|
||||
$(F)libthread_db$(O): WARNS = $(NOWARNS)
|
||||
|
||||
include ../server.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB_OBJS += $(F)linux_stub$(O)
|
||||
$(STUB): MODULE_OBJS += $(STUB_OBJS)
|
||||
$(STUB): $(STUB_OBJS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER_OBJS += $(F)linux_user$(O)
|
||||
USER_OBJS += $(BASE_OBJS)
|
||||
$(USER): MODULE_OBJS += $(USER_OBJS)
|
||||
$(USER): $(USER_OBJS)
|
||||
$(USER): DEFFILE = linux_debmod.script
|
||||
$(USER): STDLIBS += -ldl
|
||||
$(USER): STDLIBS += -lthread_db
|
||||
|
||||
ifeq ($(COMPILER_NAME),gcc)
|
||||
$(USER): LDFLAGS += -Wl,--export-dynamic
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
include $(IDA)objdir.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)armlinux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../arm_local_impl.cpp ../arm_regs.cpp ../arm_regs.hpp \
|
||||
../common_local_impl.cpp ../common_stub_impl.cpp \
|
||||
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_arm.hpp \
|
||||
../debmod.h ../rpc_debmod.h armlinux_stub.cpp \
|
||||
linux_local_impl.cpp
|
||||
$(F)libthread_db$(O): libthread_db.c
|
||||
$(F)linux_debmod$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)diskio.hpp $(I)err.h $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp $(I)pro.h \
|
||||
$(I)prodir.h $(I)range.hpp $(I)segment.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../../plugins/dwarf/look_for_debug_file.cpp \
|
||||
../arm_debmod.h ../arm_regs.hpp ../dbg_rpc_engine.h \
|
||||
../dbg_rpc_handler.h ../dbg_rpc_handler_ioctls.h \
|
||||
../deb_arm.hpp ../deb_pc.hpp ../debmod.h ../pc_debmod.h \
|
||||
../pc_regs.hpp android.cpp android.hpp linux_debmod.cpp \
|
||||
linux_debmod.h linux_threads.cpp linuxbase_debmod.h \
|
||||
symelf.hpp
|
||||
$(F)linux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../common_local_impl.cpp ../common_stub_impl.cpp \
|
||||
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_pc.hpp \
|
||||
../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \
|
||||
../rpc_debmod.h linux_local_impl.cpp linux_stub.cpp
|
||||
$(F)linux_user$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../arm_debmod.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../deb_arm.hpp ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \
|
||||
../pc_regs.hpp linux_debmod.h linux_local_impl.cpp \
|
||||
linux_user.cpp linuxbase_debmod.h
|
||||
$(F)linux_wait$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
|
||||
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
linux_debmod.h linux_wait.cpp linuxbase_debmod.h
|
||||
$(F)linuxbase_debmod$(O): $(I)bytes.hpp $(I)diskio.hpp $(I)fpro.h \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
|
||||
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
linuxbase_debmod.cpp linuxbase_debmod.h
|
||||
$(F)symelf$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
|
||||
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/elf/../idaldr.h ../../ldr/elf/common.cpp \
|
||||
../../ldr/elf/elf.h ../../ldr/elf/elfbase.h \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
../../ldr/elf/reader.cpp \
|
||||
../debmod.h symelf.cpp symelf.hpp
|
||||
239
idasdk76/dbg/linux/symelf.cpp
Normal file
239
idasdk76/dbg/linux/symelf.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
|
||||
// read elf symbols
|
||||
|
||||
#include <fpro.h>
|
||||
#include <kernwin.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include "../../ldr/elf/elfbase.h"
|
||||
#include "../../ldr/elf/elf.h"
|
||||
#include "debmod.h"
|
||||
#include "symelf.hpp"
|
||||
|
||||
#include "../../ldr/elf/common.cpp"
|
||||
#include "../../ldr/elf/reader.cpp"
|
||||
|
||||
inline uint32 low(uint32 x) { return x; }
|
||||
|
||||
uval_t imagebase;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{1764} could be declared const ref
|
||||
static int handle_symbol(
|
||||
reader_t &reader,
|
||||
int shndx,
|
||||
int _info,
|
||||
uint32 st_name,
|
||||
uval_t st_value,
|
||||
slice_type_t slice_type,
|
||||
symbol_visitor_t &sv)
|
||||
{
|
||||
if ( shndx == SHN_UNDEF
|
||||
|| shndx == SHN_LOPROC
|
||||
|| shndx == SHN_HIPROC
|
||||
|| shndx == SHN_ABS )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int type = ELF_ST_TYPE(_info);
|
||||
if ( type != STT_OBJECT && type != STT_FUNC )
|
||||
return 0;
|
||||
|
||||
if ( st_name == 0 )
|
||||
return 0;
|
||||
|
||||
if ( imagebase != uval_t(-1) )
|
||||
st_value -= imagebase;
|
||||
|
||||
qstring name;
|
||||
reader.get_name(&name, slice_type, st_name);
|
||||
return sv.visit_symbol(st_value, name.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int load_symbols(
|
||||
reader_t &reader,
|
||||
const elf_shdr_t §ion,
|
||||
slice_type_t slice_type,
|
||||
symbol_visitor_t &sv)
|
||||
{
|
||||
int code = 0;
|
||||
sym_rel *sym;
|
||||
buffered_input_t<sym_rel> symbols_input(reader, section);
|
||||
for ( elf_sym_idx_t i = 0; code == 0 && symbols_input.next(sym); ++i )
|
||||
{
|
||||
if ( i == 0 ) // skip _UNDEF
|
||||
continue;
|
||||
|
||||
code = handle_symbol(reader,
|
||||
sym->original.st_shndx,
|
||||
sym->original.st_info,
|
||||
sym->original.st_name,
|
||||
sym->original.st_value,
|
||||
slice_type,
|
||||
sv);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool map_pht(reader_t &reader)
|
||||
{
|
||||
if ( !reader.read_program_headers() )
|
||||
return false;
|
||||
|
||||
imagebase = reader.pheaders.get_image_base();
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool silent_handler(const reader_t &reader, reader_t::errcode_t code, ...)
|
||||
{
|
||||
return reader.is_warning(code); // resume after warnings
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int _load_elf_symbols(linput_t *li, symbol_visitor_t &sv)
|
||||
{
|
||||
reader_t reader(li);
|
||||
reader.set_handler(silent_handler);
|
||||
if ( !reader.read_ident() || !reader.read_header() )
|
||||
return -1;
|
||||
|
||||
const elf_ident_t &ident = reader.get_ident();
|
||||
uint8 elf_class = ident.elf_class;
|
||||
if ( elf_class != ELFCLASS32 && elf_class != ELFCLASS64 )
|
||||
return -1;
|
||||
|
||||
uint8 elf_data_ord = ident.bytesex;
|
||||
if ( elf_data_ord != ELFDATA2LSB && elf_data_ord != ELFDATA2MSB )
|
||||
return -1;
|
||||
|
||||
section_headers_t §ions = reader.sections;
|
||||
dynamic_linking_tables_t dlt;
|
||||
|
||||
int code = 0;
|
||||
elf_ehdr_t &header = reader.get_header();
|
||||
if ( header.has_pht() && !map_pht(reader) )
|
||||
return -1;
|
||||
|
||||
reader.read_section_headers();
|
||||
|
||||
// Try and acquire dynamic linking tables info.
|
||||
dlt = reader.sections.get_dynamic_linking_tables_info();
|
||||
if ( !dlt.is_valid() )
|
||||
dlt = reader.pheaders.get_dynamic_linking_tables_info();
|
||||
|
||||
// Parse dynamic info if available
|
||||
dynamic_info_t di;
|
||||
if ( dlt.is_valid() )
|
||||
{
|
||||
reader_t::dyninfo_tags_t dyninfo_tags;
|
||||
dyninfo_tags.reserve(10);
|
||||
if ( reader.read_dynamic_info_tags(&dyninfo_tags, dlt)
|
||||
&& reader.parse_dynamic_info(&di, dyninfo_tags)
|
||||
&& (sv.velf & VISIT_DYNINFO) != 0 )
|
||||
{
|
||||
reader.set_di_strtab(reader.dyn_strtab, di.strtab());
|
||||
typedef reader_t::dyninfo_tags_t::const_iterator const_it;
|
||||
for ( const_it dyn = dyninfo_tags.begin();
|
||||
dyn != dyninfo_tags.end();
|
||||
++dyn )
|
||||
{
|
||||
qstring name;
|
||||
switch ( dyn->d_tag )
|
||||
{
|
||||
case DT_SONAME:
|
||||
case DT_RPATH:
|
||||
case DT_RUNPATH:
|
||||
case DT_NEEDED:
|
||||
reader.get_name(&name, reader.dyn_strtab, uint32(dyn->d_un));
|
||||
break;
|
||||
}
|
||||
if ( sv.visit_dyninfo(dyn->d_tag, name.c_str(), dyn->d_un) != 0 )
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_INTERP) != 0 )
|
||||
{
|
||||
elf_shdr_t *interp_sh = reader.sections.get_wks(WKS_INTERP);
|
||||
if ( interp_sh != NULL )
|
||||
{
|
||||
qstring name;
|
||||
reader.get_string_at(&name, interp_sh->sh_offset);
|
||||
code = sv.visit_interp(name.c_str());
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_SYMBOLS) != 0 )
|
||||
{
|
||||
elf_shndx_t symtab = sections.get_index(WKS_SYMTAB);
|
||||
elf_shndx_t dynsym = sections.get_index(WKS_DYNSYM);
|
||||
elf_shdr_t fake_section;
|
||||
if ( symtab != 0 || dynsym != 0 )
|
||||
{
|
||||
// Loading symbols
|
||||
if ( symtab != 0 )
|
||||
code = load_symbols(reader, *sections.getn(symtab), SLT_SYMTAB, sv);
|
||||
if ( code == 0 && dynsym != 0 )
|
||||
code = load_symbols(reader, *sections.getn(dynsym), SLT_DYNSYM, sv);
|
||||
}
|
||||
else if ( di.fill_section_header(&fake_section, DIT_SYMTAB) )
|
||||
{
|
||||
code = load_symbols(reader, fake_section, SLT_DYNSYM, sv);
|
||||
}
|
||||
}
|
||||
|
||||
notes_t notes(&reader);
|
||||
if ( (sv.velf & VISIT_BUILDID) != 0 && reader.read_notes(¬es) )
|
||||
{
|
||||
qstring id;
|
||||
if ( notes.get_build_id(&id) )
|
||||
{
|
||||
code = sv.visit_buildid(id.c_str());
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_DBGLINK ) != 0 )
|
||||
{
|
||||
uint32 crc;
|
||||
qstring debuglink;
|
||||
if ( sections.is_initialized()
|
||||
&& sections.read_gnu_debuglink(&debuglink, &crc) )
|
||||
{
|
||||
code = sv.visit_debuglink(debuglink.c_str(), crc);
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int load_linput_elf_symbols(linput_t *li, symbol_visitor_t &sv)
|
||||
{
|
||||
if ( li == NULL )
|
||||
return -1;
|
||||
int code;
|
||||
// there is thread unsafe code in elf handling, so use locks
|
||||
lock_begin();
|
||||
{
|
||||
code = _load_elf_symbols(li, sv);
|
||||
}
|
||||
lock_end();
|
||||
close_linput(li);
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote)
|
||||
{
|
||||
return load_linput_elf_symbols(open_linput(fname, remote), sv);
|
||||
}
|
||||
30
idasdk76/dbg/linux/symelf.hpp
Normal file
30
idasdk76/dbg/linux/symelf.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// read symbols from an elf file
|
||||
#ifndef __SYMELF__
|
||||
#define __SYMELF__
|
||||
|
||||
struct symbol_visitor_t
|
||||
{
|
||||
symbol_visitor_t(int visit_flags) : velf(visit_flags) {}
|
||||
|
||||
int velf;
|
||||
#define VISIT_SYMBOLS 0x0001
|
||||
#define VISIT_INTERP 0x0002
|
||||
#define VISIT_DYNINFO 0x0004
|
||||
#define VISIT_SEGMENTS 0x0008
|
||||
#define VISIT_BUILDID 0x0010
|
||||
#define VISIT_DBGLINK 0x0020
|
||||
|
||||
// any callback returns nonzero - stop enumeration
|
||||
virtual int visit_symbol(ea_t /*ea*/, const char * /*name*/) { return 0; }
|
||||
virtual int visit_interp(const char * /*name*/) { return 0; }
|
||||
virtual int visit_segment(ea_t /*start*/, size_t /*size*/, const char * /*name*/) { return 0; }
|
||||
virtual int visit_dyninfo(uint64 /*tag*/, const char * /*name*/, uint64 /*value*/) { return 0; }
|
||||
virtual int visit_buildid(const char * /*Build ID*/) { return 0; }
|
||||
virtual int visit_debuglink(const char * /*debug*/, uint32 /*crc*/) { return 0; }
|
||||
};
|
||||
|
||||
// returns -1 on errors
|
||||
// otherwise returns the non-zero code returned by the visitor or 0
|
||||
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote=false);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user