/*	$NetBSD: pthread_dbg.h,v 1.1 2017/02/08 01:02:19 kamil Exp $	*/

/*-
 * Copyright (c) 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Nathan J. Williams for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project by 
 *      Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

#ifndef _LIB_PTHREAD_DBG_H
#define _LIB_PTHREAD_DBG_H

#include <sys/types.h>
#include <signal.h>

__BEGIN_DECLS

struct td_proc_st;
struct td_thread_st;
struct td_sync_st;

typedef struct td_proc_st td_proc_t;
typedef struct td_thread_st td_thread_t;
typedef struct td_sync_st td_sync_t;

struct td_proc_callbacks_t {
	int (*proc_read)(void *arg, caddr_t addr, void *buf, size_t size);
	int (*proc_write)(void *arg, caddr_t addr, void *buf, size_t size);
	int (*proc_lookup)(void *arg, const char *sym, caddr_t *addr);
	int (*proc_regsize)(void *arg, int regset, size_t *size);
	int (*proc_getregs)(void *arg, int regset, int lwp, void *buf);
	int (*proc_setregs)(void *arg, int regset, int lwp, void *buf);
};


typedef struct td_thread_info_st {
	caddr_t	thread_addr;		/* Address of data structure */
	int	thread_state;		/* TD_STATE_*; see below */
	int	thread_type;		/* TD_TYPE_*; see below */
	int	thread_id;
	stack_t	thread_stack;
	int	thread_hasjoiners;	/* 1 if threads are waiting */
	caddr_t	thread_tls;
	int	thread_errno;
	sigset_t thread_sigmask;
	sigset_t thread_sigpending;
	long	pad[32];
} td_thread_info_t;

#define	TD_STATE_UNKNOWN	0
#define TD_STATE_RUNNING	1	/* On a processor */
#define	TD_STATE_UNUSED2	2	/* former TD_STATE_RUNNABLE for SA */
#define	TD_STATE_UNUSED3	3	/* former TD_STATE_BLOCKED for SA */
#define	TD_STATE_UNUSED4	4	/* former TD_STATE_SLEEPING for SA */
#define	TD_STATE_ZOMBIE		5
#define	TD_STATE_UNUSED6	6	/* former TD_STATE_SUSPENDED for SA */
#define	TD_STATE_DEAD		7

#define	TD_TYPE_UNUSED0	0
#define	TD_TYPE_UNUSED1	1
#define	TD_TYPE_UNUSED2	2

typedef struct {
	caddr_t	sync_addr;	/* Address within the process */
	int	sync_type;	/* TD_SYNC_*; see below */
	size_t	sync_size;
	int	sync_haswaiters;  /* 1 if threads are known to be waiting */
	union {
		struct {
			int	locked;
			td_thread_t *owner;
		} mutex;
		struct {
			int	locked;
		} spin;
		struct {
			td_thread_t *thread;
		} join;
		struct {
			int	locked;
			int	readlocks;
			td_thread_t *writeowner;
		} rwlock;
		long pad[8];
	} sync_data;
} td_sync_info_t;

#define	TD_SYNC_UNKNOWN	0
#define	TD_SYNC_MUTEX	1	/* pthread_mutex_t */
#define TD_SYNC_COND	2	/* pthread_cond_t */
#define TD_SYNC_SPIN	3	/* pthread_spinlock_t */
#define TD_SYNC_JOIN	4	/* thread being joined */
#define TD_SYNC_RWLOCK	5	/* pthread_rwlock_t */

/* Error return codes */
#define TD_ERR_OK		0
#define TD_ERR_ERR		1  /* Generic error */
#define TD_ERR_NOSYM		2  /* Symbol not found (proc_lookup) */
#define TD_ERR_NOOBJ		3  /* No object matched the request */
#define TD_ERR_BADTHREAD	4  /* Request is not meaningful for that thread */
#define TD_ERR_INUSE		5  /* The process is already being debugged */
#define TD_ERR_NOLIB		6  /* The process is not using libpthread */
#define TD_ERR_NOMEM		7  /* malloc() failed */
#define TD_ERR_IO		8  /* A callback failed to read or write */
#define TD_ERR_INVAL		9  /* Invalid parameter */

/* Make a connection to a threaded process */
int td_open(struct td_proc_callbacks_t *, void *arg, td_proc_t **);
int td_close(td_proc_t *);

/* Iterate over the threads in the process */
int td_thr_iter(td_proc_t *, int (*)(td_thread_t *, void *), void *);

/* Get information on a thread */
int td_thr_info(td_thread_t *, td_thread_info_t *);

/* Get the user-assigned name of a thread */
int td_thr_getname(td_thread_t *, char *, int);

/* Get register state of a thread */
int td_thr_getregs(td_thread_t *, int, void *);

/* Set register state of a thread */
int td_thr_setregs(td_thread_t *, int, void *);

/* Iterate over the set of threads that are joining with the given thread */
int td_thr_join_iter(td_thread_t *, int (*)(td_thread_t *, void *), void *);

/* Get the synchronization object that the thread is sleeping on */
int td_thr_sleepinfo(td_thread_t *, td_sync_t **);

/* Get information on a synchronization object */
int td_sync_info(td_sync_t *, td_sync_info_t *);

/* Iterate over the set of threads waiting on a synchronization object */
int td_sync_waiters_iter(td_sync_t *, int (*)(td_thread_t *, void *), void *);

/* Convert the process address to a synchronization handle, if possible */
int td_map_addr2sync(td_proc_t *, caddr_t addr, td_sync_t **);

/* Convert the pthread_t to a thread handle, if possible */
int td_map_pth2thr(td_proc_t *, pthread_t, td_thread_t **);

/* Convert the thread ID to a thread handle, if possible */
int td_map_id2thr(td_proc_t *, int, td_thread_t **);

/* Return the thread handle of the thread running on the given LWP */
int td_map_lwp2thr(td_proc_t *, int, td_thread_t **);

/*
 * Establish a mapping between threads and LWPs. Must be called
 * every time a live process runs before calling td_thr_getregs() or
 * td_thr_setregs().
 */
int td_map_lwps(td_proc_t *);

/* Iterate over the set of TSD keys in the process */
int td_tsd_iter(td_proc_t *, int (*)(pthread_key_t, void (*)(void *), void *), 
    void *);

/* Get a TSD value from a thread */
int td_thr_tsd(td_thread_t *, pthread_key_t, void **);

/* Suspend a thread from running */
int td_thr_suspend(td_thread_t *);

/* Restore a suspended thread to its previous state */
int td_thr_resume(td_thread_t *);

__END_DECLS

#endif /* _LIB_PTHREAD_DBG_H */
