summaryrefslogtreecommitdiff
path: root/proc-region-rw.c
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-10-18 15:07:39 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2018-10-18 15:07:39 +0300
commit82eb10b0c7ae9382a4bbc97071c74de9055ad56e (patch)
tree06054053835f3ce37b01c7da8bba4638986a4727 /proc-region-rw.c
parenta939c762524f6bc6da41a5ebce0f83617d6267a5 (diff)
Nicer cli interface
Remove some behaviour that isn't clear to user, such as if no offset argument is given, write uses the map offsets from regions to write data from file starting from the region's map offset! now write is explicit and does exactly what you would expect. map is provided for remapping regions, that is providing file (such as shared library usually), and it will write contents of it starting from the region map offset for each given region. Assuming maps has this line: `7f392b87e000-7f392b8b9000 r-xp 00017000 08:01 133842 /usr/lib/libncursesw.so.6.1` And we do this: `proc-region-rw <pid> write /usr/lib/libncursesw.so << maps` The contents of /usr/lib/libncursesw.so would be written to 7f392b87e000-7f392b8b9000 (This will most likely cause htop to crash) Now if we do this instead: `proc-region-rw <pid> map /usr/lib/libncursesw.so << maps` The contents of /usr/lib/libncursesw.so _starting from offset 000170000_ would be written to 7f392b87e000-7f392b8b9000. Notice the difference, map function uses the offset information from region, to write contents from the input file, starting from the offset in the region. (This should not crash htop.)
Diffstat (limited to 'proc-region-rw.c')
-rw-r--r--proc-region-rw.c104
1 files changed, 65 insertions, 39 deletions
diff --git a/proc-region-rw.c b/proc-region-rw.c
index 0c1ca4f..c2a9b13 100644
--- a/proc-region-rw.c
+++ b/proc-region-rw.c
@@ -11,13 +11,15 @@ struct context {
struct {
size_t offset, len;
- bool with_offset_and_len;
+ bool has_offset, has_len;
struct {
FILE *src;
- } write;
+ size_t size;
+ } wm; // write/map
enum {
+ MODE_MAP,
MODE_WRITE,
MODE_READ
} mode;
@@ -32,44 +34,57 @@ struct context {
static void
usage(const char *argv0)
{
- fprintf(stderr, "usage: %s pid write file [offset len] < regions\n"
- " %s pid read [offset len] < regions\n\n"
- " regions must be in /proc/<pid>/maps format", argv0, argv0);
+ fprintf(stderr, "usage: %s pid map file [offset] [len] < regions\n"
+ " %s pid write file [offset] [len] < regions\n"
+ " %s pid read [offset] [len] < regions\n"
+ " regions must be in /proc/<pid>/maps format", argv0, argv0, argv0);
exit(EXIT_FAILURE);
}
static void
-context_init(struct context *ctx, int argc, const char *argv[])
+context_init(struct context *ctx, size_t argc, const char *argv[])
{
if (argc < 3)
usage(argv[0]);
+ size_t arg = 1;
*ctx = (struct context){0};
- ctx->proc.pid = strtoull(argv[1], NULL, 10);
+ ctx->proc.pid = strtoull(argv[arg++], NULL, 10);
{
- bool w, r;
- const char *mode = argv[2];
- if ((w = strcmp(mode, "write")) && (r = strcmp(mode, "read")))
+ bool w = false, r = false, m = false;
+ const char *mode = argv[arg++];
+ if (!(m = !strcmp(mode, "map")) && !(w = !strcmp(mode, "write")) && !(r = !strcmp(mode, "read")))
err(EXIT_FAILURE, "mode must be write or read");
- ctx->op.mode = (!w ? MODE_WRITE : MODE_READ);
+ ctx->op.mode = (m ? MODE_MAP : (w ? MODE_WRITE : MODE_READ));
}
- if (ctx->op.mode == MODE_WRITE && argc < 4)
- usage(argv[0]);
-
- if (argc > (ctx->op.mode == MODE_WRITE) + 3) {
- if (argc < (ctx->op.mode == MODE_WRITE) + 5)
+ const char *wmname = NULL;
+ if (ctx->op.mode == MODE_MAP || ctx->op.mode == MODE_WRITE) {
+ if (argc < arg + 1)
usage(argv[0]);
- ctx->op.offset = strtoull(argv[(ctx->op.mode == MODE_WRITE) + 3], NULL, 10);
- ctx->op.len = strtoull(argv[(ctx->op.mode == MODE_WRITE) + 4], NULL, 10);
- ctx->op.with_offset_and_len = true;
+ wmname = argv[arg++];
+ }
+
+ if (argc >= arg + 1) {
+ ctx->op.offset = strtoull(argv[arg++], NULL, 10);
+ ctx->op.has_offset = true;
+ }
+
+ if (argc >= arg + 1) {
+ ctx->op.len = strtoull(argv[arg++], NULL, 10);
+ ctx->op.has_len = true;
}
- if (ctx->op.mode == MODE_WRITE && !(ctx->op.write.src = fopen(argv[3], "rb")))
- err(EXIT_FAILURE, "fopen(%s)", argv[3]);
+ if (wmname && !(ctx->op.wm.src = fopen(wmname, "rb")))
+ err(EXIT_FAILURE, "fopen(%s)", wmname);
+
+ if (fseek(ctx->op.wm.src, 0, SEEK_END) != 0)
+ err(EXIT_FAILURE, "fseek");
+
+ ctx->op.wm.size = ftell(ctx->op.wm.src);
char path[128];
snprintf(path, sizeof(path), "/proc/%u/mem", ctx->proc.pid);
@@ -80,8 +95,8 @@ context_init(struct context *ctx, int argc, const char *argv[])
static void
context_release(struct context *ctx)
{
- if (ctx->op.write.src)
- fclose(ctx->op.write.src);
+ if (ctx->op.wm.src)
+ fclose(ctx->op.wm.src);
fclose(ctx->proc.mem);
free(ctx->buf);
@@ -112,25 +127,23 @@ static void
region_cb(const char *line, void *data)
{
struct context *ctx = data;
- unsigned long start, end, offset;
- if (sscanf(line, "%lx-%lx %*s %lx", &start, &end, &offset) < 3) {
+ unsigned long start, end, region_offset;
+ if (sscanf(line, "%lx-%lx %*s %lx", &start, &end, &region_offset) < 3) {
warnx("failed to parse mapping:\n%s", line);
return;
}
warnx("%s", line);
+ start += ctx->op.offset;
- offset = (ctx->op.with_offset_and_len ? 0 : offset);
- const size_t len = (ctx->op.with_offset_and_len ? ctx->op.len : end - start);
- if (start + ctx->op.offset > end) {
- warnx("write offset %lx is out of bounds", start + ctx->op.offset);
+ if (start > end) {
+ warnx("write offset %lx is out of bounds", start);
return;
}
- if (len > (end - start - ctx->op.offset)) {
- warnx("%zu bytes doesn't fit in the region", len);
- return;
- }
+ region_offset = (ctx->op.mode == MODE_MAP ? region_offset : 0);
+ const size_t rlen = (ctx->op.has_len ? ctx->op.len : ctx->op.wm.size); // requested write/read
+ const size_t len = (rlen > end - start ? end - start : rlen); // actual write/read
if (!len)
return;
@@ -139,24 +152,37 @@ region_cb(const char *line, void *data)
err(EXIT_FAILURE, "realloc");
clearerr(ctx->proc.mem);
- if (ctx->op.mode == MODE_WRITE) {
- if (fseek(ctx->op.write.src, offset, SEEK_SET) != 0)
+ if (ctx->op.mode == MODE_MAP || ctx->op.mode == MODE_WRITE) {
+ if (fseek(ctx->op.wm.src, region_offset, SEEK_SET) != 0)
err(EXIT_FAILURE, "fseek");
- const size_t rd = fread(ctx->buf, 1, len, ctx->op.write.src);
+ const size_t rd = fread(ctx->buf, 1, len, ctx->op.wm.src);
- if (fseek(ctx->proc.mem, start + ctx->op.offset, SEEK_SET) != 0)
+ if (fseek(ctx->proc.mem, start, SEEK_SET) != 0)
err(EXIT_FAILURE, "fseek");
const size_t wd = fwrite(ctx->buf, 1, rd, ctx->proc.mem);
if (ferror(ctx->proc.mem)) {
warn("fread(/proc/%u/mem)", ctx->proc.pid);
+ return;
+ }
+
+ if (ctx->op.mode == MODE_WRITE) {
+ if (rlen > wd) {
+ warnx("wrote %lu bytes (%lu bytes truncated) to offset 0x%lx", wd, rlen - wd, start);
+ } else {
+ warnx("wrote %lu bytes to offset 0x%lx", wd, start);
+ }
} else {
- warnx("wrote %lu bytes from offset 0x%lx to offset 0x%lx", wd, offset, start + ctx->op.offset);
+ if (rlen > wd) {
+ warnx("mapped %lu bytes (%lu bytes truncated) from offset 0x%lx to offset 0x%lx", wd, rlen - wd, region_offset, start);
+ } else {
+ warnx("mapped %lu bytes from offset 0x%lx to offset 0x%lx", wd, region_offset, start);
+ }
}
} else {
- if (fseek(ctx->proc.mem, start + ctx->op.offset, SEEK_SET) != 0)
+ if (fseek(ctx->proc.mem, start, SEEK_SET) != 0)
err(EXIT_FAILURE, "fseek");
const size_t rd = fread(ctx->buf, 1, len, ctx->proc.mem);