/* **********************************************************
 * Copyright (c) 2012-2022 Google, Inc.  All rights reserved.
 * Copyright (c) 2003-2009 VMware, Inc.  All rights reserved.
 * **********************************************************/

/*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of VMware, Inc. nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

/* Copyright (c) 2003-2007 Determina Corp. */

/*
 * options.h
 *
 * options struct and prototypes from options.c
 * for use with core and gui/nm
 */

#ifndef _OPTIONS_H_
#define _OPTIONS_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "options_struct.h"

/* For default integer values we use an enum, while for default string values we
 * use the default_options struct instance that is already being used
 * for option parsing, and a second one for internal options when !INTERNAL
 */
extern const options_t default_options;

#ifndef EXPOSE_INTERNAL_OPTIONS
/* only needs to contain string options, but no compile-time way to
 * do that without having OPTION_COMMAND_INTERNAL_STRING()!
 */
extern const internal_options_t default_internal_options;
#endif

#define IS_OPTION_INTERNAL(name) (OPTION_IS_INTERNAL_##name)
#define IS_OPTION_STRING(name) (OPTION_IS_STRING_##name)
/* FIXME : figure out a way to handle types here so that we don't have to cast
 * strings to ints to avoid compiler warnings */
#define DEFAULT_OPTION_VALUE(name) \
    (IS_OPTION_STRING(name) ? (int)default_options.name : OPTION_DEFAULT_VALUE_##name)
#ifdef EXPOSE_INTERNAL_OPTIONS
#    define DEFAULT_INTERNAL_OPTION_VALUE DEFAULT_OPTION_VALUE
#else
#    define DEFAULT_INTERNAL_OPTION_VALUE(name)                 \
        (IS_OPTION_STRING(name) ? default_internal_options.name \
                                : OPTION_DEFAULT_VALUE_##name)
#endif
/* for non-internal builds we don't support setting the default value
 * since they are all constants
 */
#define SET_DEFAULT_VALUE(name) (dynamo_options.name = DEFAULT_OPTION_VALUE(name))

/* checks for incompatible option values */
/* max==0 means no max and 0 is an ok value */
/* if option is incompatible, will try to touch up the option
 * by assigning min to make it valid returns true if changed the
 * option value
 */
bool
check_param_bounds(ptr_uint_t *val, ptr_uint_t min, ptr_uint_t max, const char *name);

int
options_init(void);

/* Only frees a lock: does not destroy any options info other exit routines
 * might need (due to orderings during exit). See options_detach for resetting
 * options back to defaults for static re-attach.
 */
void
options_exit(void);

/* Resets options to default values for the purpose of a full cleanup
 * during static detach. It is called after nearly all other cleanup has
 * occurred.
 */
void
options_detach(void);

int
synchronize_dynamic_options(void);

#ifdef WINDOWS
const options_t *
get_process_options(HANDLE process_handle);
#endif

/*
 * if minimal then the options string only contains values different than
 *  the defaults, otherwise it explicitly lists all options being used
 */
void
get_dynamo_options_string(options_t *options, char *opstr, int len, bool minimal);

/* Fills opstr with a minimal string of only
 * persistent-cache-affecting options whose effect is >= pcache_effect
 * and that are different from the defaults.
 */
void
get_pcache_dynamo_options_string(options_t *options, char *opstr, int len,
                                 op_pcache_t pcache_effect);

bool
has_pcache_dynamo_options(options_t *options, op_pcache_t pcache_effect);

char *
d_r_parse_word(const char *str, const char **strpos, char *wordbuf, uint wordbuflen);

void
options_enable_code_api_dependences(options_t *options);

/****************************************************************************/
#ifdef NOT_DYNAMORIO_CORE
void
set_dynamo_options_defaults(options_t *options);
int
set_dynamo_options(options_t *options, const char *optstr);
#else /* !NOT_DYNAMORIO_CORE */

#    include "utils.h"

/* are any fragments (potentially) shared? */
#    define SHARED_FRAGMENTS_ENABLED() \
        (DYNAMO_OPTION(shared_bbs) || DYNAMO_OPTION(shared_traces))

/* PR 244737: for x64 we use a "unified" scheme were thread-shared and
 * thread-private code always uses TLS for scratch space, eliminating
 * reachability issues.  We require -private_ib_in_tls for x64 as well
 * as for SHARED_FRAGMENTS_ENABLED and use that option to also
 * cover non-ib scratch space.
 */
#    define SCRATCH_ALWAYS_TLS() (DYNAMO_OPTION(private_ib_in_tls))

/* are any traces (potentially) private? */
/* FIXME Fix this if we permit private & shared traces to co-exist */
#    define PRIVATE_TRACES_ENABLED() \
        (!DYNAMO_OPTION(disable_traces) && !DYNAMO_OPTION(shared_traces))

/* are shared BBs ibl targets? */
#    define SHARED_BB_IB_TARGETS() \
        (DYNAMO_OPTION(shared_bbs) && DYNAMO_OPTION(bb_ibl_targets))

/* What this answers is
 * "Are only shared BBs being created and are they valid IB targets?"
 * It's used when a client wants to know if shared BBs are the only
 * possible IB targets. So, for example, this is false whenever trace
 * building is active, even if traces are not being added to the
 * lookup tables.
 */
#    define SHARED_BB_ONLY_IB_TARGETS() \
        (SHARED_BB_IB_TARGETS() && DYNAMO_OPTION(disable_traces))

/* are any shared fragments ibl targets? */
#    define SHARED_IB_TARGETS() (DYNAMO_OPTION(shared_traces) || SHARED_BB_IB_TARGETS())

/* are any IBT tables (potentially) shared? */
#    define SHARED_IBT_TABLES_ENABLED() \
        (DYNAMO_OPTION(shared_bb_ibt_tables) || DYNAMO_OPTION(shared_trace_ibt_tables))

#    define TRACEDUMP_ENABLED()                                                   \
        (!DYNAMO_OPTION(disable_traces) &&                                        \
         (INTERNAL_OPTION(tracedump_text) || INTERNAL_OPTION(tracedump_binary) || \
          INTERNAL_OPTION(tracedump_origins)))

#    define RUNNING_WITHOUT_CODE_CACHE() \
        (IF_HOTP(DYNAMO_OPTION(hotp_only) ||) DYNAMO_OPTION(thin_client))

#    ifndef NOT_DYNAMORIO_CORE_PROPER
#        define CLIENT_OR_STANDALONE() (standalone_library || CLIENTS_EXIST())
#    else
#        define CLIENT_OR_STANDALONE() false
#    endif

extern char d_r_option_string[];
extern read_write_lock_t options_lock;

/* check for empty is considered safe w/o the read lock
 * this takes the field name only, and not {DYNAMO,INTERNAL}_OPTION macro,
 * since those macros will ASSERT_OWN_READWRITE_LOCK(<is_stringtype>, &options_lock)
 */
#    define IS_STRING_OPTION_EMPTY(op) ((dynamo_options.op)[0] == '\0')

/* single character check for ALL is considered safe w/o the read lock
 * similarly to IS_STRING_OPTION_EMPTY see above
 */
#    define IS_LISTSTRING_OPTION_FORALL(op) ((dynamo_options.op)[0] == '*')

#    ifdef EXPOSE_INTERNAL_OPTIONS
#        define IS_INTERNAL_STRING_OPTION_EMPTY(op) IS_STRING_OPTION_EMPTY(op)
#    else
#        define IS_INTERNAL_STRING_OPTION_EMPTY(op) \
            ((default_internal_options.op)[0] == '\0')
#    endif

#    ifdef STATIC_LIBRARY
/* For our static model, we enable -code_api and assume that client code could
 * be run at any time, even if there's no dr_init.
 */
#        define CLIENTS_EXIST() true
#    else
#        define CLIENTS_EXIST() (!IS_INTERNAL_STRING_OPTION_EMPTY(client_lib))
#    endif

/* 0=ret => 1, 1=call* => 2, 2=jmp* => 4 */
#    define COARSE_FILL_IBL_MASK(branch_type) (1 << (branch_type))

/* full access to string requires read lock */
static inline void
string_option_read_lock()
{
    d_r_read_lock(&options_lock);
}
static inline void
string_option_read_unlock()
{
    d_r_read_unlock(&options_lock);
}

typedef enum {
    LIST_NO_MATCH = 0, /* ensure can use as bool */
    LIST_ON_DEFAULT = 1,
    LIST_ON_APPEND = 2,
} list_default_or_append_t;

/* compare short_name, usually module name, against a list option of the combined
 * default option (that could be overridden) and append list that is usually used
 */
list_default_or_append_t
check_list_default_and_append(liststring_t default_list, liststring_t append_list,
                              const char *short_name);

void
options_make_writable(void);

void
options_restore_readonly(void);

#endif /* !NOT_DYNAMORIO_CORE */

#ifdef __cplusplus
}
#endif

#endif /* _OPTIONS_H_ */