mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 01:03:07 +00:00
libdrgn: add read(2) and pread(2) wrappers that don't return short reads
We have a couple of loops that deal with short reads/EINTR from read(2) and pread(2), and upcoming changes would need to add more. Add some wrappers to abstract this away. drgn_read_memory_file() still needs the loop so it can fault on the exact offset that returns EIO. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
56fda2a0cf
commit
b8cdfff250
@ -269,7 +269,7 @@ TAB_SIZE = 4
|
||||
# commands \{ and \} for these it is advised to use the version @{ and @} or use
|
||||
# a double escape (\\{ and \\})
|
||||
|
||||
ALIASES =
|
||||
ALIASES = manpage{2}="<a href=\"http://man7.org/linux/man-pages/man\2/\1.\2.html\">\1(\2)</a>"
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C. For
|
||||
|
@ -55,6 +55,8 @@ libdrgnimpl_la_SOURCES = $(ARCH_DEFS_PYS:_defs.py=.c) \
|
||||
hash_table.c \
|
||||
hash_table.h \
|
||||
helpers.h \
|
||||
io.c \
|
||||
io.h \
|
||||
language.c \
|
||||
language.h \
|
||||
language_c.c \
|
||||
|
50
libdrgn/io.c
Normal file
50
libdrgn/io.c
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "io.h"
|
||||
|
||||
ssize_t read_all(int fd, void *buf, size_t count)
|
||||
{
|
||||
if (count > SSIZE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size_t n = 0;
|
||||
while (n < count) {
|
||||
ssize_t r = read(fd, (char *)buf + n, count - n);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
break;
|
||||
}
|
||||
n += r;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t pread_all(int fd, void *buf, size_t count, off_t offset)
|
||||
{
|
||||
if (count > SSIZE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size_t n = 0;
|
||||
while (n < count) {
|
||||
ssize_t r = pread(fd, (char *)buf + n, count - n, offset + n);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
break;
|
||||
}
|
||||
n += r;
|
||||
}
|
||||
return n;
|
||||
}
|
27
libdrgn/io.h
Normal file
27
libdrgn/io.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Input/output helpers.
|
||||
*/
|
||||
|
||||
#ifndef DRGN_IO_H
|
||||
#define DRGN_IO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* Wrapper around \manpage{read,2} that never returns less bytes than requested unless it
|
||||
* hits end-of-file.
|
||||
*/
|
||||
ssize_t read_all(int fd, void *buf, size_t count);
|
||||
|
||||
/**
|
||||
* Wrapper around \manpage{pread,2} that never returns less bytes than requested unless
|
||||
* it hits end-of-file.
|
||||
*/
|
||||
ssize_t pread_all(int fd, void *buf, size_t count, off_t offset);
|
||||
|
||||
#endif /* DRGN_IO_H */
|
@ -23,6 +23,7 @@
|
||||
#include "error.h"
|
||||
#include "hash_table.h"
|
||||
#include "helpers.h"
|
||||
#include "io.h"
|
||||
#include "linux_kernel.h"
|
||||
#include "platform.h"
|
||||
#include "program.h"
|
||||
@ -630,27 +631,17 @@ kernel_module_iterator_gnu_build_id_live(struct kernel_module_iterator *it,
|
||||
goto out;
|
||||
}
|
||||
|
||||
char *buf = it->build_id_buf;
|
||||
size_t size = 0;
|
||||
while (size < st.st_size) {
|
||||
ssize_t r = read(fd, buf + size, st.st_size - size);
|
||||
ssize_t r = read_all(fd, it->build_id_buf, st.st_size);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
err = drgn_error_format_os("read", errno,
|
||||
"%s/%s", path,
|
||||
err = drgn_error_format_os("read", errno, "%s/%s", path,
|
||||
ent->d_name);
|
||||
close(fd);
|
||||
goto out;
|
||||
} else if (r == 0) {
|
||||
break;
|
||||
}
|
||||
size += r;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
*build_id_len_ret = parse_gnu_build_id_from_note(buf, size,
|
||||
false,
|
||||
*build_id_len_ret =
|
||||
parse_gnu_build_id_from_note(it->build_id_buf, r, false,
|
||||
build_id_ret);
|
||||
if (*build_id_len_ret) {
|
||||
err = NULL;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "debug_info.h"
|
||||
#include "error.h"
|
||||
#include "helpers.h"
|
||||
#include "io.h"
|
||||
#include "language.h"
|
||||
#include "linux_kernel.h"
|
||||
#include "memory_reader.h"
|
||||
@ -205,23 +206,11 @@ static struct drgn_error *has_kdump_signature(const char *path, int fd,
|
||||
bool *ret)
|
||||
{
|
||||
char signature[KDUMP_SIG_LEN];
|
||||
size_t n = 0;
|
||||
|
||||
while (n < sizeof(signature)) {
|
||||
ssize_t sret;
|
||||
|
||||
sret = pread(fd, signature + n, sizeof(signature) - n, n);
|
||||
if (sret == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
ssize_t r = pread_all(fd, signature, sizeof(signature), 0);
|
||||
if (r < 0)
|
||||
return drgn_error_create_os("pread", errno, path);
|
||||
} else if (sret == 0) {
|
||||
*ret = false;
|
||||
return NULL;
|
||||
}
|
||||
n += sret;
|
||||
}
|
||||
*ret = memcmp(signature, KDUMP_SIGNATURE, sizeof(signature)) == 0;
|
||||
*ret = (r == sizeof(signature)
|
||||
&& memcmp(signature, KDUMP_SIGNATURE, sizeof(signature)) == 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user