/* Copyright (C) 2007-2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program 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.
*/

/*
 * Contains declaration of types, strctures, routines, etc. that encapsulte
 * an API for parsing an ELF file containing debugging information in DWARF
 * format.
 */

#ifndef ELFF_API_H_
#define ELFF_API_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

/* Defines type for a handle used in ELFF API. */
typedef void* ELFF_HANDLE;

/* Defines an entry for 'inline_stack' array in Elf_AddressInfo structure.
 * Each entry in the array represents a routine, where routine represented
 * with the previous array entry has been inlined. First element in the array
 * (at index 0) represents information for the inlined routine, referenced by
 * Elf_AddressInfo structure itself. If name for a routine was not available
 * (DW_AT_name attribute was missing), routine name is set to "<unknown>".
 * Last entry in the array has all its fields set to zero. It's sufficient
 * just to check for routine_name field of this structure to be NULL to detect
 * last entry in the array.
 */
typedef struct Elf_InlineInfo {
  /* Name of the routine where previous routine is inlined.
   * This field can never be NULL, except for the last array entry.
   */
  const char*     routine_name;

  /* Source file name where routine is inlined.
   * This field can be NULL, if it was not possible to obtain information
   * about source file location for the routine. If this field is NULL, content
   * of inlined_in_file_dir and inlined_at_line fields is undefined and should
   * be ignored. */
  const char*     inlined_in_file;

  /* Source file directory where routine is inlined.
   * If inlined_in_file field contains NULL, content of this field is undefined
   * and should be ignored. */
  const char*     inlined_in_file_dir;

  /* Source file line number where routine is inlined.
   * If inlined_in_file field contains NULL, content of this field is undefined
   * and should be ignored. */
  uint32_t        inlined_at_line;
} Elf_InlineInfo;

/* Checks if an entry is the last entry in the array.
 * Return:
 *  Boolean: 1 if this is last entry, or zero otherwise.
 */
static inline int
elfinlineinfo_is_last_entry(const Elf_InlineInfo* info) {
    return info->routine_name == 0;
}

/* PC address information descriptor.
 * This descriptor contains as much information about a PC address as it was
 * possible to collect from an ELF file. */
typedef struct Elf_AddressInfo {
  /* Name of the routine containing the address. If name of the routine
   * was not available (DW_AT_name attribute was missing) this field
   * is set to "<unknown>". */
  const char*       routine_name;

  /* Name of the source file containing the routine. If source location for the
   * routine was not available, this field is set to NULL, and content of
   * dir_name, and line_number fields of this structure is not defined. */
  const char*       file_name;

  /* Path to the source file directory. If file_name field of this structure is
   * NULL, content of this field is not defined. */
  const char*       dir_name;

  /* Line number in the source file for the address. If file_name field of this
   * structure is NULL, content of this field is not defined. */
  uint32_t          line_number;

  /* If routine that contains the given address has been inlined (or it is part
   * of even deeper inline branch) this array lists information about that
   * inline branch rooting to the first routine that has not been inlined. The
   * first element in the array references a routine, where routine containing
   * the given address has been inlined. The second entry contains information
   * about a routine referenced by the first entry (and so on). If routine,
   * containing the given address has not been inlined, this field is set to
   * NULL. The array ends with an entry containing all zeroes. */
  Elf_InlineInfo*   inline_stack;
} Elf_AddressInfo;

//=============================================================================
// API routines
//=============================================================================

/* Initializes ELFF API for the given ELF file.
 * Param:
 *  elf_file_path - Path to the ELF file to initialize API for.
 * Return:
 *  On success, this routine returns a handle that can be used in subsequent
 *  calls to this API dealing with the given ELF file. On failure this routine
 *  returns NULL, with errno providing extended error information.
 *  NOTE: handle returned from this routine must be closed using elff_close().
 */
ELFF_HANDLE elff_init(const char* elf_file_path);

/* Closes a handle obtained after successful call to elff_init routine.
 * Param:
 *  handle - A handle to close. This handle must be a handle returned from
 *  a successful call to elff_init routine.
 */
void elff_close(ELFF_HANDLE handle);

/* Checks if ELF file represents an executable file, or a shared library.
 *  handle - A handle obtained from successful call to elff_init().
 * Return:
 *  1  if ELF file represents an executable file, or
 *  0  if ELF file represents a shared library, or
 *  -1 if handle is invalid.
 */
int elff_is_exec(ELFF_HANDLE handle);

/* Gets PC address information.
 * Param:
 *  handle - A handle obtained from successful call to elff_init().
 *  address - PC address to get information for. Address must be relative to
 *    the beginning of ELF file represented by the handle parameter.
 *  address_info - Upon success contains information about routine(s) that
 *    contain the given address.
 * Return:
 *  0 if routine(s) containing the given address has been found and information
 *  has been saved into address_info, or -1 if no appropriate routine for that
 *  address has been found, or there was a memory error when collecting
 *  routine(s) information. In case of failure, errno provides extended
 *  error information.
 *  NOTE: Successful call to this routine must be complimented with a call
 *  to free_pc_address_info, so ELFF API can release resources aquired for
 *  address_info.
 */
int elff_get_pc_address_info(ELFF_HANDLE handle,
                             uint64_t address,
                             Elf_AddressInfo* address_info);

/* Frees resources acquired for address information in successful call to
 * get_pc_address_info().
 * Param:
 *  handle - A handle obtained from successful call to elff_init().
 *  address_info - Address information structure, initialized in successful
 *    call to get_pc_address_info() routine.
 */
void elff_free_pc_address_info(ELFF_HANDLE handle,
                               Elf_AddressInfo* address_info);

#ifdef __cplusplus
}   /* end of extern "C" */
#endif

#endif  // ELFF_API_H_
