Programmers build large-scale systems with multiple languages to leverage legacy code and languages best suited to their problems. For instance, the same program may use Java for ease of programming and C to interface with the operating system. These programs pose significant debugging challenges, because programmers need to understand and control code across languages, which often execute in different environments. Unfortunately, traditional multilingual debuggers require a single execution environment. This paper presents a novel composition approach to building portable mixed-environment debuggers, in which an intermediate agent interposes on language transitions, controlling and reusing single-environment debuggers. We implement debugger composition in Blink, a debugger for Java, C, and the Jeannie programming language. We show that Blink is (i) simple: it requires modest amounts of new code; (ii) portable: it supports multiple Java virtual machines, C compilers, operating systems, and component debuggers; and (iii) powerful: composition eases debugging, while supporting new mixed-language expression evaluation and Java native interface bug diagnostics. To demonstrate the generality of interposition, we build prototypes and demonstrate debugger language transitions with C for five of six other languages (Caml, Common Lisp, C#, Perl 5, Python, and Ruby) without modifications to their debuggers. Using real-world case studies, we show that diagnosing language interface errors require prior single-environment debuggers to restart execution multiple times, whereas Blink directly diagnoses them with one execution.Traditional debuggers are not much help with mixed-language programs because they are limited to a single execution environment. For example, native programs and their debuggers (e.g., the gdb debugger for C, C++, and Fortran) require language implementations to use the same application binary interface (ABI). The ABI is machine dependent and thus precludes portable execution environments for managed languages, such as Java, C#, JavaScript, and Python. For portability, managed languages rely on virtual machine (VM) execution, using interpretation, just-in-time compilation, and garbage collection. They abstract over internal code, the stack, and data representations. Debuggers for managed languages, such as the standard Java debugger jdb, operate on VM abstractions, for example, through the Java Debug Wire Protocol (JDWP), but do not understand native code. Current mixed-language debuggers are limited to XDI and dbx, which support Java and C within a single JVM [6,7], and the Visual Studio debugger, which supports managed and native code in the Common Language Runtime (CLR) [8]. While these debuggers understand all environments, they are behemoths that are generally not portable. The challenge when building a mixed-environment debugger is that each environment has different representations; managed debuggers operate at the level of bytecodes and objects, whereas native debuggers deal with machine instructio...