1. PMD工具
PMD工具是基于ptrace的Android手机内存dump工具,其能够获取Android手机指定进程的内存,并生成相应的map文件和mem文件。
Usage: pid out_dir [-s <image> <offset>]
PMD工具的编译与使用见我的另一篇博客:
http://blog.youkuaiyun.com/rzwinters/article/details/75517107
2. Android.mk与Application.mk
- Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := pmd
LOCAL_SRC_FILES := pmd.c
LOCAL_CPPFLAGS := -O3 -Wall -fPIE
LOCAL_LDLIBS := -O3 -llog -fPIE -pie
LOCAL_C_INCLUDES := /home/richard/android-ndk-r15b/platforms/android-19/arch-arm/usr/include/
include $(BUILD_EXECUTABLE)
- Application.mk
APP_ABI := armeabi
APP_PLATFORM := android-19
3. 源代码(注释版)
#define _LARGEFILE64_SOURCE //for using function lseek64
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <linux/user.h>
#include <dirent.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#define DROID_VERSION
#ifdef DROID_VERSION
# include <android/log.h>
#endif
//#define LOG_ON //for LOG
#undef LOG_ON
/* Variadic macros for printing log and err info */
#ifdef DROID_VERSION
# define PMD_LOG(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "[pmd]", "%s: "fmt, __func__, ##__VA_ARGS__)
#else
# define PMD_LOG(fmt, ...) fprintf(stderr, "[ ] "__func__ fmt, ##__VA_ARGS__)
#endif
#define PMD_ERR(prefix, ...) PMD_LOG(prefix": %s\n", ##__VA_ARGS__, strerror(errno))
#define n_ARRAY(array) (sizeof(array)/sizeof(array[0]))
/* Segments need to be skipped when dumping memory */
const char *skip_segments[] = {
"/dev/kgsl-3d0"
};
/* Segements must be injected when dumping memory */
const char *must_injects[] = {
"/dev/ashmem"
};
static inline int
is_in_string_list (const char* s,
const char* strings[],
unsigned n_strings)
{
unsigned i;
/* Check if s is in the strings */
for(i = 0; i < n_strings; i++)
{
if(strcmp(strings[i], s) == 0) return 1;
}
return 0;
}
#define is_in_skip_segments(s) is_in_string_list(s, skip_segments, n_ARRAY(skip_segments))
#define is_in_must_inject(s) is_in_string_list(s, must_injects, n_ARRAY(must_injects))
static inline size_t
get_tids(pid_t **const listptr, size_t *const sizeptr, const pid_t pid)
{
char dirname[64];
DIR *dir;
pid_t *list;
size_t size, used = 0;
list = *listptr = NULL;
size = *sizeptr = 0;
/* Open the task dir of the target process in proc filesystem */
sprintf(dirname, "/proc/%d/task/", (int)pid);
dir = opendir(dirname);
if (!dir) {
PMD_ERR("open task dir");
return 0;
}
while (1) {
struct dirent *ent;
int value;
char dummy;
/* Read the entries in the task dir */
ent = readdir(dir);
if (!ent)
break;
/* Parse TIDs. Ignore non-numeric entries. */
if (sscanf(ent->d_name, "%d%c", &value, &dummy) != 1)
continue;
/* Ignore obviously invalid entries. */
if (value < 1)
continue;
/* Make sure there is room for another TID. */
if (used >= size) {
size = (used | 127) + 128;
list = realloc(list, size * sizeof list[0]); //expansion
*listptr = list; //write back
*sizeptr = size; //write back
}
/* Add to list. */
list[used++] = (pid_t)value;
}
closedir(dir);
return used; //return, write back
}
static inline void
check_new_tids(pid_t **const listptr, size_t *const usedptr, size_t *const sizeptr,
const pid_t pid, const unsigned char let_run)
{
int used = *usedptr;
int max = *sizeptr;
pid_t *list = *listptr;