/**  @file kdumpfile.h
 * Public interface for `libkdumpfile` (kernel coredump file access).
*/
/* Copyright (C) 2014-2016 Petr Tesarik <ptesarik@suse.com>

   This file is free software; you can redistribute it and/or modify
   it under the terms of either

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at
       your option) any later version

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at
       your option) any later version

   or both in parallel, as here.

   libkdumpfile is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _KDUMPFILE_H
#define _KDUMPFILE_H	1

#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/sysmacros.h>

#include "addrxlat.h"

/** Major version (1st number in the release tag). */
#define KDUMPFILE_VER_MAJOR	0
/** Minor version (2nd number in the release tag). */
#define KDUMPFILE_VER_MINOR	5
/** Micro version (3rd number in the release tag). */
#define KDUMPFILE_VER_MICRO	5

/** Make a single-number version from three digits of the release tag. */
#define KDUMPFILE_MKVER(major,minor,micro)	\
	(((major) << 16) | ((minor) << 8) | ((micro)))

/** Version as a single number */
#define KDUMPFILE_VERSION		\
	KDUMPFILE_MKVER(		\
		KDUMPFILE_VER_MAJOR,	\
		KDUMPFILE_VER_MINOR,	\
		KDUMPFILE_VER_MICRO)

/** Version as a string constant */
#define KDUMPFILE_VERSION_STRING "0.5.5"

