-
David Johnson authored
This commit contains the conversion of the target_xen_vm_process target into the target_os_process target. What this basically means is that most of the linux-specific and Xen-specific code that was in the previous driver is now moved into the os_linux_generic personality; and the logic in the target_xen_vm_process driver is now part of the target_os_process driver. That driver is completely generic; it can sit atop any other driver that is paired with an OS personality. The os_process driver gets all its information from loading target_process objects from the underlying driver, and using that information to build its own model of the world. Its active probing support is implemented by enabling OS_PROCESS active probing in the underlying target, and listening for the target-object-events that are generated -- and handling them. There is better generic support for both the OS and process level. One core piece of this refactor is the use of the full weak reference support. This basically means that many target objects assure the validity of backref pointers better -- and that deallocation can happen to refcnt'd objects when weak refs are dropped -- not just regular refs. I use weak refs as a cyclic dependency breaker, which is all I need. Kind of weird, but I don't need a completely generic weak refcnt system! Anyway, what this means is that we are now ready for the case where a language binding can hold onto C-level objects in crazy ways (i.e., given the standard target object hierarchy of target->space->region->range, a Python binding could be able to hold onto range, drop the target object, and the whole backref chain will be intact, and get dropped when range is dropped). (One thing the weak ref stuff does mean is that the <type>_free deallocators must be more careful! Even if their refcnt has gone to nil, they must hold a temp ref if they might free things that hold a weak ref to them -- because if both the refcnt and refcntw counts go to 0, the deallocator will be called again on an RPUTW. Hence the use of RWGUARD/RWUNGUARD.) Drivers can now generate target events to broadcast new, changed, or deleted target objects. This replaces the state change stuff. Events are now broadcast to relevant parties -- namely underlying and overlaying targets. For instance, active probing support in the os_process target is built atop the assumption that the underlying target supports active OS_PROCESS probing, and generates OS_PROCESS events when things change. I also needed to make active probing mechanism a bit more useful. So rather than just the the thread_entry, thread_exit, and memory flags for each target, I split them into personality-level-specific flags: os_thread_entry, process_memory, etc. This allowed to add a set of os_process_* active probing flags, which the os_linux_generic personality understands, and uses to dynamically track processes and their address spaces. This is the bit that was critical enable part of the conversion from target_xen_process to target_os_process, because it allowed me to have the linux personality track processes and their addrspaces actively, and to have the generic os_process driver toggle that via active probing. I'm not sure how active probing will change in the future; hopefully this is enough for now... Also, refactor the memory code (addrspaces, memregions, memranges) to use GLists instead of the Linux linked lists. We don't need the advantages of the Linux linked lists. Also, employ weak refs and object liveness data and macros throughout, instead of the old custom "new" and "updated" (et al) members. Much improved. Technically, a user could now hold onto a memrange, and the object chain all the way up to the containing target or target_process should be intact until they drop the memrange; perfect. This means they're easier to expose to users via a language binding, and more amenable to reuse throughout the target library (i.e., the target_process object owns a (disconnected -- meaning, not bound to a target) addrspace object, which is populated with regions and ranges like a normal addrspace describing a valid target. Thus, we avoid duplicating a lot of code and/or logic, by having silly duplicates like target_process and target_os_process, or having multiple kinds of memregions. There is some waste; memregions and spaces that are not bound to targets will never be fully utilized; but lots of code reuse. A few more notes: This commit introduces target_finalize as the replacement for target_free. Basically, the target library never RHOLDs target objects on behalf of users; it only caches them in its global hashtable (iff the user has called target_init()), and holds them there. target_free thus becomes the refcnt-callable deallocator for target objects, and thus cannot be exposed to users. It's a better pairing for target_instantiate() anyway. target_notify_overlay() now passes target_exception_flags_t to better encapsulate the nature of the underlying exception. We'll see if this is a good compromise between abstraction and exception handling, or not. Get rid of all the personality wrapper functions and replace them with SAFE_* macros. These are better! Make debugfile caching explicit, and expose functions to evict unnecessary debugfiles. This also handles the cached debugfile RHOLDs appropriately in dwdebug_fini(). Much better.
39819b65