update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View 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;
}

View 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

View 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"

File diff suppressed because it is too large Load Diff

View 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

View 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:
*;
};

View 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.";

View 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"

File diff suppressed because it is too large Load Diff

View 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"

View 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);
}

View 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();
}

View 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
View 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

View 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 &section,
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 &sections = 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(&notes) )
{
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);
}

View 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