#ifdef  __cplusplus
extern "C" {
#endif

/**  Type of a generic number.
 *
 * This type is large enough to hold register value on any architecture
 * supported by `libkdumpfile`. Note that it may be larger than the
 * registers in the target.
 */
typedef uint_fast64_t kdump_num_t;

/** @name fprintf() macros for the libkdumpfile number type
 * @{
 *
 * POSIX @c PRI_xxx style macros for use with @ref kdump_num_t.
 */
#define KDUMP_PRIoNUM	PRIoFAST64 /**< Octal @c kdump_num_t */
#define KDUMP_PRIuNUM	PRIuFAST64 /**< Decimal @c kdump_num_t */
#define KDUMP_PRIxNUM	PRIxFAST64 /**< Lowercase hex @c kdump_num_t */
#define KDUMP_PRIXNUM	PRIXFAST64 /**< Uppercase hex @c kdump_num_t */
/* @} */

/**  Type of a physical or virtual address.
 *
 * This type is large enough to hold any possible address type on any
 * architecture supported by `libkdumpfile`. Note that this type may
 * be larger than the actual address in the target.
 */
typedef addrxlat_addr_t kdump_addr_t;

/**  Maximum value represented by @ref kdump_addr_t.
 */
#define KDUMP_ADDR_MAX	ADDRXLAT_ADDR_MAX

/**  Type of a physical address.
 *
 * Use this type instead of @ref kdump_addr_t if the entity is always
 * known to be a physical address.
 */
typedef kdump_addr_t kdump_paddr_t;

/**  Type of a virtual addresses.
 *
 * Use this type instead of @ref kdump_addr_t if the entity is always
 * known to be a virtual address.
 */
typedef kdump_addr_t kdump_vaddr_t;

/** @name fprintf() macros for the libkdumpfile address type
 * @{
 *
 * POSIX @c PRI_xxx style macros for use with @ref kdump_addr_t,
 * @ref kdump_paddr_t and @ref kdump_vaddr_t.
 */
#define KDUMP_PRIoADDR	ADDRXLAT_PRIoADDR /**< Octal address */
#define KDUMP_PRIuADDR	ADDRXLAT_PRIuADDR /**< Decimal address */
#define KDUMP_PRIxADDR	ADDRXLAT_PRIxADDR /**< Lowercase hex address */
#define KDUMP_PRIXADDR	ADDRXLAT_PRIXADDR /**< Uppercase hex address */
/* @} */

/**  Representation of a dump file.
 *
 * The context contains all information needed to work with a dump file.
 * It is an opaque type, so it can be modified and/or extended without
 * breaking binary compatibility with existing programs.
 */
typedef struct _kdump_ctx kdump_ctx_t;

/**  Status code.
 *
 * Return type of all (almost) library functions that may fail. It
 * provides a very rough description of the error. See @ref kdump_get_err
 * if you want a human-readable error description.
 */
typedef enum _kdump_status {
	KDUMP_OK = 0,		/**< Success. */
	KDUMP_ERR_SYSTEM,	/**< OS error, see @c errno. */
	KDUMP_ERR_NOTIMPL,	/**< Unimplemented feature. */
	KDUMP_ERR_NODATA,	/**< Data is not stored in the dump file. */
	KDUMP_ERR_CORRUPT,	/**< Corrupted file data. */
	KDUMP_ERR_INVALID,	/**< Invalid value. */
	KDUMP_ERR_NOKEY,	/**< No such attribute key. */
	KDUMP_ERR_EOF,		/**< Unexpected EOF. */
	KDUMP_ERR_BUSY,		/**< Too many pending requests. */
	KDUMP_ERR_ADDRXLAT,	/**< Address translation error. */
} kdump_status;

/**  Target dump byte order.
 *
 * Target byte order. Note that this may be different from the host byte
 * order. The library will convert any values it needs internally, but
 * if you read any data from the dump file, you are responsible for
 * converting the data to the host byte order.
 *
 * @sa KDUMP_ATTR_BYTE_ORDER
 */
typedef enum _kdump_byte_order {
	KDUMP_BIG_ENDIAN = ADDRXLAT_BIG_ENDIAN,
	KDUMP_LITTLE_ENDIAN = ADDRXLAT_LITTLE_ENDIAN,
} kdump_byte_order_t;

/**  File mmap policy.
 *
 * Control if and how mmap(2) should be used to access data from the
 * underlying core file.
 *
 * @sa KDUMP_ATTR_FILE_MMAP_POLICY
 */
typedef enum _kdump_mmap_policy {
	KDUMP_MMAP_NEVER,	/**< Never use mmap(2), always use read(2). */
	KDUMP_MMAP_ALWAYS,	/**< Always use mmap(2), never use read(2). */
	KDUMP_MMAP_TRY,		/**< Try mmap(2), fall back to read(2). */

	/** Same as @c KDUMP_MMAP_TRY, but change to @c KDUMP_MMAP_NEVER
	 *  or @c KDUMP_MMAP_ALWAYS based on the result of the next read.
	 */
	KDUMP_MMAP_TRY_ONCE,
} kdump_mmap_policy_t;

/**  Type of a Xen dump.
 * @sa KDUMP_ATTR_XEN_TYPE
 */
typedef enum _kdump_xen_type {
	KDUMP_XEN_NONE,		/**< Not running under Xen */
	KDUMP_XEN_SYSTEM,	/**< Comlete dump of a Xen machine */
	KDUMP_XEN_DOMAIN,	/**< Dump of a single domain */
} kdump_xen_type_t;

/**  Xen physmap translation type.
 * @sa KDUMP_ATTR_XEN_XLAT
 */
typedef enum _kdump_xen_xlat {
	KDUMP_XEN_AUTO,		/**< Auto-translated physmap */
	KDUMP_XEN_NONAUTO	/**< Non-auto-translated physmap */
} kdump_xen_xlat_t;

/**  Initialize a new dump file object.
 * @returns    New initialized object, or @c NULL on failure.
 *
 * Use this function to create a new @ref kdump_ctx_t. When the object
 * is no longer needed, you should free all resources with
 * @ref kdump_free.
 */
kdump_ctx_t *kdump_new(void);

/**  Clone flag bits.
 * Bit positions for individual clone flags.
 */
enum kdump_clone_bits {
	KDUMP_CLONE_BIT_XLAT,	/*< Do not share address translation. */
};

/** @name Clone Flags
 * @{
 */
/** Do not share address translation. */
#define KDUMP_CLONE_XLAT	(1UL << KDUMP_CLONE_BIT_XLAT)
/* @} */

/**  Clone a dump file object.
 * @param orig  Original dump file object.
 * @param flags Specify which data should be shared with the original.
 * @returns     Cloned dump file object, or @c NULL on allocation error.
 *
 * A cloned dump file object shares file descriptor, cache, attributes and
 * other data with the original, according to @c flags.  Changes of shared
 * data in one of the objects are also seen by the other object.
 *
 * The following fields are *not* shared:
 * - address translation context (see @ref kdump_get_addrxlat_ctx),
 * - error string (see @ref kdump_get_err),
 *
 * Private data and callbacks are initialized to their values from the
 * @p orig context here.
 *
 * @sa @ref threads
 */
kdump_ctx_t *kdump_clone(const kdump_ctx_t *orig, unsigned long flags);

/**  Free a dump file object.
 * @param ctx  Object to be freed.
 *
 * Free all resources associated with the dump file. Do not just call
 * @c free(ctx), because that may leak some resources.
 *
 * The object must not be used after calling this function.
 */
void kdump_free(kdump_ctx_t *ctx);

/** Prepend an error message.
 * @param ctx     Dump file object.
 * @param status  Error status.
 * @param msgfmt  Message format string (@c printf style).
 * @returns       The error status which was passed as argument.
 *
 * This function prepends the new error message to the existing
 * content of the error buffer, resulting in a kind of error
 * backtrace.
 */
kdump_status kdump_err(
	kdump_ctx_t *ctx, kdump_status status, const char *msgfmt, ...)
	__attribute__ ((format (printf, 3, 4)));

/** Clear the error message.
 * @param ctx  Dump file object.
 */
void kdump_clear_err(kdump_ctx_t *ctx);

/**  Get a detailed error string.
 * @param ctx  Dump file object.
 * @returns    Error string, or @c NULL if there was no error.
 *
 * If an error status is returned, this function can be used to get
 * a human-readable description of the error. The error string is not
 * reset by calling this function, but it is reset by calling any
 * library function that returns @ref kdump_status.
 */
const char *kdump_get_err(kdump_ctx_t *ctx);

/**  Get the associated address translation data structures.
 * @param ctx    Dump file object.
 * @param axctx  Address translation context (filled on return).
 * @param axsys  Address translation system (filled on return).
 * @returns      Error status.
 *
 * You may pass @c NULL as a target parameter if you don't need that
 * specific object.
 *
 * This function grabs a new reference.  You should call addrxlat_ctx_decref
 * and/or addrxlat_sys_decref on the returned object(s) when you no longer
 * need them.
 */
kdump_status kdump_get_addrxlat(kdump_ctx_t *ctx,
				addrxlat_ctx_t **axctx,
				addrxlat_sys_t **axsys);

/** Convert a 16-bit value from dump to host byte order.
 * @param ctx  Dump file object.
 * @param val  Value in dump file byte order.
 * @returns    Value in host byte order.
 */
uint_fast16_t kdump_d16toh(kdump_ctx_t *ctx, uint_fast16_t val);

/** Convert a 32-bit value from dump to host byte order.
 * @param ctx  Dump file object.
 * @param val  Value in dump file byte order.
 * @returns    Value in host byte order.
 */
uint_fast32_t kdump_d32toh(kdump_ctx_t *ctx, uint_fast32_t val);

/** Convert a 64-bit value from dump to host byte order.
 * @param ctx  Dump file object.
 * @param val  Value in dump file byte order.
 * @returns    Value in host byte order.
 */
uint_fast64_t kdump_d64toh(kdump_ctx_t *ctx, uint_fast64_t val);

/** Set descriptive file names.
 * @param ctx    Dump file object.
 * @param n      Number of names in @p names.
 * @param names  Names. @c NULL means clear the name.
 * @returns      Error status.
 *
 * Set the optional file names. These names are used in error messages to give
 * humans a clue which file of a multi-file dump the error is related.
 */
kdump_status kdump_set_filenames(kdump_ctx_t *ctx, unsigned n,
				 const char *const *names);

/** Set a file name.
 * @param ctx   Dump file object.
 * @param name  File name.
 * @returns     Error status.
 *
 * This is a shortcut for naming a single-file dump.
 */
static inline kdump_status
kdump_set_filename(kdump_ctx_t *ctx, const char *name)
{
	return kdump_set_filenames(ctx, 1, &name);
}

/** Open a set of dump files.
 * @param ctx   Dump file object.
 * @param nfds  Number of file descriptors in @p fds.
 * @param fds   Open file descriptors.
 * @returns     Error status.
 *
 * Set up file.fdset attribute subtree to open a set of dump files.
 *
 * Note: Only file descriptors are replaced by this call; if file name
 * attributes were set before the call, they are not changed. However, this
 * function sets file.set.number to @p nfds, which discards file.set.x
 * sub-directories for x greater than or equal to @p nfds, INCLUDING any
 * respective file.set.x.name attributes.
 */
kdump_status kdump_open_fdset(kdump_ctx_t *ctx, unsigned nfds, const int *fds);

/** Open a dump file.
 * @param ctx  Dump file object.
 * @param fd   Open file descriptor.
 * @returns    Error status.
 *
 * This is a shortcut for opening a single-file dump.
 */
static inline kdump_status
kdump_open_fd(kdump_ctx_t *ctx, int fd)
{
	return kdump_open_fdset(ctx, 1, &fd);
}

/**  Address spaces used by kdump_read()
 *
 * When passing an address to kdump_read(), this type is used to
 * specify the kind of address.
 *
 * The numeric values shall match those of @ref addrxlat_addrspace_t.
 */
typedef enum _kdump_addrspace {
	/** Kernel physical address. */
	KDUMP_KPHYSADDR = ADDRXLAT_KPHYSADDR,

	/** Machine physical address. */
	KDUMP_MACHPHYSADDR = ADDRXLAT_MACHPHYSADDR,

	/** Kernel virtual address. */
	KDUMP_KVADDR = ADDRXLAT_KVADDR,

	/** Invalid address. */
	KDUMP_NOADDR = ADDRXLAT_NOADDR,
} kdump_addrspace_t;

/**  Read data from the dump file.
 * @param ctx              Dump file object.
 * @param[in] as           Address space of @c addr.
 * @param[in] addr         Any type of address.
 * @param[out] buffer      Buffer to receive data.
 * @param[in,out] plength  Length of the buffer.
 * @returns                Error status.
 *
 * Read data from a dump file. On return, the length of the buffer pointed
 * to by @c plength is updated to reflect the actual number of bytes read
 * from the dump file.
 *
 * If @c kdump_read returns @ref KDUMP_OK, then all requested bytes have
 * been read successfully, and the value referenced by @p plength is not
 * changed. However, if the read fails, some bytes may already have been
 * read, and their number is reported in this variable, so the caller may
 * process a partial read.
 *
 * In particular, if some pages were filtered out, @c kdump_read may return
 * @ref KDUMP_ERR_NODATA when it reaches the filtered out page.
 */
kdump_status kdump_read(kdump_ctx_t *ctx,
			 kdump_addrspace_t as, kdump_addr_t addr,
			 void *buffer, size_t *plength);

/**  Read a string from the dump file.
 * @param ctx        Dump file object.
 * @param[in] as     Address space of @c addr.
 * @param[in] addr   Any type of address.
 * @param[out] pstr  String to be read.
 * @returns          Error status.
 *
 * Use this function to read a NUL-terminated string at address @c addr.
 * The resulting string is allocated dynamically, and you should free
 * it with the @c free library function when it is no longer needed.
 * This function is usually more efficient than implementing the same
 * thing with @ref kdump_read.
 */
kdump_status kdump_read_string(kdump_ctx_t *ctx,
			       kdump_addrspace_t as, kdump_addr_t addr,
			       char **pstr);

/**  Dump bitmap.
 *
 * A bitmap contains the validity of indexed objects, e.g. pages
 * in a dump file (indexed by their page frame numbers).
 * It may not be implemented internally as an actual bitmap.
 */
typedef struct _kdump_bmp kdump_bmp_t;

/** Increment kdump bitmap reference counter.
 * @param map    Translation map.
 * @returns      New reference count.
 */
unsigned long kdump_bmp_incref(kdump_bmp_t *bmp);

/** Decrement kdump bitmap reference counter.
 * @param map    Translation map.
 * @returns      New reference count.
 *
 * If the new reference count is zero, the underlying object is freed
 * and its address must not be used afterwards.
 */
unsigned long kdump_bmp_decref(kdump_bmp_t *bmp);

/**  Get a detailed error string.
 * @param bmp  Bitmap object.
 * @returns    Last error string.
 *
 * If an error status is returned, this function can be used to get
 * a human-readable description of the error. The error string is not
 * reset by calling this function, but it is reset by calling any
 * other function that returns @ref kdump_status.
 */
const char *kdump_bmp_get_err(const kdump_bmp_t *bmp);

/**  Get bitmap bits as a raw bitmap.
 * @param bmp    Bitmap object.
 * @param first  First index in the bitmap.
 * @param last   Last index in the bitmap.
 * @param raw    Raw bitmap (updated on success).
 * @returns      Error status.
 */
kdump_status kdump_bmp_get_bits(
	kdump_bmp_t *bmp,
	kdump_addr_t first, kdump_addr_t last, unsigned char *raw);

/** Find the closest set bit in a bitmap.
 * @param bmp  Bitmap object.
 * @param idx  Starting index in the bitmap, updated on success.
 * @returns    Error status.
 */
kdump_status kdump_bmp_find_set(
	kdump_bmp_t *bmp, kdump_addr_t *idx);

/** Find the closest zero bit in a bitmap.
 * @param bmp  Bitmap object.
 * @param idx  Starting index in the bitmap, updated on success.
 * @returns    Error status.
 */
kdump_status kdump_bmp_find_clear(
	kdump_bmp_t *bmp, kdump_addr_t *idx);

/**  Dump binary large object (BLOB).
 *
 * A blob contains arbitrary binary data.
 */
typedef struct _kdump_blob kdump_blob_t;

/** Create a new blob object.
 * @param data  Raw data buffer (can be @c NULL).
 * @param size  Length of data at @c data.
 * @returns     New blob object, or @c NULL on allocation error.
 *
 * Create a new blob object from a dynamically allocated memory buffer.
 * Keep in mind that the buffer will be eventually de-allocated with
 * free(3) when the blob reference count drops to zero.
 *
 * If @c data is @c NULL, then the blob does not contain any data.
 *
 * The new object's reference count is initialized to 1 (the caller
 * receives one reference), and the memory buffer is not pinned.
 */
kdump_blob_t *kdump_blob_new(void *data, size_t size);

/** Create a new blob object from a copy of a buffer.
 * @param data  Raw data buffer (can be @c NULL).
 * @param size  Length of data at @c data.
 * @returns     New blob object, or @c NULL on allocation error.
 *
 * Create a new blob object by duplicating data from a buffer. The
 * data is copied into a newly allocated buffer which is owned by
 * the blob object itself.
 *
 * @sa kdump_blob_new
 */
kdump_blob_t *kdump_blob_new_dup(const void *data, size_t size);

/** Increment kdump blob reference counter.
 * @param blob   Binary object.
 * @returns      New reference count.
 */
unsigned long kdump_blob_incref(kdump_blob_t *blob);

/** Decrement kdump blob reference counter.
 * @param blob   Binary object.
 * @returns      New reference count.
 *
 * If the new reference count is zero, the underlying object is freed
 * and its address must not be used afterwards.
 */
unsigned long kdump_blob_decref(kdump_blob_t *blob);

/**  Pin the internal data buffer.
 * @param blob  Binary object.
 * @returns     Pointer to binary data.
 *
 * Returns pointer to the internal data buffer. The pointer is valid
 * until a matching call to @ref kdump_blob_unpin. While a blob is pinned,
 * it cannot be modified by a call to @ref kdump_blob_set or by any other
 * internal library operation. The blob is pinned if there is at least one
 * user of the data.
 */
void *kdump_blob_pin(kdump_blob_t *blob);

/**  Unpin the internal data buffer.
 * @param blob  Binary object.
 * @returns     Number of remaining pinned users.
 *
 * This function releases the data pointer, decreasing an internal pin
 * counter. When the counter reaches zero, any pointers to internal data
 * are no longer valid (but the blob object itself remains valid).
 */
unsigned long kdump_blob_unpin(kdump_blob_t *blob);

/**  Get a blob size in bytes.
 * @param blob  Binary object.
 * @returns     Size of the binary object in bytes.
 *
 * Note that an unpinned blob may be changed at any time, so you probably
 * want to call @ref kdump_blob_pin first.
 */
size_t kdump_blob_size(const kdump_blob_t *blob);

/**  Set kdump blob data.
 * @param blob  Binary object.
 * @param data  Pointer to new binary data.
 * @param size  Size of the new data in bytes.
 * @returns     Error status.
 *
 * Set the internal buffer to @c data. The buffer must be allocated from
 * the heap (i.e. using @c malloc and friends), because the library will
 * eventually call @c free on it!
 *
 * Attempts to set data of a pinned blob return @ref KDUMP_ERR_BUSY,
 * all other calls return @ref KDUMP_OK.
 *
 * It is OK to set the data to @c NULL.
 */
kdump_status kdump_blob_set(kdump_blob_t *blob, void *data, size_t size);

/**  Dump file attribute value type.
 */
typedef enum _kdump_attr_type {
	KDUMP_NIL,		/**< No type; used for deletions. */
	KDUMP_DIRECTORY,	/**< Attribute directory. */
	KDUMP_NUMBER,		/**< General number. */
	KDUMP_ADDRESS,		/**< Address or symbol value. */
	KDUMP_STRING,		/**< String attribute. */
	KDUMP_BITMAP,		/**< Bitmap. */
	KDUMP_BLOB,		/**< Binary large object. */
} kdump_attr_type_t;

/**  Dump file attribute value.
 */
typedef union _kdump_attr_value {
	kdump_num_t number;	/**< Valid if type is @ref KDUMP_NUMBER. */
	kdump_addr_t address;	/**< Valid if type is @ref KDUMP_ADDRESS.  */
	const char *string;	/**< Valid if type is @ref KDUMP_STRING. */
	kdump_bmp_t *bitmap;	/**< Valid if type is @ref KDUMP_BITMAP. */
	kdump_blob_t *blob;	/**< Valid if type is @ref KDUMP_BLOB. */
} kdump_attr_value_t;

/**  Dump file attribute: type + value.
 */
typedef struct _kdump_attr {
	kdump_attr_type_t type;	/**< Attribute type. */
	kdump_attr_value_t val;	/**< Attribute value. */
} kdump_attr_t;

/**  Reference to an attribute.
 * This type is used to make a fixed-size reference to an attribute,
 * rather than its (variable-size) key path.
 *
 * This type points to an internal structure which may change layout
 * without affecting the ABI, so callers must not make any attempts
 * to interpret that data.
 */
typedef struct _kdump_attr_ref {
	void *_ptr;		/**< Reference (private field). */
} kdump_attr_ref_t;

/**  Attribute iterator.
 * Iterators are used to iterate over all children of a directory
 * attribute. This is a public structure, so callers can allocate
 * it e.g. on stack.
 *
 * Note that the attribute name is stored in the structure, but
 * the attribute value is not. This allows to keep the same ABI
 * while implementing special attribute handling (e.g. calculate
 * the value on the fly).
 */
typedef struct _kdump_attr_iter {
	/** Attribute key.
	 * This is the attribute's name relative to parent (no dots),
	 * or @c NULL if end of iteration has been reached.
	 */
	const char *key;

	/** Iterator position.
	 * This field must not be modified by callers, but it can
	 * be used as an argument to the reference-handling functions.
	 */
	kdump_attr_ref_t pos;
} kdump_attr_iter_t;

/**  Set a dump file attribute.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param valp New attribute value.
 * @returns    Error status.
 */
kdump_status kdump_set_attr(kdump_ctx_t *ctx, const char *key,
			    const kdump_attr_t *valp);

/**  Set a numeric attribute.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param num  New attribute value.
 * @returns    Error status.
 */
static inline kdump_status
kdump_set_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t num)
{
	kdump_attr_t attr;
	attr.type = KDUMP_NUMBER;
	attr.val.number = num;
	return kdump_set_attr(ctx, key, &attr);
}

