当前位置: 首页 > 工具软件 > KGTP > 使用案例 >

使kgtp支持存储超过一页的内存数据

亢正德
2023-12-01


使kgtp支持存储超过一页的内存数据


这周完成了中期计划,这个是commit:https://code.csdn.net/lynuszhu/gktp/commit/057f9cc901346a42e7d45e41031fb046453b722f


1. kgtp的Ring Buffer模型

目前的焦点是在gtp_rb.c文件中实现的ringbuffer模型。

核心数据结构:

struct gtp_rb_s {
	spinlock_t	lock;

	/* Pointer to the prev frame entry head.
	   */
	void		*prev_frame;

	/* When write, this is the next address to be write.
	   When read, this is the end of read.  */
	void		*w;

	/* When alloc memory from rb, record prev value W to PREV_W.
	   When this memory doesn't need, set W back to PREV_W to release
	   this memroy.  */
	void		*prev_w;

	/* Point to the begin of ring buffer.  Read will begin from R.  */
	void		*r;

	/* Point to the trace frame entry head of current read.  */
	void		*rp;

	/* This the id of rp point to.
	   0 means rp doesn't point to a trace frame entry.
	   So it need call gtp_rb_walk first.  */
	u64		rp_id;

	/* The cpu id.  */
	int		cpu;
};

以上数据结构管理一个ringbuffer的读写指针。另外有个per_cpu变量指向各个cpu自己的gtp_rb_s数据结构。每当cpu hit到一个tracepoint时候,首先要获取到自己的gtp_rb_s指针,才能进行接下来对ringbuffer的操作。使用per_cpu变量有个显著的优点就是各个cpu使用自己的内存区域,不用考虑并发冲突。免除使用各种同步机制的麻烦。

ringbuffer示意图:

ringbuffer并不保证使用连续内存,它使用类似链表形式将一块块内存page串联到一起,每页内存的前sizeof(size_t)字节和最后sizeof(size_t)字节分别是上一页和下一页的地址。

gdb的frame与kgtp的frame在ringbuffer中的示意图:

gdb的一个frame是指当hit tp时,kgtp根据用户在当前tp定义的所有action所收集的所有数据(内存数据,寄存器,TSV)保存在的一块连续区域。首先会在ringbuffer内分配一块head_frame,在内部保存了触发中断的tp编号,和一个新生成的id号;接下来执行各个具体action,例如执行memory_read(addr,size)操作,首先申请从ringbuffer申请一块内存,在内存首部打上记号FID_MEM意为当前frame保存了内存数据;接下来是地址addr和长度size,最后是内存数据正文。因为每次中断时候会把所有action一起执行完,所以每个head_frame后面跟着的frame都是由同一次tp的触发产生的。所以gdb用户所看到的frame是由head_frame引领的一串action frame.


目前的实现不支持一个action frame 跨页保存,导致的问题有1.当前页分配不了申请的数据块长度,只有废弃当前页,跳到下一页去分配 2.若申请长度在一块全新页也无法分配,则报错退出。这就引出了这次CSDN开源活动要解决的主要问题。 

要解决这个问题,简单的方法是1.将一个大的内存切片,分为多个frame保存。2.在gtp_gdbrsp_m函数中支持从多个frame中读取还原原来大的数据块。幸运的是,第二步原来的代码已经支持了:

                        while (1) {                    
                                struct gtp_frame_mem    *mr;   
                                ULONGEST                cur_start, cur_end;            
                                uint8_t                 *buf;  

                                tmp = gtp_rb_walk(&rbws, tmp); 
                                if (rbws.reason != gtp_rb_walk_type)
                                        break;                         

                                mr = (struct gtp_frame_mem *) (tmp + FID_SIZE);
                                buf = tmp + GTP_FRAME_MEM_SIZE;
                                cur_start = max(((ULONGEST)mr->addr), addr);
                                cur_end = min(((ULONGEST)mr->addr
                                                + mr->size),                   
                                               (addr + len));                 
                                if (cur_start < cur_end) {     
                                        memcpy(gtp_m_buffer + cur_start - addr,
                                                buf + cur_start - mr->addr,    
                                                cur_end - cur_start);          
                                        ret = 0;                       
                                }                              

                                tmp += FRAME_ALIGN(GTP_FRAME_MEM_SIZE 
                                                   + mr->size);                   
                        }
所以我要做的就是第一步。

 类似资料: