| /******************************************************************************* |
| * Copyright (c) 2007, 2013 Wind River Systems, Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * and Eclipse Distribution License v1.0 which accompany this distribution. |
| * The Eclipse Public License is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * and the Eclipse Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * You may elect to redistribute this code under either of these licenses. |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| |
| /* |
| * This module handles debug contexts and their state machine. |
| */ |
| |
| #ifndef D_context |
| #define D_context |
| |
| #include <tcf/config.h> |
| #include <tcf/framework/cpudefs.h> |
| #include <tcf/framework/errors.h> |
| #include <tcf/framework/sigsets.h> |
| #include <tcf/framework/link.h> |
| #include <tcf/framework/context-ext.h> |
| |
| extern LINK context_root; |
| |
| #define ctxl2ctxp(A) ((Context *)((char *)(A) - offsetof(Context, ctxl))) |
| #define cldl2ctxp(A) ((Context *)((char *)(A) - offsetof(Context, cldl))) |
| |
| typedef void ContextAttachCallBack(int, Context *, void *); |
| |
| /* |
| * A context corresponds to an execution thread, process, address space, etc. |
| * A context can belong to a parent context. Contexts hierarchy can be simple |
| * plain list or it can form a tree. It is up to target agent developers to choose |
| * layout that is most descriptive for a given target. |
| * |
| * Role of a context is defined by its capabilities. Clients learn the context |
| * capabilities using functions like context_has_state(), context_can_resume(), |
| * context_get_group(), etc. For example, if a context has a name and no other capabilities, |
| * its role is to provide human readable label for a group of contexts - its children. |
| */ |
| struct Context { |
| char id[256]; /* context ID */ |
| char * name; /* human readable context name */ |
| LINK cldl; /* link that used to form a list of context children */ |
| LINK ctxl; /* link that used to form a list of all contexts */ |
| LINK children; /* context children double linked list */ |
| Context * parent; /* context parent */ |
| Context * creator; /* context creator */ |
| Context * mem; /* context memory space */ |
| int big_endian; /* 0 - little endian, 1 - big endian */ |
| unsigned int mem_access; /* bit set of memory access types represented by this context */ |
| unsigned int ref_count; /* reference count, see context_lock() and context_unlock() */ |
| int stopped; /* OS kernel has stopped this context */ |
| int stopped_by_bp; /* stopped by breakpoint instruction */ |
| ContextBreakpoint** stopped_by_cb; /* stopped by ContextBreakpoint - NULL terminated list of triggered ContextBreakpoint's */ |
| int stopped_by_exception;/* stopped by runtime exception (like SIGSEGV, etc.) */ |
| int stopped_by_funccall;/* stopped by return from injected function call */ |
| char * exception_description;/* description of exception if stopped by runtime exception */ |
| int exiting; /* context is about to exit */ |
| int exited; /* context exited */ |
| int event_notification; /* set to 1 when calling one of ContextEventListener call-backs for this context */ |
| int pending_intercept; /* host is waiting for this context to be suspended */ |
| SigSet pending_signals; /* bit set of signals that were received, but not handled yet */ |
| SigSet sig_dont_stop; /* bit set of signals that should not be intercepted by the debugger */ |
| SigSet sig_dont_pass; /* bit set of signals that should not be delivered to the context */ |
| int signal; /* signal that stopped this context */ |
| }; |
| |
| /* |
| * Debug context suspend reason. |
| */ |
| extern const char * REASON_USER_REQUEST; |
| extern const char * REASON_STEP; |
| extern const char * REASON_ACTIVE; |
| extern const char * REASON_BREAKPOINT; |
| extern const char * REASON_EXCEPTION; |
| extern const char * REASON_CONTAINER; |
| extern const char * REASON_WATCHPOINT; |
| extern const char * REASON_SIGNAL; |
| extern const char * REASON_SHAREDLIB; |
| extern const char * REASON_ERROR; |
| |
| /* |
| * Values of "mem_access". |
| * Target system can support multiple different memory access types, like instruction and data access. |
| * Different access types can use different logic for address translation and memory mapping, so they can |
| * end up accessing different data bits, even if address is the same. |
| * Each distinct access type should be represented by separate memory context. |
| * A memory context can represent multiple access types if they are equivalent - all access same memory bits. |
| * Same data bits can be exposed through multiple memory contexts. |
| */ |
| #define MEM_ACCESS_INSTRUCTION 0x0001 /* Context represent instructions fetch access */ |
| #define MEM_ACCESS_DATA 0x0002 /* Context represents data access */ |
| #define MEM_ACCESS_IO 0x0004 /* Context represents IO peripherals */ |
| #define MEM_ACCESS_USER 0x0008 /* Context represents a user (e.g. application running in Linux) view to memory */ |
| #define MEM_ACCESS_SUPERVISOR 0x0010 /* Context represents a supervisor (e.g. Linux kernel) view to memory */ |
| #define MEM_ACCESS_HYPERVISOR 0x0020 /* Context represents a hypervisor view to memory */ |
| #define MEM_ACCESS_VIRTUAL 0x0040 /* Context uses virtual addresses */ |
| #define MEM_ACCESS_PHYSICAL 0x0080 /* Context uses physical addresses */ |
| #define MEM_ACCESS_CACHE 0x0100 /* Context is a cache */ |
| #define MEM_ACCESS_TLB 0x0200 /* Context is a TLB memory */ |
| |
| /* |
| * MemoryErrorInfo is used to retrieve additional information about memory access error. |
| */ |
| typedef struct MemoryErrorInfo { |
| int error; /* The memory access error code */ |
| size_t size_valid; /* The number of bytes transferred successfully */ |
| size_t size_error; /* The number of bytes that caused the error, starting at 'size_valid' offset */ |
| } MemoryErrorInfo; |
| |
| /* Memory map data types */ |
| typedef struct MemoryMap MemoryMap; |
| typedef struct MemoryRegion MemoryRegion; |
| typedef struct MemoryRegionAttribute MemoryRegionAttribute; |
| |
| struct MemoryMap { |
| unsigned region_cnt; |
| unsigned region_max; |
| MemoryRegion * regions; |
| }; |
| |
| struct MemoryRegion { |
| ContextAddress addr; /* Region address in context memory */ |
| ContextAddress size; /* Region size */ |
| uint64_t file_offs; /* File offset of the region */ |
| uint64_t file_size; /* File size of the region */ |
| int bss; /* 1 if the region is BSS segment */ |
| dev_t dev; /* Region file device ID */ |
| ino_t ino; /* Region file inode */ |
| char * file_name; /* Region file name */ |
| char * sect_name; /* Region file section name, can be NULL */ |
| unsigned flags; /* Region flags, see MM_FLAG* */ |
| char * query; /* If not NULL, the region is only part of the memory map for contexts matches the query */ |
| char * id; /* Region ID, not NULL only if the region info is submitted by a client */ |
| MemoryRegionAttribute * attrs; /* Additional memory region attributes */ |
| }; |
| |
| struct MemoryRegionAttribute { |
| MemoryRegionAttribute * next; |
| char * name; |
| char * value; |
| }; |
| |
| #define MM_FLAG_R 1 |
| #define MM_FLAG_W 2 |
| #define MM_FLAG_X 4 |
| |
| /* Context resume modes */ |
| #define RM_RESUME 0 /* Resume normal execution of the context */ |
| #define RM_STEP_OVER 1 /* Step over a single instruction */ |
| #define RM_STEP_INTO 2 /* Step a single instruction */ |
| #define RM_STEP_OVER_LINE 3 /* Step over a single source code line */ |
| #define RM_STEP_INTO_LINE 4 /* Step a single source code line */ |
| #define RM_STEP_OUT 5 /* Run until control returns from current function */ |
| #define RM_REVERSE_RESUME 6 /* Start running backwards */ |
| #define RM_REVERSE_STEP_OVER 7 /* Reverse of RM_STEP_OVER - run backwards over a single instruction */ |
| #define RM_REVERSE_STEP_INTO 8 /* Reverse of RM_STEP_INTO: "un-execute" the previous instruction */ |
| #define RM_REVERSE_STEP_OVER_LINE 9 /* Reverse of RM_STEP_OVER_LINE */ |
| #define RM_REVERSE_STEP_INTO_LINE 10 /* Reverse of RM_STEP_INTO_LINE */ |
| #define RM_REVERSE_STEP_OUT 11 /* Reverse of RM_STEP_OUT */ |
| #define RM_STEP_OVER_RANGE 12 /* Step over instructions until PC is outside the specified range */ |
| #define RM_STEP_INTO_RANGE 13 /* Step instruction until PC is outside the specified range for any reason */ |
| #define RM_REVERSE_STEP_OVER_RANGE 14 /* Reverse of RM_STEP_OVER_RANGE */ |
| #define RM_REVERSE_STEP_INTO_RANGE 15 /* Reverse of RM_STEP_INTO_RANGE */ |
| #define RM_UNTIL_ACTIVE 16 /* Run until the context becomes active - scheduled to run on a target CPU */ |
| #define RM_REVERSE_UNTIL_ACTIVE 17 /* Run reverse until the context becomes active */ |
| #define RM_TERMINATE 19 /* Terminate the context */ |
| #define RM_DETACH 18 /* Detach the context */ |
| #define RM_UNDEF 19 |
| |
| /* Mode flags for context_attach() */ |
| #define CONTEXT_ATTACH_SELF 0x01 /* The process is forked child - it will attach itself */ |
| #define CONTEXT_ATTACH_CHILDREN 0x02 /* Enable auto-attaching of children of the process */ |
| #define CONTEXT_ATTACH_NO_STOP 0x04 /* Don't stop after attach */ |
| #define CONTEXT_ATTACH_NO_MAIN 0x08 /* Don't stop at main() */ |
| |
| /* |
| * Convert PID to TCF Context ID. |
| * Note: PID to ID mapping is supported for native debugging only. |
| */ |
| extern char * pid2id(pid_t pid, pid_t parent); |
| |
| /* |
| * Convert TCF Context ID to PID. |
| * Note: PID to ID mapping is supported for native debugging only. |
| */ |
| extern pid_t id2pid(const char * id, pid_t * parent); |
| |
| /* |
| * Search Context record by TCF Context ID. |
| */ |
| extern Context * id2ctx(const char * id); |
| |
| /* |
| * Register an extension of struct Context. |
| * Return offset of extension data area. |
| * Additional memory of given size will be allocated in each context struct. |
| * Client are allowed to call this function only during initialization. |
| */ |
| extern size_t context_extension(size_t size); |
| |
| /* |
| * Create a Context object. |
| * The function is called by context implementation. |
| * It is not supposed to be called by clients. |
| */ |
| extern Context * create_context(const char * id); |
| |
| /* |
| * Clear a memory map - dispose all entries. |
| */ |
| extern void context_clear_memory_map(MemoryMap * map); |
| |
| #if ENABLE_DebugContext |
| |
| /* |
| * Get context full name that includes ancestor names. |
| */ |
| extern const char * context_full_name(Context * ctx); |
| |
| /* |
| * Get human redable name of current state of a context. |
| */ |
| extern const char * context_state_name(Context * ctx); |
| |
| /* |
| * Get state change reason of a context. |
| * Reason can be any text, but if it is one of predefined strings, |
| * a generic client might be able to handle it better. |
| * See REASON_* for predefined reason names. |
| */ |
| extern const char * context_suspend_reason(Context * ctx); |
| |
| /* |
| * Find a context by PID |
| * Both process and main thread can have same PID. |
| * 'thread' = 0: search for process, otherwise search for a thread. |
| * Note: PID to context mapping is supported for native debugging only. |
| */ |
| extern Context * context_find_from_pid(pid_t pid, int thread); |
| |
| /* |
| * Trigger self attachment e.g. of forked child |
| * Only available on Linux/Unix. |
| */ |
| extern int context_attach_self(void); |
| |
| /* |
| * Start tracing of a process. |
| * Client provides a call-back function that will be called when context is attached. |
| * The callback function args are error code, the context and client data. |
| * 'mode' - attach mode flags, see CONTEXT_ATTACH_*. |
| * Note: attaching by PID is supported for native debugging only. |
| */ |
| extern int context_attach(pid_t pid, ContextAttachCallBack * done, void * client_data, int mode); |
| |
| /* |
| * Increment reference counter of Context object. |
| * While ref count > 0 object will not be deleted even when context exits. |
| */ |
| extern void context_lock(Context * ctx); |
| |
| /* |
| * Decrement reference counter. |
| * If ref count == 0, delete Context object. |
| */ |
| extern void context_unlock(Context * ctx); |
| |
| /* |
| * Return 1 if the context has running/stopped state, return 0 othewise |
| */ |
| extern int context_has_state(Context * ctx); |
| |
| /* |
| * Get additional context properties. |
| * 'values' are JSON objects. |
| * Return -1 and set errno if cannot access the properties. |
| * Return 0 on success. |
| */ |
| #if ENABLE_ContextExtraProperties |
| extern int context_get_extra_properties(Context * ctx, const char *** names, const char *** values, int * cnt); |
| #endif |
| |
| /* |
| * Get additional context state properties. |
| * 'values' are JSON objects. |
| * Return -1 and set errno if cannot access the properties. |
| * Return 0 on success. |
| */ |
| #if ENABLE_ContextStateProperties |
| extern int context_get_state_properties(Context * ctx, const char *** names, const char *** values, int * cnt); |
| #endif |
| |
| /* |
| * Stop execution of the context. |
| * Execution can be resumed by calling context_resume() |
| * Return -1 and set errno if the context cannot be stopped. |
| * Return 0 on success. |
| */ |
| extern int context_stop(Context * ctx); |
| |
| /* |
| * Resume execution of the context using give execution mode. |
| * See RM_* for mode definitions. |
| * Return -1 and set errno if the context cannot be resumed. |
| * Return 0 on success. |
| */ |
| extern int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end); |
| |
| /* |
| * Check if given resume mode is supported. |
| * See RM_* for mode definitions. |
| * Return 0 if not supported, 1 if supported. |
| */ |
| extern int context_can_resume(Context * ctx, int mode); |
| |
| /* |
| * Resume normal execution of the context. |
| * Return -1 and set errno if the context cannot be resumed. |
| * Return 0 on success. |
| * Deprecated: use context_resume(ctx, RM_RESUME, 0, 0). |
| */ |
| extern int context_continue(Context * ctx); |
| |
| /* |
| * Perform single instruction step on the context. |
| * Return -1 and set errno if the context cannot be single stepped. |
| * Return 0 on success. |
| * Deprecated: use context_resume(ctx, RM_STEP_INTO, 0, 0). |
| */ |
| extern int context_single_step(Context * ctx); |
| |
| /* |
| * Retrieve context memory map. |
| * Return -1 and set errno if the map cannot be retrieved. |
| * Return 0 on success. |
| * Note: the caller owns MemoryMap object and all its contents, it can call loc_free() on it at any time. |
| * When context_get_memory_map() is called, 'map' is empty: region_cnt == 0, |
| * but 'map->regions' can be pre-allocated: 'map->regions' can be not NULL and 'map->region_max' > 0. |
| * The function adds memory region descriptions into it, doing loc_strdup() for things like file names. |
| * The function implementation should not retain references to 'map' or its contents. |
| */ |
| extern int context_get_memory_map(Context * ctx, MemoryMap * map); |
| |
| /* |
| * Write context memory. |
| * Implementation calls check_breakpoints_on_memory_write() before writing to context memory, |
| * which can change contents of the buffer. |
| * Return -1 and set errno if the context memory cannot be written. |
| * Return 0 on success. |
| */ |
| extern int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size); |
| |
| /* |
| * Read context memory. |
| * Implementation calls check_breakpoints_on_memory_read() after reading context memory. |
| * Return -1 and set errno if the context memory cannot be read. |
| * Return 0 on success. |
| */ |
| extern int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size); |
| |
| /* |
| * Retrieve addition information about error reported by last memory access. |
| * Return -1 and set errno if the info cannot be read. |
| * Return 0 on success. |
| */ |
| #if ENABLE_ExtendedMemoryErrorReports |
| extern int context_get_mem_error_info(MemoryErrorInfo * info); |
| #endif |
| |
| /* |
| * Write 'size' bytes into context register starting at offset 'offs'. |
| * Return -1 and set errno if the register cannot be written. |
| * Return 0 on success. |
| */ |
| extern int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf); |
| |
| /* |
| * Read 'size' bytes from context register starting at offset 'offs'. |
| * Return -1 and set errno if the register cannot be read. |
| * Return 0 on success. |
| */ |
| extern int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf); |
| |
| /* |
| * Return context word size in bytes. |
| * It is the default value of sizeof(void*) when debug symbols are not available. |
| */ |
| extern unsigned context_word_size(Context * ctx); |
| |
| /* |
| * Map an address in given address space to a unique canonical memory location. |
| * A target system can have same block (page) of memory mapped to different address spaces at different addresses. |
| * This function should return memory space and address that uniquely identify the location. |
| * 'block_addr' and 'block_size' are optional arguments that clients can use to retrieve |
| * the memory block start address and size. Clients can use this information to map a range of addresses |
| * with a single function call. |
| * Return -1 and set errno if canonical address cannot be resolved. |
| * Return 0 on success. |
| */ |
| extern int context_get_canonical_addr(Context * ctx, ContextAddress addr, |
| Context ** canonical_ctx, ContextAddress * canonical_addr, |
| ContextAddress * block_addr, ContextAddress * block_size); |
| |
| /* |
| * Get a context that represents a group of related contexts. |
| * Implementation can choose a member of a group to represent the group, |
| * or it can create a separate context object for that. |
| * Clients can use this function to check if two or more contexts belong to same group, |
| * for example: |
| * if (context_get_group(ctx1, group) == context_get_group(ctx2, group) ... |
| * |
| * See CONTEXT_GROUP_* for possible values of 'group' argument. |
| */ |
| extern Context * context_get_group(Context * ctx, int group); |
| |
| /* |
| * "stop" context group - all contexts that need to be stopped to make sure |
| * that memory contents in a particular address space is stable. |
| * Note: NULL is not allowed as the group handle. |
| * If the grouping is not applicable to a context, |
| * context_get_group() should return the context itself. |
| */ |
| #define CONTEXT_GROUP_STOP 1 |
| |
| /* |
| * "breakpoint" context group - all contexts for which evaluation of breakpoint |
| * location should produce same list of addresses. |
| * context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT) == NULL means |
| * the context does not support breakpoints. |
| */ |
| #define CONTEXT_GROUP_BREAKPOINT 2 |
| |
| /* |
| * "intercept" context group - all contexts which should be intercepted |
| * when any member of the group is intercepted for any reason. |
| * Note: NULL is not allowed as the group handle. |
| * If the grouping is not applicable to a context, |
| * context_get_group() should return the context itself. |
| */ |
| #define CONTEXT_GROUP_INTERCEPT 3 |
| |
| /* |
| * "process" context group - all contexts that share same memory address space, |
| * memory map and executable files. |
| * Note: NULL is not allowed as the group handle. |
| * If the grouping is not applicable to a context, |
| * context_get_group() should return the context itself. |
| */ |
| #define CONTEXT_GROUP_PROCESS 4 |
| |
| /* |
| * "CPU" context group - all contexts that belong to same CPU. |
| * On SMP systems, all CPUs (cores) of same type should be members of same group. |
| * Note: NULL is not allowed as the group handle. |
| * If the grouping is not applicable to a context, |
| * context_get_group() should return the context itself. |
| */ |
| #define CONTEXT_GROUP_CPU 5 |
| |
| /* |
| * "Symbols" context group - all contexts that share same symbol reader data, |
| * including symbol files, source file paths and user defined memory map entries. |
| * Note: NULL is not allowed as the group handle. |
| * If the grouping is not applicable to a context, |
| * context_get_group() should return the context itself. |
| */ |
| #define CONTEXT_GROUP_SYMBOLS 6 |
| |
| /* |
| * Debug context implementation can support low-level breakpoints. |
| * The support is optional, if not implemented, the agent will use generic code |
| * to plant software breakpoints. Hardware breakpoints is an example of breakpoints |
| * that can be implemented by debug context. |
| * |
| * ContextBreakpoint struct is used by the agent to communicate breakpoint properties to |
| * debug context implementation. Generic code in the Breakpoints service handles common |
| * breakpoint properties, like source code position and location expression. Debug context |
| * implementation can support additional breakpoint properties. The implementation can |
| * get values of the properties using Breakpoint service API: iterate_context_breakpoint_links() |
| * and get_breakpoint_attributes(). |
| */ |
| struct ContextBreakpoint { |
| Context * ctx; /* breakpoint context, one of returned by |
| * context_get_group(..., CONTEXT_GROUP_BREAKPOINT) */ |
| ContextAddress address; /* breakpoint address, or 0 if CTX_BP_ACCESS_NO_ADDRESS */ |
| ContextAddress length; /* length of the breakpoint address range */ |
| unsigned access_types; /* memory access type, bit set of CTX_BP_ACCESS_* */ |
| unsigned id; /* to be used by debug context implementation */ |
| void * ext; /* to be used by debug context implementation */ |
| }; |
| |
| #define CTX_BP_ACCESS_DATA_READ 0x01 |
| #define CTX_BP_ACCESS_DATA_WRITE 0x02 |
| #define CTX_BP_ACCESS_INSTRUCTION 0x04 |
| #define CTX_BP_ACCESS_CHANGE 0x08 |
| #define CTX_BP_ACCESS_VIRTUAL 0x10 |
| #define CTX_BP_ACCESS_SOFTWARE 0x20 |
| #define CTX_BP_ACCESS_NO_ADDRESS 0x40 |
| |
| /* |
| * Return bitmask of supported CTX_BP_ACCESS_* values. |
| */ |
| extern int context_get_supported_bp_access_types(Context * ctx); |
| |
| /* |
| * Plant a breakpoint. |
| * Return 0 on success, or return -1 and set errno on error. |
| * If error code is ERR_UNSUPPORTED, Breakpoints service will |
| * try to plant the breakpoint as a generic software breakpoint. |
| */ |
| extern int context_plant_breakpoint(ContextBreakpoint * bp); |
| |
| /* |
| * Un-plant (remove) a breakpoint. |
| * Return 0 on success, or return -1 and set errno on error. |
| * 'bp' must be a breakpoint that was planted by context_plant_breakpoint(). |
| */ |
| extern int context_unplant_breakpoint(ContextBreakpoint * bp); |
| |
| /* |
| * Get context breakpoint capabilities. |
| * 'values' are JSON objects. |
| * 'ctx' can be NULL, it means a client has requested global capabilities. |
| * Return -1 and set errno if cannot access the capabilities. |
| * Return 0 on success. |
| */ |
| #if ENABLE_ContextBreakpointCapabilities |
| extern int context_get_breakpoint_capabilities(Context * ctx, const char *** names, const char *** values, int * cnt); |
| #endif |
| |
| /* |
| * Get extended breakpoint status properties. |
| * 'values' are JSON objects. |
| * Return -1 and set errno if cannot access the status. |
| * Return 0 on success. |
| */ |
| #if ENABLE_ExtendedBreakpointStatus |
| extern int context_get_breakpoint_status(ContextBreakpoint * bp, const char *** names, const char *** values, int * cnt); |
| #endif |
| |
| #if ENABLE_ContextISA |
| typedef struct { |
| ContextAddress addr; |
| ContextAddress size; |
| ContextAddress alignment; |
| ContextAddress max_instruction_size; |
| const char * isa; |
| const char * def; |
| } ContextISA; |
| |
| /* |
| * Get context Instruction Set Architecture information. |
| * Return -1 and set errno if cannot access the status. |
| * Return 0 on success. |
| */ |
| extern int context_get_isa(Context * ctx, ContextAddress addr, ContextISA * isa); |
| #endif |
| |
| /* |
| * Functions that notify listeners of various context event. |
| * These function are called by context implementation. |
| * They are not supposed to be called by clients. |
| */ |
| extern void send_context_created_event(Context * ctx); |
| extern void send_context_changed_event(Context * ctx); |
| extern void send_context_stopped_event(Context * ctx); |
| extern void send_context_started_event(Context * ctx); |
| extern void send_context_exited_event(Context * ctx); |
| |
| extern void ini_contexts(void); |
| extern void init_contexts_sys_dep(void); |
| |
| #endif /* ENABLE_DebugContext */ |
| |
| typedef struct ContextEventListener { |
| void (*context_created)(Context * ctx, void * client_data); |
| void (*context_exited )(Context * ctx, void * client_data); |
| void (*context_stopped)(Context * ctx, void * client_data); |
| void (*context_started)(Context * ctx, void * client_data); |
| void (*context_changed)(Context * ctx, void * client_data); |
| void (*context_disposed)(Context * ctx, void * client_data); |
| } ContextEventListener; |
| |
| extern void add_context_event_listener(ContextEventListener * listener, void * client_data); |
| |
| #endif |