/**  Set an address attribute.
 * @param ctx   Dump file object.
 * @param key   Attribute key.
 * @param addr  New attribute value.
 * @returns     Error status.
 */
static inline kdump_status
kdump_set_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t addr)
{
	kdump_attr_t attr;
	attr.type = KDUMP_ADDRESS;
	attr.val.address = addr;
	return kdump_set_attr(ctx, key, &attr);
}

/**  Set a string attribute.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param str  New attribute value.
 * @returns    Error status.
 */
static inline kdump_status
kdump_set_string_attr(kdump_ctx_t *ctx, const char *key, const char *str)
{
	kdump_attr_t attr;
	attr.type = KDUMP_STRING;
	attr.val.string = str;
	return kdump_set_attr(ctx, key, &attr);
}

/**  Clear an attribute.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param str  New attribute value.
 * @returns    Error status.
 */
static inline kdump_status
kdump_clear_attr(kdump_ctx_t *ctx, const char *key)
{
	kdump_attr_t attr;
	attr.type = KDUMP_NIL;
	return kdump_set_attr(ctx, key, &attr);
}

/**  Get a dump file attribute.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param valp Value (filled on successful return).
 * @returns    Error status.
 *
 * This function is useful only when the caller can fully control the
 * lifetime of the returned attribute value. In that case, the value
 * is valid only as long as no changes are made to the containing dump
 * file object.
 *
 * Note that attribute data (or the attribute hierarchy itself) may
 * change as a side effect of another operation. Merely reading dump
 * data or attributes will never invalidate the attribute value, i.e.
 * it is safe to dereference pointers. However, the returned value may
 * become stale, for example cache statistics.
 *
 * A more robust API is provided by @ref kdump_attr_ref_get.
 */
