📄 memtrace.c
字号:
/* memtrace.c:
* This file contains CLI and API code to support a simple memory trace
* capability that allows application developers to call mon_memtrace()
* with a "printf-like" formatted arglist and the formatted string is
* put into a circular buffer in some allocated RAM space.
* The circular buffer is established by "mtrace cfg" command, then all
* subsequent calls to mon_memtrace() will have the formatted string
* destined for that buffer.
*
* To keep the output formatted clean, the user of mon_memtrace() should
* not include any line-feeds in the string. Each time mon_memtrace() is
* called, a line feed and sequence number is prepended to the string.
* This allows the dump to simply run through the buffer using putchar().
*
* Both the mon_memtrace() API function and the dump facility in the CLI
* will deal with buffer wrapping.
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Note1: the majority of this code was edited with 4-space tabs.
* Note2: as more and more contributions are accepted, the term "author"
* is becoming a mis-representation of credit.
*
* Original author: Ed Sutter
* Email: esutter@lucent.com
* Phone: 908-582-2351
*/
#include "config.h"
#include <stdarg.h>
#include "stddefs.h"
#include "genlib.h"
#include "cli.h"
#if INCLUDE_MEMTRACE
#define MINBUFSIZE 512
#define MAXLINSIZE MINBUFSIZE/2
#define MODE_PRINT (1<<0) /* mtrace text is output to console */
#define MODE_NOWRAP (1<<1) /* when mtrace buffer fills, stop */
/* struct mtInfo:
* This structure is at the base of the memory space allocated for
* the print buffer. The control structure is part of the print buffer
* because the print buffer is assumed to be outside of the bss area
* of the monitor; hence, if a reset occurs and the monitor clears out
* its bss space, this structure will still be accessible and contain
* the data prior to the reset.
* So, to initialize a memory trace buffer use...
* mtrace cfg BASE SIZE
* and to re-establish the trace after a reset, use...
* mtrace mip BASE
*/
struct mtInfo {
char *base; /* Base of ram space allocated for print buffer. */
char *ptr; /* Running pointer into circular print buffer. */
char *end; /* End of ram space allocated. */
int size; /* Size of space originally allocated for mtrace. */
int off; /* Set if tracing is disabled. */
int sno; /* Sequence number of Mtrace() call. */
int wrap; /* Wrap counter. */
int mode; /* See MODE_XXX bits above. */
int reentered; /* Reentry counter. */
};
static struct mtInfo *Mip;
/* Mtrace():
* Memory trace... This function can be used to place some trace statements
* (readable text) in some memory location specified by the
* setting of mtracebuf. This was originally written for debugging Xmodem
* because you can't use printf() since the protocol is using the serial
* port. I have since pulled it out of the Xmodem.c file and placed it in
* generally accessible space so that it can be made available to the
* application code and other monitor code.
*/
int
Mtrace(char *fmt,...)
{
static int inMtraceNow;
int len;
char *eolp;
va_list argp;
/* Mtrace not configured or disabled, so just return.
*/
if (!Mip || Mip->off)
return(0);
/* This may be called from interrupt and/or non-interrupt space of
* an application, so we must deal with possible reentrancy here.
*/
if (inMtraceNow) {
Mip->reentered++;
return(0);
}
inMtraceNow = 1;
Mip->ptr += snprintf(Mip->ptr,MAXLINSIZE,"\n<%04d> ",Mip->sno++);
va_start(argp,fmt);
len = vsnprintf(Mip->ptr,MAXLINSIZE,fmt,argp);
va_end(argp);
/* Strip all CR/LFs from the incoming string.
* The incoming string can have CR/LFs in it; however, they are stripped
* so that the format of the dump is stable (one line per Mtrace call).
* Notice that the top line of this function inserts a newline ahead
* of the sequence number; hence, additional CR/LFs in the text would
* just confuse the output.
*/
eolp = Mip->ptr;
while(*eolp) {
if ((*eolp == '\r') || (*eolp == '\n')) {
strcpy(eolp,eolp+1);
len--;
}
else
eolp++;
}
/* If print flag is set, then dump to the console...
*/
if (Mip->mode & MODE_PRINT) {
int i;
for(i=0;i<len;i++)
putchar(*Mip->ptr++);
putchar('\n');
}
else
Mip->ptr += len;
if (Mip->ptr >= Mip->end) {
Mip->ptr = Mip->base;
if (Mip->mode & MODE_NOWRAP)
Mip->off = 1;
else
Mip->wrap++;
}
/* Flush the d-cache of the mtrace buffer and Mip structure after each
* transfer...
* This is important because if this is being accessed from an
* application that has d-cache enabled, then the hardware is reset,
* there is a chance that the data written was in cache and would be
* lost.
*/
flushDcache((char *)Mip,sizeof(struct mtInfo));
flushDcache((char *)Mip->base,Mip->end - Mip->base);
inMtraceNow = 0;
return(len);
}
void
MtraceReset(void)
{
Mip->ptr = Mip->base;
Mip->sno = 1;
Mip->wrap = 0;
Mip->off = 0;
Mip->mode = 0;
Mip->reentered = 0;
memset(Mip->base,0,Mip->size-sizeof(struct mtInfo));
}
void
MtraceInit(char *base, int size)
{
if (size < MINBUFSIZE)
return;
Mip = (struct mtInfo *)base;
Mip->base = base + sizeof(struct mtInfo);
Mip->size = size;
Mip->end = (Mip->base + size - MAXLINSIZE);
MtraceReset();
}
char *
mDump(char *bp, int more)
{
int line;
line = 0;
while((bp < Mip->end) && (*bp)) {
putchar(*bp);
if (more && (*bp == '\n')) {
if (++line == 24) {
line = 0;
if (!More())
return(0);
}
}
bp++;
}
while(*bp) {
putchar(*bp);
if (more && (*bp == '\n')) {
if (++line == 24) {
line = 0;
if (!More())
return(0);
}
}
bp++;
}
return(bp);
}
/* If Mip pointer is configured, return 1; else return zero
* and print an error message.
*/
static int
MipConfigured(void)
{
if (Mip)
return(1);
printf("Not configured\n");
return(0);
}
char *MtraceHelp[] = {
"Configure/Dump memory trace.",
"-[nm] {cmd} [cmd specific args]",
#if INCLUDE_VERBOSEHELP
"Options:",
" -m enable 'more' flag for dump.",
" -n disable wrapping.",
"Cmd:",
" on",
" off",
" dump",
" pron",
" reset",
" log {msg}",
" mip {base}",
" cfg [{base} {size}]",
#endif
0
};
int
MtraceCmd(int argc,char *argv[])
{
char *bp;
int more, opt, nowrap;
more = 0;
nowrap = 0;
while((opt=getopt(argc,argv,"nm")) != -1) {
switch(opt) {
case 'n':
nowrap = 1;
break;
case 'm':
more = 1;
break;
default:
return(CMD_PARAM_ERROR);
}
}
if (argc <= optind)
return(CMD_PARAM_ERROR);
if (!strcmp(argv[optind],"cfg")) {
if (argc == optind + 3) {
MtraceInit((char *)strtoul(argv[optind+1],0,0),
strtoul(argv[optind+2],0,0));
if (nowrap)
Mip->mode |= MODE_NOWRAP;
}
else if (argc == optind + 1) {
if (MipConfigured()) {
printf("Base: 0x%lx, End: 0x%lx\n",
(ulong)Mip->base,(ulong)Mip->end);
printf("Ptr: 0x%lx, Sno: %d\n",(ulong)Mip->ptr,Mip->sno);
printf("Wrap: %d\n",Mip->wrap);
}
}
else
return(CMD_PARAM_ERROR);
}
else if (!strcmp(argv[optind],"on")) {
if (MipConfigured()) {
Mip->mode &= ~MODE_PRINT;
Mip->off = 0;
}
}
else if (!strcmp(argv[optind],"pron")) {
if (MipConfigured()) {
Mip->mode |= MODE_PRINT;
Mip->off = 0;
}
}
else if (!strcmp(argv[optind],"off")) {
if (MipConfigured())
Mip->off = 1;
}
else if (!strcmp(argv[optind],"reset")) {
if (MipConfigured())
MtraceReset();
}
else if (!strcmp(argv[optind],"mip")) {
if (argc != optind + 2)
return(CMD_PARAM_ERROR);
Mip = (struct mtInfo *)strtoul(argv[optind+1],0,0);
}
else if (!strcmp(argv[optind],"log")) {
if (argc != optind + 2)
return(CMD_PARAM_ERROR);
Mtrace(argv[optind+1]);
}
else if (!strcmp(argv[optind],"dump")) {
if (MipConfigured()) {
if (Mip->reentered)
printf("Reentry count: %d\n",Mip->reentered);
if (Mip->wrap) {
printf("Buffer wrapped...\n");
bp = Mip->ptr;
while(bp < Mip->end) {
if (*bp == '\n') {
bp = mDump(bp,more);
break;
}
bp++;
}
if (bp) {
bp = Mip->base;
while(bp < Mip->ptr)
putchar(*bp++);
}
}
else {
bp = mDump(Mip->base,more);
}
printf("\n\n");
}
}
else
return(CMD_PARAM_ERROR);
return(CMD_SUCCESS);
}
#else
void
MtraceInit(char *base, int size)
{
printf("Mtrace() facility not built in.\n");
}
int
Mtrace(char *fmt, ...)
{
return(0);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -