Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

704 lines
16 KiB
C

static char sccsid[] = "@(#)33 1.5.1.15 src/bos/usr/ccs/lib/libdbx/dpi_memory.c, libdbx, bos411, 9428A410j 3/28/94 10:11:57";
/*
* COMPONENT_NAME: (LIBDBX) - dbx symbolic debugger library
*
* FUNCTIONS: dpi_calc_effective_addr
* dpi_check_heap_and_stacks
* dpi_get_address_of_line
* dpi_get_file_length
* dpi_get_func_size
* dpi_get_mapinfo
* dpi_get_memory
* dpi_get_registers
* dpi_invalid_regs
*
* ORIGINS: 27, 83
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1990,1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
#ifdef KDBXRT
#include "rtnls.h" /* MUST BE FIRST */
#endif
#include <setjmp.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/reg.h>
#include <stdarg.h>
/*#include <string.h>*/
#ifdef KDBX
#include <stdlib.h>
#endif /* KDBX */
#include "defs.h"
#include "process.h"
#include "decode.h"
#include "source.h"
#include "mappings.h"
#include "envdefs.h"
#include "ops.h"
#include <sys/proc.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <stddef.h>
#include <errno.h>
#include <procinfo.h>
#ifdef K_THREADS
#include "k_thread.h"
#endif
#define U_OFF(x) ((int)&(((struct user *)NULL)->x))
typedef struct dpi_ldinfo {
char filename[255];
uint textorg;
uint dataorg;
uint textsize;
uint datasize;
} MAP;
extern int loadcnt;
extern Process process;
extern Boolean notstdout;
public int *envptr;
/*
* NAME: dpi_get_registers
*
* FUNCTION:
* Reads the general purpose registers, and floating point registers.
* The values of all the registers are returned through two input
* parameters "gpr" and "fpr". Space is allocated for both the
* parameters that must be freed by the caller.
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES:
* There is no need for the standard longjmp setup since setreg(), reg(),
* and fpregval() simply make calls to ptrace and do not have any error
* conditions.
* If -1 is returned then the output variables are not filled in.
*
* PARAMETERS:
* gpr - output parameter which will contain a vector of values of
* the general purpose (NGREG) and system control registers (NSYS).
* Currently this is 41 registers.
* fpr - output parameter which will contain a vector of values of
* the floating point registers (fpregs in number).
* Currently this is 32 registers.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* fpregs - number of floating point registers.
* process must be set
*
* RETURNS:
* Success: 0
* Failure: -1
*/
int dpi_get_registers(gpr, fpr)
uint **gpr;
double **fpr;
{
int i;
/*
* If there's no process then there are no registers to get.
*/
if ( ! process )
return -1;
/*
* Allocate space for the registers.
*/
*gpr = (uint *) malloc( (NGREG+NSYS) * sizeof(uint) );
*fpr = (double *) malloc ( fpregs * sizeof (double ) );
/*
* force the registers in the ptrace process area
* to be up to date
*/
setregs(process);
/*
* copy in the gprs and system control regs.
*/
for (i=0; i < NGREG+NSYS; i++) {
(*gpr)[i] = reg(i);
}
/*
* copy in the fprs
*/
for (i=0; i < fpregs; i++) {
(*fpr)[i] = fpregval(i);
}
return 0;
}
/*
* NAME: dpi_invalid_regs
*
* FUNCTION:
* Returns a count and an array of invalid registers based
* on the current operating hardware.
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES: This function would need to be modified in the
* future if there is a new hardware for which certain registers
* are invalid.
* It also assumed by its caller that only special purpose
* registers are invalid on some architectures. That is,
* all floating point registers are valid on all hardware
* architectures.
*
*
* PARAMETERS:
* invalid_count - output integer parameter indicating the number
* of invalid registers in the array invalid_regs
* invalid_regs - output parameter to be used to return
* an array containing the numbers of the invalid
* registers for the current operating hardware.
* Space is allocated which must be freed by the caller.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* current_hardware must be set
*
* RETURNS: NONE
*/
void dpi_invalid_regs(invalid_count,invalid_regs)
int *invalid_count;
int **invalid_regs;
{
#define MAX_INVALID_REGS 2
/* Allocate space for the invalid register array */
*invalid_regs = (int *) malloc(MAX_INVALID_REGS * sizeof(int) );
/* initialize count of number of invalid registers */
*invalid_count = 0;
/*
if current hardware is POWERPC (and not 601 POWERPC),
then set mq register to be invalid.
*/
if (current_hardware == PPC)
{
(*invalid_regs)[*invalid_count] = SYSREGNO(MQ);
(*invalid_count)++;
}
/*
if current hardware is POWERPC or 601 POWERPC,
then set tid register to be invalid.
*/
if ((current_hardware == PPC) || (current_hardware == SET_601))
{
(*invalid_regs)[*invalid_count] = SYSREGNO(TID);
(*invalid_count)++;
}
return;
}
/*
* NAME: dpi_get_memory
*
* FUNCTION:
* Reads the memory from the current process's address space and
* upon successful completion returns the memory's value in "memory"
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES:
* Space is allocated to hold the memory which must be freed by
* the calling function on successful completion.
* If an error occurs then -1 is returned and the memory allocated
* is freed.
*
* PARAMETERS:
* address base address from which to retrieve memory
* num_items number of bytes to read
* memory output, pointer to buffer holding read memory
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* process must be set
*
* RETURNS:
* Success: 0
* Failure: -1
*/
int dpi_get_memory(address, num_items, memory)
unsigned int address; /* Address to read from */
int num_items; /* Number of bytes to read */
char **memory; /* A pointer to the read memory */
{
int i;
jmp_buf env;
int *svenv;
/*
* standard longjmp error recovery setup
*/
if (! process )
return -1;
svenv = envptr;
envptr = env;
switch ( setjmp(env) ) {
/* longjmp error cases */
case ENVCONT:
case ENVEXIT:
case ENVQUIT:
case ENVFATAL:
envptr = svenv;
dispose( *memory );
return -1;
/* no error occurred */
default:
break;
}
/*
* Allocate space for the memory.
*/
*memory = malloc ( (uint) num_items );
/*
* get the memory and check for normal errors
*/
if ( dread(*memory, address, num_items) ) {
dispose( *memory );
envptr = svenv;
return -1;
}
else {
envptr = svenv;
return 0;
}
}
/*
* NAME: dpi_get_address_of_line
*
* FUNCTION:
* Fill in "address" with the machine address of the given file
* line number. If there was an error or if the address couldn't
* be found then "address" is set to nil.
*
* EXECUTION ENVIRONMENT: normal user process
*
* PARAMETERS:
* line source line number
* filename name of file containing the line
* address output - the address of the specified source line
*
* RECOVERY OPERATION: NONE NEEDED
*
* RETURNS:
* Success: 0
* Failure: -1
*/
int dpi_get_address_of_line(line, filename, address)
int line;
char *filename;
uint *address;
{
jmp_buf env;
int *svenv;
/*
* standard longjmp error recovery setup
*/
svenv = envptr;
envptr = env;
switch ( setjmp(env) ) {
case ENVCONT:
case ENVEXIT:
case ENVQUIT:
case ENVFATAL:
envptr = svenv;
*address = nil;
return -1;
default:
break;
}
*address = objaddr (line, filename);
if ( *address == NOADDR ) {
*address = nil;
envptr = svenv;
return -1;
}
else {
envptr = svenv;
return 0;
}
}
/*
* NAME: dpi_calc_effective_addr
*
* FUNCTION:
* Calculate the effective address from the expression of the
* form:
*
* offset(register_number)
*
* where offset could be any valid expression, and register_number
* must be one of the register numbers as defined in the sys/reg.h.
*
* Result of the expression = offset + contents of register_number.
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES:
* If the input expression is not correctly formed then -1 will
* be returned.
*
* PARAMETERS:
* expression input expression to be evaluated.
* address output - effective address of the input expression.
*
* RECOVERY OPERATION: NONE NEEDED
*
* RETURNS:
* The value of the expression is returned through the pointer
* variable result if successful.
*
* Success: 0
* Failure: -1
*/
int dpi_calc_effective_addr(expression, result)
char *expression;
uint *result;
{
char *p;
char *q;
char *r;
char *res;
char cmd[80];
/*
* In order to calculate the effective address, we add a '+'
* character before the '(', and a '$' before the register
* number, then build the dbx command
* "print offset+($register_number)\n"
* and then use the dpi function get_dbx_result to evaluate the
* command.
*/
q = expression;
p = strchr( expression, '(' ); /* Look for the '(' */
if ( p == NULL ) /* if no '(' then input was bad */
return ( -1 );
strcpy( cmd, "print " );
r = cmd + 6; /* this is the length of "print " */
/* Copy the offset expression */
while ( q < p )
*r++ = *q++;
*r++ = '+'; /* Add '+' after the offset */
*r++ = '(';
*r++ = '$'; /* Add $ to the register name , there should
not be a single blank between $ and regno.*/
q = p+1;
while ( *q == ' ' ) /* skip the blanks */
q++;
p = strchr( q, ')' );
if ( p == NULL ) /* if no ')' then input was bad */
return ( -1 );
while ( q <= p )
*r++ = *q++;
*r++ = '\n';
*r = '\0';
if ( get_dbx_result(cmd, NOFORMAT, &res) == -1 )
return -1;
/*
* convert the ascii result to int
*/
*result = strtoul(res, NULL, 0);
free( res );
return 0;
}
/*
* NAME : dpi_get_mapinfo
*
* FUNCTION: This function is used to get the information about the loaded
* objects, i.e address of beginning of text section, size of
* text section etc.
*
* It basically reorganizes the information present in the
* dbx data structure loader_info, for xde/adc.
* loader_info is defined in process.h.
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES:
* Storage is allocated for mapinfo that must be freed by the caller
* on successful invocations.
*
* PARAMETERS:
* mapinfo : output - is used to return the array containing the map info.
* count : output - tells xde/adc, about the number of loaded objects.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* process must be set
*
* RETURNS:
* SUCCESS : returns 0;
* FAILURE : returns -1;
*/
int dpi_get_mapinfo(mapinfo, count)
MAP **mapinfo;
int *count;
{
MAP *loadmap;
int i;
*count = loadcnt;
/* If there is no process, then the loadcnt == 0 */
if (! process )
return -1;
/*
* Allocate space for the mapinfo and fill it in for all
* the loaded segments.
*/
*mapinfo = (MAP *)malloc(loadcnt * sizeof(MAP));
loadmap = *mapinfo;
for(i=0; i< loadcnt; i++) {
loadmap[i].textorg = loader_info[i].textorg;
loadmap[i].textsize = loader_info[i].textsize;
loadmap[i].dataorg = loader_info[i].dataorg;
loadmap[i].datasize = loader_info[i].datasize;
strcpy(loadmap[i].filename, fd_info[i].pathname);
}
return 0;
}
/*
* NAME : dpi_get_file_length
*
* FUNCTION: This function returns the number of lines in the current file.
*
* EXECUTION ENVIRONMENT: normal user process
*
* PARAMETERS: NONE
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* process must be set
*
* RETURNS:
* SUCCESS : linecount;
* FAILURE : -1;
*/
int dpi_get_file_length()
{
extern Lineno lastlinenum;
if (!process)
return -1;
if( canReadSource() == false ) {
return -1;
}
return(lastlinenum);
}
/*
* NAME: dpi_get_func_size
*
* FUNCTION: returns the start and end addresses of the function that the
* input address is in. If those addresses cannot be determined,
* then the start and end addresses of the load segment that the
* input address is in is returned.
*
* EXECUTION ENVIRONMENT: normal user process
*
* PARAMETERS:
* address : address for which to find the function information
* start : output - starting address of the function containing
* the input address.
* end : output - ending address of the function containing
* the input address.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES:
* process must be set
*
* RETURNS:
* SUCCESS : 0;
* FAILURE : -1;
*/
int dpi_get_func_size(address, start, end)
unsigned address;
unsigned *start;
unsigned *end;
{
if (!process || !getfuncinfo(address, start, end))
return -1;
return(0);
}
/*
* NAME: dpi_qtoa
*
* FUNCTION:
* Convert the input quad precision floating point number to
* ascii.
*
* EXECUTION ENVIRONMENT: normal user process
*
* NOTES: space is allocated to hold the returned ascii representation
* of the quad float number. This space must be freed by the
* calling routine.
*
* PARAMETERS:
* q - input quad number.
* result - output ascii representation of q.
*
* RECOVERY OPERATION: NONE NEEDED
*
* RETURNS:
* The ascii representation of q is returned via result.
*
* Success: 0
* Failure: -1
*/
int dpi_qtoa(q, result)
quadf q;
char **result;
{
msgbegin;
printquad (rpt_output, stdout, q);
msgend( *result );
return 0;
}
/*
* NAME: dpi_check_heap_and_stacks
*
* FUNCTION: Determines whether a passed address is in the heap or stacks.
* If it is, then returns the start and end of the heap or stack.
*
* RECOVERY OPERATION: none
*
* PARAMETERS:
* address - address to be checked (input)
* maxdval - end of last data segment (input)
* stacktop - top of stack (input)
* start - if the passed address is in the heap or a stack, then the
* start of the heap or stack is returned in this
* parameter.
* Otherwise, 0 is returned in this parameter.
* (output)
* end - if the passed address is in the heap or a stack, then the
* end of the heap or stack is returned in this
* parameter.
* Otherwise, 0 is returned in this parameter.
* (output)
*
* DATA STRUCTURES: none
*
* RETURNS: void
* start and end parameters are returned as defined above.
*
*/
void dpi_check_heap_and_stacks(uint address,
uint maxdvalue,
uint stacktop,
uint *start,
uint *end)
{
int i;
uint stackend;
uint heap_end;
uint dvalue;
pid_t pid;
*start = *end = 0;
/*
* force the registers in the ptrace process area
* to be up to date
*/
setregs(process);
/* get the value of the stack pointer register */
stackend = reg(GPR1);
/* See if it is on the stack */
if (address <= stacktop && address >= stackend)
{
*start = stackend;
*end = stacktop;
}
else
{
/*
Determine if address is in the heap
*/
/* find size of heap */
pid = dpi_report_newProcessId();
if (pid != -1)
{
#ifdef PT_READ_U
heap_end = ptrace(PT_READ_U, pid,
(int *)U_OFF(u_dsize), NULL, NULL);
if (heap_end == -1) heap_end = 0;
#else
heap_end = getheapsize(pid);
#endif
if (heap_end != 0)
{
heap_end += BASE(DATASEG) - 1;
if (address >= maxdvalue && address <= heap_end)
{
*start = maxdvalue;
*end = heap_end;
}
#ifdef K_THREADS
else
{
if (lib_type == KERNEL_THREAD)
{
check_thread_stacks(address,start,end);
}
}
#endif
}
}
}
}