kdump_status kdump_get_attr(kdump_ctx_t *ctx, const char *key,
			    kdump_attr_t *valp);

/**  Get a dump file attribute with a given type.
 * @param ctx  Dump file object.
 * @param key  Attribute key.
 * @param type Expected attribute type.
 * @param valp Value (updated on return).
 * @returns    Error status.
 *
 * If the attribute is of a different type, this function returns
 * KDUMP_ERR_INVALID and does not change @p valp.
 *
 * The caller must ensure the lifetime of the returned data is valid. See
 * the description of @ref kdump_get_attr for more details.
 */
kdump_status kdump_get_typed_attr(kdump_ctx_t *ctx, const char *key,
				  kdump_attr_type_t type,
				  kdump_attr_value_t *valp);

/** Get a numeric attribute.
 *
 * @param ctx       Dump file object.
 * @param key       Attribute key.
 * @param num[out]  Filled with the attribute value on successful return.
 * @returns         Error status.
 */
static inline kdump_status
kdump_get_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t *num)
{
	return kdump_get_typed_attr(ctx, key, KDUMP_NUMBER,
				    (kdump_attr_value_t *)num);
}

/** Get an address attribute.
 *
 * @param ctx        Dump file object.
 * @param key        Attribute key.
 * @param addr[out]  Filled with the attribute value on successful return.
 * @returns          Error status.
 */
