X-Git-Url: https://git.saurik.com/apple/dyld.git/blobdiff_plain/bac542e65c0030c0d819c7ff1dcfc25892a61844..d113e8b5ffc80ec29316b2eb968dfaa7502c1da8:/src/dyld_gdb.cpp diff --git a/src/dyld_gdb.cpp b/src/dyld_gdb.cpp index 456f048..f13064d 100644 --- a/src/dyld_gdb.cpp +++ b/src/dyld_gdb.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,163 +32,111 @@ #include "mach-o/dyld_gdb.h" #include "mach-o/dyld_images.h" +#include "mach-o/dyld_process_info.h" +#include "ImageLoader.h" +#include "dyld.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + #define INITIAL_UUID_IMAGE_COUNT 4 +#else + #define INITIAL_UUID_IMAGE_COUNT 32 +#endif -#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__ - -// old gdb interface to dyld only supported on 32-bit ppc and i386 -#if OLD_GDB_DYLD_INTERFACE - -unsigned int gdb_dyld_version = 2; +VECTOR_NEVER_DESTRUCTED(dyld_image_info); +VECTOR_NEVER_DESTRUCTED(dyld_uuid_info); +static std::vector sImageInfos; +static std::vector sImageUUIDs; -/* - * gdb_dyld_state_changed() is a dummy routine called by dyld after images get - * added or removed/ Gdb is expected to set a break point at - * gdb_dyld_state_changed() then re-read dyld internal data as specified in - * the header file dyld_gdb.h - */ -void gdb_dyld_state_changed() +size_t allImagesCount() { - // do nothing + return sImageInfos.size(); } -#define NLIBRARY_IMAGES 200 -#define NOBJECT_IMAGES 1 - - -struct image { - const char* physical_name; // physical image name (file name) - uint32_t vmaddr_slide; // the slide from the staticly linked address - const mach_header* mh; // address of the mach header of the image - uint32_t valid; // TRUE if this is struct is valid - const char* name; // image name for reporting errors -}; - - -struct library_images { - struct image images[NLIBRARY_IMAGES]; - uint32_t nimages; - struct library_images* next_images; -}; -struct object_images { - struct image images[NOBJECT_IMAGES]; - uint32_t nimages; - struct library_images* next_images; -}; - -unsigned int gdb_nobject_images = NOBJECT_IMAGES; -unsigned int gdb_object_image_size = sizeof(image); -unsigned int gdb_nlibrary_images = NLIBRARY_IMAGES; -unsigned int gdb_library_image_size = sizeof(image); - -extern "C" { -object_images object_images;// = { {}, 0 , NULL }; -library_images library_images;// = { {}, 0 , NULL }; -void send_event(const struct dyld_event* event); +const mach_header* allImagesIndexedMachHeader(uint32_t index) +{ + if ( index < sImageInfos.size() ) + return sImageInfos[index].imageLoadAddress; + else + return NULL; } +const char* allImagesIndexedPath(uint32_t index) +{ + if ( index < sImageInfos.size() ) + return sImageInfos[index].imageFilePath; + else + return NULL; +} -enum dyld_event_type { - DYLD_IMAGE_ADDED = 0, - DYLD_IMAGE_REMOVED = 5 -}; - -struct dyld_event { - enum dyld_event_type type; - const struct mach_header* header; - uintptr_t slide; -}; - - -// gdb only notices changes bundles/dylibs loaded at runtime -// if the "send_event()" function in dyld is called... -void send_event(const struct dyld_event* event); -void (*send_event_ptr)(const struct dyld_event* event) = &send_event; -void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath) +void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]) { - struct library_images* li = &library_images; - while ( li->nimages >= NLIBRARY_IMAGES ) { - if ( li->next_images == NULL ) { - struct library_images* li2 = new struct library_images(); - li2->nimages = 0; - li2->next_images = NULL; - li->next_images = li2; - li = li2; - } - else { - li = li->next_images; - } - } - image* info = &li->images[li->nimages++]; - info->physical_name = physicalPath; - info->vmaddr_slide = slide; - info->mh = mh; - info->valid = 1; - info->name = logicalPath; - - // ping gdb about change - dyld_event event; - event.type = DYLD_IMAGE_ADDED; - event.header = mh; - event.slide = slide; + // make initial size large enough that we probably won't need to re-alloc it + if ( sImageInfos.size() == 0 ) + sImageInfos.reserve(INITIAL_IMAGE_COUNT); + if ( sImageUUIDs.capacity() == 0 ) + sImageUUIDs.reserve(4); + // set infoArray to NULL to denote it is in-use + dyld::gProcessInfo->infoArray = NULL; - // we have to indirect through a function pointer to keep gcc-3.5 from inlining away the function call - // rdar://problem/3830560 - (*send_event_ptr)(&event); -} + // append all new images + for (uint32_t i=0; i < infoCount; ++i) + sImageInfos.push_back(info[i]); + dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); + dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); -// move this to after use, otherwise gcc will see it has an empty implementation and -// optimize away the call site -void send_event(const struct dyld_event* event) -{ - // This function exists to let gdb set a break point - // and catch libraries being added... + // set infoArray back to base address of vector (other process can now read) + dyld::gProcessInfo->infoArray = &sImageInfos[0]; } - -void removeImageForgdb(const mach_header* mh) +#if TARGET_IPHONE_SIMULATOR +// called once in dyld_sim start up to copy image list from host dyld to sImageInfos +void syncProcessInfo() { - for (struct library_images* li = &library_images; li != NULL; li = li->next_images) { - for( uint32_t n=0; n < li->nimages; ++n) { - struct image* image = &li->images[n]; - if ( image->mh == mh ) { - image->physical_name = NULL; - image->vmaddr_slide = 0; - image->mh = 0; - image->valid = 0; - image->name = NULL; - return; + // may want to set version field of gProcessInfo if it might be different than host + if ( sImageInfos.size() == 0 ) { + sImageInfos.reserve(INITIAL_IMAGE_COUNT); + if ( dyld::gProcessInfo->infoArray != NULL ) { + for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i) { + sImageInfos.push_back(dyld::gProcessInfo->infoArray[i]); } + dyld::gProcessInfo->infoArray = &sImageInfos[0]; + dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); } } + dyld::gProcessInfo->notification(dyld_image_info_change, 0, NULL); } - #endif -static std::vector sImageInfos; +const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]) +{ + // tell gdb that about the new images + uint64_t t0 = mach_absolute_time(); + dyld::gProcessInfo->notification(dyld_image_adding, infoCount, info); + uint64_t t1 = mach_absolute_time(); + ImageLoader::fgTotalDebuggerPausedTime += (t1-t0); + + // record initial count of images + // so CrashReporter can note which images were dynamically loaded + if ( dyld::gProcessInfo->initialImageCount == 0 ) + dyld::gProcessInfo->initialImageCount = dyld::gProcessInfo->infoArrayCount; + return NULL; +} -void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]) +void addNonSharedCacheImageUUID(const dyld_uuid_info& info) { - // make initial size large enought that we probably won't need to re-alloc it - if ( sImageInfos.size() == 0 ) - sImageInfos.reserve(200); - - // set infoArray to NULL to denote it is in-use - dyld_all_image_infos.infoArray = NULL; + // set uuidArray to NULL to denote it is in-use + dyld::gProcessInfo->uuidArray = NULL; // append all new images - for (uint32_t i=0; i < infoCount; ++i) - sImageInfos.push_back(info[i]); - dyld_all_image_infos.infoArrayCount = sImageInfos.size(); + sImageUUIDs.push_back(info); + dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); - // set infoArray back to base address of vector - dyld_all_image_infos.infoArray = &sImageInfos[0]; - - // tell gdb that about the new images - dyld_all_image_infos.notification(dyld_image_adding, infoCount, info); + // set uuidArray back to base address of vector (other process can now read) + dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; } void removeImageFromAllImages(const struct mach_header* loadAddress) @@ -196,7 +144,7 @@ void removeImageFromAllImages(const struct mach_header* loadAddress) dyld_image_info goingAway; // set infoArray to NULL to denote it is in-use - dyld_all_image_infos.infoArray = NULL; + dyld::gProcessInfo->infoArray = NULL; // remove image from infoArray for (std::vector::iterator it=sImageInfos.begin(); it != sImageInfos.end(); it++) { @@ -206,31 +154,88 @@ void removeImageFromAllImages(const struct mach_header* loadAddress) break; } } - dyld_all_image_infos.infoArrayCount = sImageInfos.size(); + dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); // set infoArray back to base address of vector - dyld_all_image_infos.infoArray = &sImageInfos[0]; + dyld::gProcessInfo->infoArray = &sImageInfos[0]; + + + // set uuidArrayCount to NULL to denote it is in-use + dyld::gProcessInfo->uuidArray = NULL; + + // remove image from infoArray + for (std::vector::iterator it=sImageUUIDs.begin(); it != sImageUUIDs.end(); it++) { + if ( it->imageLoadAddress == loadAddress ) { + sImageUUIDs.erase(it); + break; + } + } + dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); + dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); + + // set infoArray back to base address of vector + dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; // tell gdb that about the new images - dyld_all_image_infos.notification(dyld_image_removing, 1, &goingAway); + dyld::gProcessInfo->notification(dyld_image_removing, 1, &goingAway); } -static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]) -{ - // do nothing - // gdb sets a break point here to catch notifications - //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount); - //for (uint32_t i=0; i < infoCount; ++i) - // dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath); - //for (uint32_t i=0; i < dyld_all_image_infos.infoArrayCount; ++i) - // dyld::log("dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath); -} +#if TARGET_IPHONE_SIMULATOR + namespace dyld { + struct dyld_all_image_infos* gProcessInfo = NULL; + } +#else + static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]) + { + uint64_t machHeaders[infoCount]; + for (uint32_t i=0; i < infoCount; ++i) { + machHeaders[i] = (uintptr_t)(info[i].imageLoadAddress); + } + switch ( mode ) { + case dyld_image_adding: + _dyld_debugger_notification(dyld_notify_adding, infoCount, machHeaders); + break; + case dyld_image_removing: + _dyld_debugger_notification(dyld_notify_removing, infoCount, machHeaders); + break; + default: + break; + } + // do nothing + // gdb sets a break point here to catch notifications + //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount); + //for (uint32_t i=0; i < infoCount; ++i) + // dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath); + //for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i) + // dyld::log("dyld: %d loading at %p %s\n", i, dyld::gProcessInfo->infoArray[i].imageLoadAddress, dyld::gProcessInfo->infoArray[i].imageFilePath); + } + // only used with accelerator tables and ASan which images need to be re-loaded + void resetAllImages() + { + sImageInfos.clear(); + sImageUUIDs.clear(); + _dyld_debugger_notification(dyld_notify_remove_all, 0, NULL); + } -struct dyld_all_image_infos dyld_all_image_infos = { 1, 0, NULL, &gdb_image_notifier, false }; + extern void* __dso_handle; + #define STR(s) # s + #define XSTR(s) STR(s) -struct dyld_shared_cache_ranges dyld_shared_cache_ranges; + struct dyld_all_image_infos dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info"))) + = { + 15, 0, NULL, &gdb_image_notifier, false, false, (const mach_header*)&__dso_handle, NULL, + XSTR(DYLD_VERSION), NULL, 0, NULL, 0, 0, NULL, &dyld_all_image_infos, + 0, 0, NULL, NULL, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, + 0, 0, "/usr/lib/dyld", {0}, {0} + }; + struct dyld_shared_cache_ranges dyld_shared_cache_ranges; + + namespace dyld { + struct dyld_all_image_infos* gProcessInfo = &dyld_all_image_infos; + } +#endif