#include <sys/mdb_modapi.h>
#include <sys/sysinfo.h>
#include "malloc.h"
#include "string.h"
#define PRINT_STR_BUFFER_SIZE 255
#define ARGV_STR_BUFFER_SIZE 255
enum RBTree{Set, Map};
/*
* 打印int类型
*/
ssize_t pint(const uintptr_t addr)
{
if (addr != 0)
{
int i = 0;
ssize_t ret = mdb_vread(&i, sizeof(int), addr);
if (-1 == ret)
{
return (DCMD_ERR);
}
mdb_printf("%d", i);
}
return (DCMD_OK);
}
/*
* 打印long long类型
*/
ssize_t pllong(const uintptr_t addr)
{
if (addr != 0)
{
long long ll = 0;
ssize_t ret = mdb_vread(&ll, sizeof(long long), addr);
if (-1 == ret)
{
return (DCMD_ERR);
}
mdb_printf("%lld", ll);
}
return (DCMD_OK);
}
/*
* 打印string类型
*/
ssize_t pstring(const uintptr_t addr)
{
if (addr != 0)
{
uintptr_t str_addr = 0;
ssize_t ret = mdb_vread(&str_addr, sizeof(uintptr_t), addr);
if (-1 == ret)
{
return (DCMD_ERR);
}
if (str_addr != 0)
{
char str[PRINT_STR_BUFFER_SIZE] = {'\0'};
ret = mdb_readstr(str, PRINT_STR_BUFFER_SIZE, str_addr);
if (-1 == ret)
{
return (DCMD_ERR);
}
mdb_printf("%s", str);
}
}
return (DCMD_OK);
}
//打印某种类型的变量
typedef ssize_t (PVAR)(const uintptr_t);
/*
* 获得类型对应的偏移
*/
size_t getOffset(PVAR * pvar)
{
size_t offset = 0;
if (pint == pvar)
{
offset = sizeof(int);
}
else if (pllong == pvar)
{
offset = sizeof(long long);
}
return offset;
}
/*
* 判断用户输入的类型
*/
void judgeType(const int argc, const mdb_arg_t *argv, char* para, PVAR** ppvar)
{
if (!strncmp("int", para, strlen("int")))
{
//int类型
*ppvar = pint;
}
else if (!strncmp("longlong", para, strlen("longlong")))
{
//long long类型
*ppvar = pllong;
}
else if (!strncmp("string", para, strlen("string")))
{
//string类型
*ppvar = pstring;
}
else
{
*ppvar = NULL;
}
}
/*
* 获得打印某种类型的方法
*/
void getPrinter(const int argc, const mdb_arg_t *argv, PVAR** ppvar)
{
char para[PRINT_STR_BUFFER_SIZE] = {'\0'};
memset(para, 0, ARGV_STR_BUFFER_SIZE);
char* para_tmp = para;
for (int i = 0; i < argc; ++i)
{
strncat(para_tmp, (argv + i)->a_un.a_str, strlen((argv + i)->a_un.a_str));
para_tmp += strlen((argv + i)->a_un.a_str);
}
judgeType(argc, argv, para, ppvar);
}
/*
* 获得打印某种map类型的方法
*/
void getMapPrinter(const int argc, const mdb_arg_t *argv, PVAR** ppvar_key, PVAR** ppvar_value)
{
char para[PRINT_STR_BUFFER_SIZE] = {'\0'};
memset(para, 0, ARGV_STR_BUFFER_SIZE);
char* para_tmp = para;
for (int i = 0; i < argc; ++i)
{
strncat(para_tmp, (argv + i)->a_un.a_str, strlen((argv + i)->a_un.a_str));
para_tmp += strlen((argv + i)->a_un.a_str);
}
judgeType(argc, argv, para, ppvar_key);
char* comma = strchr(para, ',');
if (comma != NULL)
{
judgeType(argc, argv, comma + 1, ppvar_value);
}
else
{
*ppvar_value = NULL;
}
}
/*
* 打印list成员的地址
* STL list的伪结构如下(因为都是指针,每个成员在32为系统上占4字节):
{
__buffer_size,
__buffer_list,
__free_list,
__next_avail,
__last,
__node, //指向list的node的指针
__length //list含有的成员个数
}
__node的伪结构:
{
next, //双向链表中,指向下一个节点的指针
prev, //双向链表中,指向上一个节点的指针
data //指向list成员的指针,本程序就是打印这个指针
}
* 整个list是由n个__node组成的
*/
static int
plist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
if (flags & DCMD_ADDRSPEC)
{
//打印成员个数
size_t length = 0;
/*这里解释一下mdb_vread:
形如804792c/X这样的操作就等同于调用mdb_vread,
即mdb_vread第一个参数代表的指针,解引用后,
即为被调试模块中变量的值*/
//按照list的伪结构推算,__length的地址为“首地址 + sizeof(uintptr_t) * 6”
ssize_t ret = mdb_vread(&length, sizeof(size_t), addr + sizeof(uintptr_t) * 6);
if (-1 == ret)
{
return (DCMD_ERR);
}
mdb_printf("The list size is: %d\n", length);
//打印成员地址
if (length > 0)
{
//判断是否指定了类型
PVAR *pvar = NULL;
getPrinter(argc, argv, &pvar);
uintptr_t node = 0;
//按照list node的伪结构推算,__node的地址为“首地址 + sizeof(uintptr_t) * 5”
ret = mdb_vread(&node, sizeof(uintptr_t), addr + sizeof(uintptr_t) * 5);
if (-1 == ret)
{
return (DCMD_ERR);
}
uintptr_t next = 0;
//按照list node的伪结构推算,__node的地址和其包含的next的地址相等
next = node;
if (node != 0)
{
mdb_printf("The list member is: (");
//通过dbx调试发现,第一个next指向第一个有效成员__node的地址
for (int i = 0; i < length; ++i)
{
//取得next指向的__node的地址
ret = mdb_vread(&next, sizeof(uintptr_t), next);
if (-1 == ret)
{
return (DCMD_ERR);
}
//按照list node的伪结构推算,data的地址为“next的地址 + sizeof(uintptr_t) * 2”
if (pvar != NULL)
{
mdb_printf("[%d]", i);
//按用户指定的类型打印
ret == pvar(next + sizeof(uintptr_t) * 2);
if (-1 == ret)
{
return (DCMD_ERR);
}
}
else
{
//否则打印地址
mdb_printf("[%d]0x%p", i, next + sizeof(uintptr_t) * 2);
}
if (i != length - 1)
{
mdb_printf(", ");
}
}
mdb_printf(")");
}
}
}
return (DCMD_OK);
}
/*
* 打印vector成员的地址
* STL vector的伪结构如下(因为都是指针,每个成员在32位系统上占4字节):
{
__buffer_size,
__start, //成员变量的开始地址
__finish, //成员变量的结束地址
__end_of_storage
}
* 沿着__start,不断加“sizeof(vector成员的类型)”的长度,就能访问整个vector
* 因无法知道vector成员的类型,所以这里只打印__start和__finish
*/
static int
pvec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
if (flags & DCMD_ADDRSPEC)
{
uintptr_t start = 0;
//按照vector的伪结构推算,__start的地址为“首地址 + sizeof(uintptr_t)”
ssize_t ret = mdb_vread(&start, sizeof(uintptr_t), addr + sizeof(uintptr_t));
if (-1 == ret)
{
return (DCMD_ERR);
}
uintptr_t finish = 0;
//按照vector的伪结构推算,__finish的地址为“首地址 + sizeof(uintptr_t) * 2”
ret = mdb_vread(&finish, sizeof(uintptr_t), addr + sizeof(uintptr_t) * 2);
if (-1 == ret)
{
return (DCMD_ERR);
}
if (start != finish)
{
//判断是否指定了类型
PVAR *pvar = NULL;
getPrinter(argc, argv, &pvar);
if (pvar != NULL)
{
size_t offset = getOffset(pvar);
if (0 == offset)
{
return (DCMD_ERR);
}
mdb_printf("The vector size is: %d\n", (finish - start) / offset);
mdb_printf("The vector member is: (");
for (int i = 0; start < finish; start += offset, ++i)
{
mdb_printf("[%d]", i);