static inline kdump_status
kdump_get_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t *addr)
{
	return kdump_get_typed_attr(ctx, key, KDUMP_ADDRESS,
				    (kdump_attr_value_t *)addr);
}

/** Get a string attribute.
 *
 * @param ctx       Dump file object.
 * @param key       Attribute key.
 * @param str[out]  Filled with the attribute value on successful return.
 * @returns         Error status.
 *
 * The caller must ensure the lifetime of the returned data is valid. See
 * the description of @ref kdump_get_attr for more details.
 */
static inline kdump_status
kdump_get_string_attr(kdump_ctx_t *ctx, const char *key, const char **str)
{
	return kdump_get_typed_attr(ctx, key, KDUMP_STRING,
				    (kdump_attr_value_t *)str);
}

/** Get a reference to an attribute
 * @param      ctx  Dump file object.
 * @param[in]  key  Attribute key.
 * @param[out] ref  Attribute reference (initialized on successful return).
 * @returns    Error status.
 *
 * A reference is a persistent pointer to the attribute, which stays
 * valid until the reference is dropped using @ref kdump_attr_unref,
 * or the whole dump file object is destroyed.
 */
kdump_status kdump_attr_ref(kdump_ctx_t *ctx, const char *key,
			    kdump_attr_ref_t *ref);

