coredump:support coredump command restore coredump form block device
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
fcd0729e21
commit
1334306585
@ -23,68 +23,246 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include <nuttx/streams.h>
|
|
||||||
#include <nuttx/binfmt/binfmt.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <sys/ioctl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <execinfo.h>
|
#include <nuttx/binfmt/binfmt.h>
|
||||||
|
#include <nuttx/streams.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
typedef CODE void (*dumpfile_cb_t)(FAR char *path, FAR const char *filename,
|
||||||
|
FAR void *arg);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* coredump_main
|
* dumpfile_iterate
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int main(int argc, FAR char *argv[])
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
static int dumpfile_iterate(FAR char *path, dumpfile_cb_t cb, FAR void *arg)
|
||||||
|
{
|
||||||
|
FAR struct dirent *entry;
|
||||||
|
FAR DIR *dir;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
ret = mkdir(path, 0777);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((entry = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (entry->d_type == DT_REG && !strncmp(entry->d_name, "core-", 5))
|
||||||
|
{
|
||||||
|
cb(path, entry->d_name, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* dumpfile_count
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void dumpfile_count(FAR char *path, FAR const char *filename,
|
||||||
|
FAR void *arg)
|
||||||
|
{
|
||||||
|
FAR size_t *max = (FAR size_t *)arg;
|
||||||
|
|
||||||
|
*max += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* dumpfile_delete
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void dumpfile_delete(FAR char *path, FAR const char *filename,
|
||||||
|
FAR void *arg)
|
||||||
|
{
|
||||||
|
FAR char *dumppath = arg;
|
||||||
|
|
||||||
|
sprintf(dumppath, "%s/%s", path, filename);
|
||||||
|
printf("Remove %s\n", dumppath);
|
||||||
|
remove(dumppath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* coredump_restore
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void coredump_restore(FAR char *savepath, size_t maxfile)
|
||||||
|
{
|
||||||
|
FAR struct coredump_info_s *info;
|
||||||
|
unsigned char *swap;
|
||||||
|
char dumppath[PATH_MAX];
|
||||||
|
struct geometry geo;
|
||||||
|
ssize_t writesize;
|
||||||
|
ssize_t readsize;
|
||||||
|
struct tm *dtime;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t max = 0;
|
||||||
|
int dumpfd;
|
||||||
|
int blkfd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
blkfd = open(CONFIG_BOARD_COREDUMP_BLKDEV_PATH, O_RDWR);
|
||||||
|
if (blkfd < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(blkfd, BIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
goto blkfd_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = malloc(geo.geo_sectorsize);
|
||||||
|
if (info == NULL)
|
||||||
|
{
|
||||||
|
goto blkfd_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(blkfd, (geo.geo_nsectors - 1) * geo.geo_sectorsize, SEEK_SET);
|
||||||
|
read(blkfd, info, geo.geo_sectorsize);
|
||||||
|
if (info->magic != COREDUMP_MAGIC)
|
||||||
|
{
|
||||||
|
printf("%s coredump not found!\n", CONFIG_BOARD_COREDUMP_BLKDEV_PATH);
|
||||||
|
goto info_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dumpfile_iterate(savepath, dumpfile_count, &max);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
goto info_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max >= maxfile)
|
||||||
|
{
|
||||||
|
ret = dumpfile_iterate(savepath, dumpfile_delete, dumppath);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
goto info_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = snprintf(dumppath, sizeof(dumppath),
|
||||||
|
"%s/core-%s", savepath,
|
||||||
|
info->name.version);
|
||||||
|
dtime = localtime(&info->time);
|
||||||
|
if (dtime)
|
||||||
|
{
|
||||||
|
ret += snprintf(dumppath + ret, sizeof(dumppath) - ret,
|
||||||
|
"-%d-%d-%d-%d-%d", dtime->tm_mon + 1,
|
||||||
|
dtime->tm_mday, dtime->tm_hour,
|
||||||
|
dtime->tm_min, dtime->tm_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
|
ret += snprintf(dumppath + ret, sizeof(dumppath) - ret, ".lzf");
|
||||||
|
#else
|
||||||
|
ret += snprintf(dumppath + ret, sizeof(dumppath) - ret, ".core");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (ret--)
|
||||||
|
{
|
||||||
|
if (dumppath[ret] == ' ' || dumppath[ret] == ':')
|
||||||
|
{
|
||||||
|
dumppath[ret] = '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dumpfd = open(dumppath, O_CREAT | O_WRONLY | O_TRUNC, 0777);
|
||||||
|
if (dumpfd < 0)
|
||||||
|
{
|
||||||
|
printf("Open %s fail\n", dumppath);
|
||||||
|
goto info_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap = malloc(geo.geo_sectorsize);
|
||||||
|
if (swap == NULL)
|
||||||
|
{
|
||||||
|
printf("Malloc fail\n");
|
||||||
|
goto fd_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(blkfd, 0, SEEK_SET);
|
||||||
|
while (offset < info->size)
|
||||||
|
{
|
||||||
|
readsize = read(blkfd, swap, geo.geo_sectorsize);
|
||||||
|
if (readsize < 0)
|
||||||
|
{
|
||||||
|
printf("Read %s fail\n", CONFIG_BOARD_COREDUMP_BLKDEV_PATH);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writesize = write(dumpfd, swap, readsize);
|
||||||
|
if (writesize != readsize)
|
||||||
|
{
|
||||||
|
printf("Write %s fail\n", dumppath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += writesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Coredump finish [%s][%zu]\n", dumppath, info->size);
|
||||||
|
info->magic = 0;
|
||||||
|
lseek(blkfd, (geo.geo_nsectors - 1) * geo.geo_sectorsize, SEEK_SET);
|
||||||
|
write(blkfd, info, geo.geo_sectorsize);
|
||||||
|
free(swap);
|
||||||
|
fd_err:
|
||||||
|
close(dumpfd);
|
||||||
|
info_err:
|
||||||
|
free(info);
|
||||||
|
blkfd_err:
|
||||||
|
close(blkfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* coredump_now
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int coredump_now(int pid, FAR char *filename)
|
||||||
{
|
{
|
||||||
FAR struct lib_stdoutstream_s *outstream;
|
FAR struct lib_stdoutstream_s *outstream;
|
||||||
FAR struct lib_hexdumpstream_s *hstream;
|
FAR struct lib_hexdumpstream_s *hstream;
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
FAR struct lib_lzfoutstream_s *lstream;
|
FAR struct lib_lzfoutstream_s *lstream;
|
||||||
char *name = NULL;
|
#endif
|
||||||
FAR void *stream;
|
FAR void *stream;
|
||||||
|
FAR FILE *file;
|
||||||
int logmask;
|
int logmask;
|
||||||
int pid = 0;
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (argc >= 2)
|
if (filename != NULL)
|
||||||
{
|
{
|
||||||
pid = atoi(argv[1]);
|
file = fopen(filename, "w");
|
||||||
if (pid == 0)
|
|
||||||
{
|
|
||||||
name = argv[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc >= 3)
|
|
||||||
{
|
|
||||||
if (name == NULL)
|
|
||||||
{
|
|
||||||
name = argv[2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pid = atoi(argv[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == 0)
|
|
||||||
{
|
|
||||||
pid = INVALID_PROCESS_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name != NULL)
|
|
||||||
{
|
|
||||||
file = fopen(name, "w");
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
{
|
{
|
||||||
return 1;
|
return -errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -92,29 +270,37 @@ int main(int argc, FAR char *argv[])
|
|||||||
file = stdout;
|
file = stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
hstream = malloc(sizeof(*hstream) + sizeof(*lstream) + sizeof(*outstream));
|
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
|
hstream = malloc(sizeof(*hstream) + sizeof(*lstream) +
|
||||||
|
sizeof(*outstream));
|
||||||
|
#else
|
||||||
|
hstream = malloc(sizeof(*hstream) + sizeof(*outstream));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hstream == NULL)
|
if (hstream == NULL)
|
||||||
{
|
{
|
||||||
if (name != NULL)
|
if (filename != NULL)
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
lstream = (FAR void *)(hstream + 1);
|
lstream = (FAR void *)(hstream + 1);
|
||||||
outstream = (FAR void *)(lstream + 1);
|
outstream = (FAR void *)(lstream + 1);
|
||||||
|
#else
|
||||||
logmask = setlogmask(LOG_ALERT);
|
outstream = (FAR void *)(hstream + 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("Start coredump:\n");
|
printf("Start coredump:\n");
|
||||||
|
logmask = setlogmask(LOG_ALERT);
|
||||||
|
|
||||||
/* Initialize hex output stream */
|
/* Initialize hex output stream */
|
||||||
|
|
||||||
lib_stdoutstream(outstream, file);
|
lib_stdoutstream(outstream, file);
|
||||||
lib_hexdumpstream(hstream, (FAR void *)outstream);
|
lib_hexdumpstream(hstream, (FAR void *)outstream);
|
||||||
|
|
||||||
stream = hstream;
|
stream = hstream;
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
@ -129,21 +315,109 @@ int main(int argc, FAR char *argv[])
|
|||||||
/* Do core dump */
|
/* Do core dump */
|
||||||
|
|
||||||
core_dump(NULL, stream, pid);
|
core_dump(NULL, stream, pid);
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
|
||||||
printf("Finish coredump (Compression Enabled).\n");
|
|
||||||
#else
|
|
||||||
printf("Finish coredump.\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setlogmask(logmask);
|
setlogmask(logmask);
|
||||||
|
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||||
|
printf("Finish coredump (Compression Enabled).\n");
|
||||||
|
# else
|
||||||
|
printf("Finish coredump.\n");
|
||||||
|
# endif
|
||||||
|
|
||||||
free(hstream);
|
free(hstream);
|
||||||
|
if (filename != NULL)
|
||||||
if (name != NULL)
|
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* usage
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void usage(FAR const char *progname, int exitcode)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s [option]:\n", progname);
|
||||||
|
fprintf(stderr, "Default usage, will coredump directly\n");
|
||||||
|
fprintf(stderr, "\t -p, --pid <pid>, Default, all thread\n");
|
||||||
|
fprintf(stderr, "\t -f, --filename <filename>, Default stdout\n");
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
fprintf(stderr, "Second usage, will restore coredump"
|
||||||
|
"from %s to savepath\n",
|
||||||
|
CONFIG_BOARD_COREDUMP_BLKDEV_PATH);
|
||||||
|
fprintf(stderr, "\t -s, --savepath <savepath>\n");
|
||||||
|
fprintf(stderr, "\t -m, --maxfile <maxfile>,"
|
||||||
|
"Maximum number of coredump files, Default 1\n");
|
||||||
|
#endif
|
||||||
|
exit(exitcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* coredump_main
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int main(int argc, FAR char *argv[])
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
FAR char *savepath = NULL;
|
||||||
|
size_t maxfile = 1;
|
||||||
|
#endif
|
||||||
|
char *name = NULL;
|
||||||
|
int pid = INVALID_PROCESS_ID;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
struct option options[] =
|
||||||
|
{
|
||||||
|
{"pid", 1, NULL, 'p'},
|
||||||
|
{"filename", 1, NULL, 'f'},
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
{"savepath", 1, NULL, 's'},
|
||||||
|
{"maxfile", 1, NULL, 'm'},
|
||||||
|
#endif
|
||||||
|
{"help", 0, NULL, 'h'}
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((ret = getopt_long(argc, argv, "p:f:s:m:h", options, NULL))
|
||||||
|
!= ERROR)
|
||||||
|
{
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case 'p':
|
||||||
|
pid = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
name = optarg;
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
case 's':
|
||||||
|
savepath = optarg;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
maxfile = atoi(optarg);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
usage(argv[0], EXIT_SUCCESS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
|
||||||
|
if (savepath != NULL)
|
||||||
|
{
|
||||||
|
coredump_restore(savepath, maxfile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
coredump_now(pid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user