nextstep-nat-cfm.c [plain text]
#include "defs.h"
#include "breakpoint.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "nextstep-nat-inferior.h"
#include "nextstep-nat-inferior-util.h"
#include "nextstep-nat-mutils.h"
#include "nextstep-nat-cfm.h"
#include "nextstep-nat-cfm-io.h"
#include "nextstep-nat-cfm-process.h"
#define CFM_MAX_UNIVERSE_LENGTH 1024
#define CFM_MAX_CONNECTION_LENGTH 1024
#define CFM_MAX_CONTAINER_LENGTH 1024
#define CFM_MAX_SECTION_LENGTH 1024
#define CFM_MAX_INSTANCE_LENGTH 1024
enum cfm_errtype {
noErr = 0,
paramErr = -1,
cfragCFMInternalErr = -2,
cfragConnectionIDErr = -3,
cfragContainerIDErr = -4,
cfragFragmentCorruptErr = -5,
cfragNoSectionErr = -6
};
#define CFContHashedStringLength(hash) ((hash) >> 16)
extern next_inferior_status *next_status;
long
cfm_update (task_t task, struct dyld_objfile_info *info)
{
long ret;
unsigned long n_connection_ids;
unsigned long nread_connection_ids;
unsigned long *connection_ids;
unsigned long connection_index;
CORE_ADDR cfm_cookie;
CORE_ADDR cfm_context;
struct cfm_parser *cfm_parser;
cfm_cookie = next_status->cfm_status.info_api_cookie;
cfm_parser = &next_status->cfm_status.parser;
if (cfm_cookie == NULL)
return -1;
cfm_context = read_memory_unsigned_integer (cfm_cookie, 4);
ret = cfm_fetch_context_connections (cfm_parser, cfm_context, 0, 0, &n_connection_ids, NULL);
if (ret != noErr)
return ret;
connection_ids = (unsigned long *) xmalloc (n_connection_ids * sizeof (unsigned long));
ret = cfm_fetch_context_connections (cfm_parser, cfm_context, n_connection_ids, 0, &nread_connection_ids, connection_ids);
if (ret != noErr)
return ret;
CHECK (n_connection_ids == nread_connection_ids);
for (connection_index = 0; connection_index < n_connection_ids; connection_index++)
{
NCFragConnectionInfo connection_info;
NCFragContainerInfo container_info;
NCFragSectionInfo section_info;
NCFragInstanceInfo instance_info;
ret = cfm_fetch_connection_info (cfm_parser, connection_ids[connection_index], &connection_info);
if (ret != noErr)
continue;
ret = cfm_fetch_container_info (cfm_parser, connection_info.container, &container_info);
if (ret != noErr)
continue;
if (container_info.sectionCount > 0) {
ret = cfm_fetch_connection_section_info (cfm_parser, connection_ids[connection_index], 0, §ion_info, &instance_info);
if (ret != noErr)
continue;
}
{
struct dyld_objfile_entry *entry;
entry = dyld_objfile_entry_alloc (info);
entry->dyld_name = xstrdup (container_info.name + 1);
entry->dyld_name_valid = 1;
entry->dyld_addr = container_info.address;
entry->dyld_slide = container_info.address;
entry->dyld_length = container_info.length;
entry->dyld_index = 0;
entry->dyld_valid = 1;
entry->cfm_connection = connection_ids[connection_index];
entry->reason = dyld_reason_cfm;
}
}
return noErr;
}
long
cfm_fetch_context_connections
(struct cfm_parser *parser,
CORE_ADDR contextAddr,
unsigned long requestedCount, unsigned long skipCount,
unsigned long *totalCount_o, unsigned long* connectionIDs_o)
{
int ret;
unsigned long localTotal = 0;
unsigned long currIDSlot;
NCFragUniverseInfo universe;
NCFragConnectionInfo connection;
CORE_ADDR curConnection = 0;
*totalCount_o = 0;
ret = cfm_fetch_universe_info (parser, contextAddr, &universe);
localTotal = universe.connections.length;
if (skipCount >= localTotal)
{
*totalCount_o = localTotal;
return noErr;
}
if (requestedCount > (localTotal - skipCount))
requestedCount = localTotal - skipCount;
curConnection = universe.connections.head;
while (skipCount > 0)
{
if (curConnection == 0)
return cfragCFMInternalErr;
ret = cfm_fetch_connection_info (parser, curConnection, &connection);
curConnection = connection.next;
skipCount -= 1;
}
for (currIDSlot = 0; currIDSlot < requestedCount; currIDSlot += 1)
{
if (curConnection == 0)
return cfragCFMInternalErr;
ret = cfm_fetch_connection_info (parser, curConnection, &connection);
connectionIDs_o[currIDSlot] = curConnection;
curConnection = connection.next;
}
*totalCount_o = localTotal;
return noErr;
}
long
cfm_parse_universe_info
(struct cfm_parser *parser, unsigned char *buf, size_t len, NCFragUniverseInfo *info)
{
if (parser->universe_container_offset + 12 > len) { return -1; }
if (parser->universe_connection_offset + 12 > len) { return -1; }
if (parser->universe_closure_offset + 12 > len) { return -1; }
info->containers.head = bfd_getb32 (buf + parser->universe_container_offset);
info->containers.tail = bfd_getb32 (buf + parser->universe_container_offset + 4);
info->containers.length = bfd_getb32 (buf + parser->universe_container_offset + 8);
info->connections.head = bfd_getb32 (buf + parser->universe_connection_offset);
info->connections.tail = bfd_getb32 (buf + parser->universe_connection_offset + 4);
info->connections.length = bfd_getb32 (buf + parser->universe_connection_offset + 8);
info->closures.head = bfd_getb32 (buf + parser->universe_closure_offset);
info->closures.tail = bfd_getb32 (buf + parser->universe_closure_offset + 4);
info->closures.length = bfd_getb32 (buf + parser->universe_closure_offset + 8);
return 0;
}
long
cfm_fetch_universe_info
(struct cfm_parser *parser, CORE_ADDR addr, NCFragUniverseInfo *info)
{
int ret, err;
unsigned char buf[CFM_MAX_UNIVERSE_LENGTH];
if (parser->universe_length > CFM_MAX_UNIVERSE_LENGTH) { return -1; }
ret = target_read_memory_partial (addr, buf, parser->universe_length, &err);
if (ret < 0) { return -1; }
return cfm_parse_universe_info (parser, buf, parser->universe_length, info);
}
long
cfm_parse_container_info
(struct cfm_parser *parser, unsigned char *buf, size_t len, NCFragContainerInfo *info)
{
info->address = bfd_getb32 (buf + parser->container_address_offset);
info->length = bfd_getb32 (buf + parser->container_length_offset);
info->sectionCount = bfd_getb32 (buf + parser->container_section_count_offset);
return 0;
}
long
cfm_fetch_container_info
(struct cfm_parser *parser, CORE_ADDR addr, NCFragContainerInfo *info)
{
int ret, err;
unsigned long name_length, name_addr;
unsigned char buf[CFM_MAX_CONTAINER_LENGTH];
if (parser->container_length > CFM_MAX_CONTAINER_LENGTH) { return -1; }
ret = target_read_memory_partial (addr, buf, parser->container_length, &err);
if (ret < 0) { return -1; }
ret = cfm_parse_container_info (parser, buf, parser->container_length, info);
if (ret < 0) { return -1; }
name_length = CFContHashedStringLength (bfd_getb32 (buf + parser->container_fragment_name_offset));
if (name_length > 63)
return cfragFragmentCorruptErr;
name_addr = bfd_getb32 (buf + parser->container_fragment_name_offset + 4);
info->name[0] = name_length;
ret = target_read_memory_partial (name_addr, &info->name[1], name_length, &err);
if (ret < 0)
return cfragFragmentCorruptErr;
info->name[name_length + 1] = '\0';
return 0;
}
long
cfm_parse_connection_info
(struct cfm_parser *parser, unsigned char *buf, size_t len, NCFragConnectionInfo *info)
{
if (parser->connection_next_offset + 4 > len) { return -1; }
if (parser->connection_container_offset + 4 > len) { return -1; }
info->next = bfd_getb32 (buf + parser->connection_next_offset);
info->container = bfd_getb32 (buf + parser->connection_container_offset);
return 0;
}
long
cfm_fetch_connection_info
(struct cfm_parser *parser, CORE_ADDR addr, NCFragConnectionInfo *info)
{
int ret, err;
unsigned char buf[CFM_MAX_CONNECTION_LENGTH];
if (parser->connection_length > CFM_MAX_CONNECTION_LENGTH) { return -1; }
ret = target_read_memory_partial (addr, buf, parser->connection_length, &err);
if (ret < 0) { return -1; }
return cfm_parse_connection_info (parser, buf, parser->connection_length, info);
}
long
cfm_parse_section_info
(struct cfm_parser *parser, unsigned char *buf, size_t len, NCFragSectionInfo *info)
{
if (parser->section_total_length_offset + 4 > len) { return -1; }
info->length = bfd_getb32 (buf + parser->section_total_length_offset);
return 0;
}
long
cfm_parse_instance_info
(struct cfm_parser *parser, unsigned char *buf, size_t len, NCFragInstanceInfo *info)
{
if (parser->instance_address_offset + 4 > len) { return -1; }
info->address = bfd_getb32 (buf + parser->instance_address_offset);
return 0;
}
long
cfm_fetch_connection_section_info
(struct cfm_parser *parser, CORE_ADDR addr, unsigned long sectionIndex, NCFragSectionInfo *section, NCFragInstanceInfo *instance)
{
int ret, err;
unsigned long offset;
NCFragConnectionInfo connection;
NCFragContainerInfo container;
unsigned char section_buf[CFM_MAX_SECTION_LENGTH];
unsigned char instance_buf[CFM_MAX_INSTANCE_LENGTH];
unsigned long instance_ptr;
ret = cfm_fetch_connection_info (parser, addr, &connection);
if (ret < 0)
return cfragCFMInternalErr;
ret = cfm_fetch_container_info (parser, connection.container, &container);
if (ret < 0)
return cfragCFMInternalErr;
if (sectionIndex >= container.sectionCount)
return cfragNoSectionErr;
offset = (connection.container + parser->container_length - (2 * parser->section_length) + (sectionIndex * parser->section_length));
ret = target_read_memory_partial (offset, section_buf, parser->section_length, &err);
if (ret < 0)
return cfragCFMInternalErr;
offset = (addr + parser->connection_length - (2 * sizeof (unsigned long)) + (sectionIndex * sizeof (unsigned long)));
ret = target_read_memory_partial (offset, (unsigned char *) &instance_ptr, sizeof (unsigned long), &err);
if (ret < 0)
return cfragCFMInternalErr;
if (instance_ptr == 0)
return cfragNoSectionErr;
ret = target_read_memory_partial (instance_ptr, instance_buf, parser->instance_length, &err);
if (ret < 0)
return cfragCFMInternalErr;
ret = cfm_parse_section_info (parser, section_buf, parser->section_length, section);
if (ret < 0)
return ret;
ret = cfm_parse_instance_info (parser, instance_buf, parser->instance_length, instance);
if (ret < 0)
return ret;
return noErr;
}