/** Get a reference to a subordinate attribute
 * @param      ctx     Dump file object.
 * @param[in]  base    Reference to base attribute.
 * @param[in]  subkey  Attribute key, relative to @p base.
 * @param[out] ref     Attribute reference (initialized on successful return).
 * @returns    Error status.
 */
kdump_status kdump_sub_attr_ref(kdump_ctx_t *ctx, const kdump_attr_ref_t *base,
				const char *subkey, kdump_attr_ref_t *ref);

/**  Drop a reference to an attribute.
 * @param ctx   Dump file object.
 * @param ref   Attribute reference.
 */
void kdump_attr_unref(kdump_ctx_t *ctx, kdump_attr_ref_t *ref);

/**  Get the type of an attribute by reference.
 * @param ref  Attribute reference.
 * @returns    Attribute type.
 */
kdump_attr_type_t kdump_attr_ref_type(kdump_attr_ref_t *ref);

/**  Check whether an attribute is set.
 * @param ref  Attrbute reference.
 * @returns    Non-zero if the attribute has a value, zero otherwise.
 */
int kdump_attr_ref_isset(kdump_attr_ref_t *ref);

/**  Get attribute data by reference.
 * @param      ctx   Dump file object.
 * @param[in]  ref   Attribute reference.
 * @param[out] valp  Attribute value (filled on return).
 * @returns          Error status.
 *
 * This works similarly to @ref kdump_get_attr, except:
 * - the attribute is denoted by a reference rather than by path,
 * - the returned data stays valid even if changes are made to the dump
 *   object.
 *
 * The returned value may be a dynamically allocated copy of the attribute
 * value and/or it may hold an extra reference to the underlying objects.
 * You should free up these resources with @ref kdump_attr_discard when
 * the data is no longer needed.
 *
 * If the function returns an error, it is not necessary to discard the
 * result. However, the type of @p valp is set to @c KDUMP_NIL, so it is
 * always safe to call @ref kdump_attr_discard on the result. The goal of
 * this feature is to simplify code flow in callers.
 */
kdump_status kdump_attr_ref_get(kdump_ctx_t *ctx, const kdump_attr_ref_t *ref,
				kdump_attr_t *valp);

/** Discard attribute data value.
 * @param ctx   Dump file object.
 * @param attr  Attribute data.
 *
 * Perform any actions necessary to release resources by the attribute data.
 * This function may decrement object references, free dynamically allocated
 * memory, or even do nothing, depending on the data type.
 *
 * Call this function when the data returned by @ref kdump_attr_ref_get is no
 * longer needed. Do *NOT* call this function on attribute data returned by
 * @ref kdump_get_attr.
 */
void
kdump_attr_discard(kdump_ctx_t *ctx, kdump_attr_t *attr);

/**  Set attribute data by reference.
 * @param      ctx   Dump file object.
 * @param[in]  ref   Attribute reference.
 * @param[in]  valp  New attribute value.
 *
 * This works just like @ref kdump_set_attr, except that the attribute
 * is denoted by a reference rather than by its key path.
 */
kdump_status kdump_attr_ref_set(kdump_ctx_t *ctx, kdump_attr_ref_t *ref,
				const kdump_attr_t *valp);

/**  Set a dump file attribute.
 * @param ctx     Dump file object.
 * @param base    Reference to a base attribute.
 * @param subkey  Attribute key, relative to @p base.
 * @param valp    New attribute value.
 * @returns       Error status.
 */
kdump_status kdump_set_sub_attr(kdump_ctx_t *ctx, const kdump_attr_ref_t *base,
				const char *subkey, const kdump_attr_t *valp);

/**  Get an attribute iterator.
 * @param      ctx   Dump file object.
 * @param[in]  path  Path to an attribute directory.
 * @param[out] iter  Attribute iterator.
 * @returns          Error status.
 *
 * On return, the iterator is set to the first child attribute. If the
 * attribute directory is empty, this function sets the @c key field
 * of @p iter to @c NULL and returns @ref KDUMP_OK.
 */
kdump_status kdump_attr_iter_start(kdump_ctx_t *ctx, const char *path,
				   kdump_attr_iter_t *iter);

/**  Get an attribute iterator by reference.
 * @param      ctx   Dump file object.
 * @param[in]  ref   Reference to an attribute directory.
 * @param[out] iter  Attribute iterator.
 * @returns          Error status.
 *
 * This works just like @ref kdump_attr_iter_start, but use an
 * attribute reference rather than its key path.
 */
kdump_status kdump_attr_ref_iter_start(kdump_ctx_t *ctx,
				       const kdump_attr_ref_t *ref,
				       kdump_attr_iter_t *iter);

/**  Advance an attribute iterator.
 * @param ctx   Dump file object.
 * @param iter  Attribute iterator.
 * @returns     Error status.
 *
 * If there are no more items in the iteration, this function sets
 * the @c key field of @p iter to @c NULL and returns @ref KDUMP_OK.
 * If you try to advance past end of iteration, this function returns
 * @ref KDUMP_ERR_INVALID.
 */
kdump_status kdump_attr_iter_next(kdump_ctx_t *ctx, kdump_attr_iter_t *iter);

/**  De-initialize an attribute iterator.
 * @param ctx   Dump file object.
 * @param iter  Attribute iterator.
 * @returns     Error status.
 *
 * This function must be called when an iterator is no longer needed.
 */
void kdump_attr_iter_end(kdump_ctx_t *ctx, kdump_attr_iter_t *iter);

/**********************************************************************
 * WELL-KNOWN ATTRIBUTES
 *
 * Many well-known attribute names can be referenced by a macro.
 * These macros should be used instead of the string to minimize the
 * risk of typos. If you mistype an identifier, the compiler will
 * issue an error. If you mistype a string, it will just not work...
 */

/** File descriptor attribute. */
#define KDUMP_ATTR_FILE_FD	"file.fd"

/** Base directory of a file set.
 * The @ref KDUMP_ATTR_FILE_FD attribute can be used only if the
 * dump is contained in a single file. If the dump is split across
 * multiple files (e.g. SADUMP), use @c file.set:
 *   - Set the @c number sub-attribute first. This creates numbered
 *     sub-attributes 0 to n-1.
 *   - Set 0.fd, 1.fd, ... $n_1.fd to the file descriptors (in any
 *     order).
 *   - Optionally, you may store the file name in 0.name, 1.name,
 *     ... $n_1.fd. It is used in error messages.
 *   - When all file descriptors are set, the dump file gets
 *     initialized automatically.
 */
#define KDUMP_ATTR_FILE_SET	"file.set"

/** File format name attribute.
 * This attribute is intended to be presented to humans rather than
 * machine-parsed. In fact, some format handlers create the string
 * dynamically, e.g. LKCD files will include the version in the string.
 */
#define KDUMP_ATTR_FILE_FORMAT	"file.format"

/** File page map attribute.
 * This attribute contains a bitmap of pages that are contained in
 * the file. If only part of a page is present, the corresponding
 * bit is set to 1.
 */
#define KDUMP_ATTR_FILE_PAGEMAP	"file.pagemap"

/** Memory page map attribute.
 * This attribute contains a bitmap of pages that are RAM. If only
 * part of a page is present, the corresponding bit is set to 1.
 */
#define KDUMP_ATTR_MEMORY_PAGEMAP	"memory.pagemap"

/** Canonical architecture name attribute.
 * Unlike @ref KDUMP_ATTR_MACHINE, which may contain the name of a
 * particular platform (e.g. "i586" v. "i686") or may not even be
 * initialised, this attribute (if set) always equals one of the
 * @c KDUMP_ARCH_xxx strings defined below.
 */
#define KDUMP_ATTR_ARCH_NAME	"arch.name"

/** @name Canonical Architecture Names
 * @{
 * Recognized values of the @c arch.name attribute. These macros should
 * be used instead of the actual string to prevent typos. Note that it
 * is not an error to set the @c arch.name attribute to a value that is
 * not recognized by the library. However, some functionality may be
 * unavailable (e.g. virtual-to-physical address translation).
 */
#define KDUMP_ARCH_AARCH64	"aarch64" /**< AArch64 (ARM64) */
#define KDUMP_ARCH_ALPHA	"alpha"	  /**< DEC Alpha */
#define KDUMP_ARCH_ARM		"arm"	  /**< ARM, 32-bit */
#define KDUMP_ARCH_IA32		"ia32"	  /**< Intel i386, i586, i686 */
#define KDUMP_ARCH_IA64		"ia64"	  /**< Intel Itanium */
#define KDUMP_ARCH_MIPS		"mips"	  /**< MIPS, 32-bit */
#define KDUMP_ARCH_PPC		"ppc"	  /**< Power ISA, 32-bit */
#define KDUMP_ARCH_PPC64	"ppc64"	  /**< Power ISA, 64-bit */
#define KDUMP_ARCH_RISCV32	"riscv32" /**< RISC-V, 32-bit */
#define KDUMP_ARCH_RISCV64	"riscv64" /**< RISC-V, 64-bit */
#define KDUMP_ARCH_S390		"s390"	  /**< IBM z/Architecture, 31-bit */
#define KDUMP_ARCH_S390X	"s390x"	  /**< IBM z/Architecture, 64-bit */
#define KDUMP_ARCH_X86_64	"x86_64"  /**< AMD64, Intel 64 */
/* @} */

/** Byte order attribute.
 * @sa kdump_byte_order_t
 */
#define KDUMP_ATTR_BYTE_ORDER	"arch.byte_order"

/** Pointer size attribute. */
#define KDUMP_ATTR_PTR_SIZE	"arch.ptr_size"

/** Page size attribute. */
#define KDUMP_ATTR_PAGE_SIZE	"arch.page_size"

/** Page shift attribute. */
#define KDUMP_ATTR_PAGE_SHIFT	"arch.page_shift"

/** Number of CPUs attribute.
 * The number is not the number of CPUs in the system, but rather the
 * number of CPUs with known register values.
 */
#define KDUMP_ATTR_NUM_CPUS	"cpu.number"

/** OS type attribute.
 */
#define KDUMP_ATTR_OSTYPE	"addrxlat.ostype"

/** Default libaddrxlat options.
 * Atributes under this directory will be used if no better value
 * can be inferred from the dump file.
 */
#define KDUMP_ATTR_XLAT_DEFAULT		"addrxlat.default"

/** Forced libaddrxlat options.
 * Atributes under this directory override whatever is auto-detected.
 */
#define KDUMP_ATTR_XLAT_FORCE		"addrxlat.force"

/** Xen dump type file attribute.
 * @sa kdump_xen_type_t
 */
#define KDUMP_ATTR_XEN_TYPE	"xen.type"

/** Xen translation type attribute.
 * @sa kdump_xen_xlat_t
 */
#define KDUMP_ATTR_XEN_XLAT	"xen.xlat"

/** Linux version code attribute.
 * A Linux kernel version code is a 32-bit integer that combines the
 * first three digits of the kernel version.
 * See @c KERNEL_VERSION in <linux/version.h>.
 */
#define KDUMP_ATTR_LINUX_VERSION_CODE	"linux.version_code"

/** Xen version code attribute.
 * A Xen version code is a 32-bit integer that combines the major and
 * minor version.
 * See @c XENVER_version in <xen/version.h>.
 */
#define KDUMP_ATTR_XEN_VERSION_CODE	"xen.version_code"

/** Xen physical start address attribute.
 */
#define KDUMP_ATTR_XEN_PHYS_START	"xen.phys_start"

/** Fill excluded pages with zeroes? */
#define KDUMP_ATTR_ZERO_EXCLUDED "file.zero_excluded"

/** Policy for using mmap vs. read.
 * Default is @c KDUMP_MMAP_TRY.
 * @sa kdump_mmap_policy_t
 */
#define KDUMP_ATTR_FILE_MMAP_POLICY	"file.mmap_policy"

/** Raw content of makedumpfile ERASEINFO
 */
#define KDUMP_ATTR_ERASEINFO		"file.eraseinfo.raw"

/**  Get VMCOREINFO raw data.
 * @param ctx  Dump file object.
 * @param raw  Filled with a copy of the raw VMCOREINFO string on success.
 * @returns    Error status.
 *
 * The output string is always NUL-terminated, but if there was a NUL
 * byte inside VMCOREINFO, there is no way to know the full length.
 *
 * The output string is dynamically allocated and must be eventually
 * deallocated by the caller using @c free(3).
 */
kdump_status kdump_vmcoreinfo_raw(kdump_ctx_t *ctx, char **raw);

/**  Get a VMCOREINFO line.
 * @param ctx       Dump file object.
 * @param[in] key   Name of the VMCOREINFO variable (part before '=').
 * @param[out] val  Filled with the part after (first) '='.
 * @returns         Error status.
 *
 * The output string is dynamically allocated and must be eventually
 * deallocated by the caller using @c free(3).
 */
kdump_status kdump_vmcoreinfo_line(kdump_ctx_t *ctx, const char *key,
				   char **val);

/**  Get VMCOREINFO symbol value.
 * @param ctx            Dump file object.
 * @param[in] symname    Kernel symbol name.
 * @param[out] symvalue  Value of the symbol.
 * @returns              Error status.
 *
 * Get the content of SYMBOL(@c symname) row and parse it as a hexadecimal
 * value.
 */
kdump_status kdump_vmcoreinfo_symbol(kdump_ctx_t *ctx, const char *symname,
				     kdump_addr_t *symvalue);

/**  Return the string describing a given error status.
 * @param status  Error status
 * @returns       Description of the error.
 */
const char *kdump_strerror(kdump_status status);

#ifdef  __cplusplus
}
#endif

#endif	/* kdumpfile.h */
