Index: include/llvm-c/Core.h
===================================================================
--- include/llvm-c/Core.h
+++ include/llvm-c/Core.h
@@ -1302,11 +1302,16 @@
 void LLVMReplaceAllUsesWith(LLVMValueRef OldVal, LLVMValueRef NewVal);
 
 /**
- * Determine whether the specified constant instance is constant.
+ * Determine whether the specified value instance is constant.
  */
 LLVMBool LLVMIsConstant(LLVMValueRef Val);
 
 /**
+ * Determine whether the specified value instance is a global.
+ */
+LLVMBool LLVMIsGlobalValue(LLVMValueRef Val);
+
+/**
  * Determine whether a value instance is undefined.
  */
 LLVMBool LLVMIsUndef(LLVMValueRef Val);
Index: lib/IR/Core.cpp
===================================================================
--- lib/IR/Core.cpp
+++ lib/IR/Core.cpp
@@ -708,6 +708,10 @@
   return isa<Constant>(unwrap(Ty));
 }
 
+LLVMBool LLVMIsGlobalValue(LLVMValueRef Ty) {
+  return isa<GlobalValue>(unwrap(Ty));
+}
+
 LLVMBool LLVMIsNull(LLVMValueRef Val) {
   if (Constant *C = dyn_cast<Constant>(unwrap(Val)))
     return C->isNullValue();
Index: test/Bindings/llvm-c/echo.ll
===================================================================
--- /dev/null
+++ test/Bindings/llvm-c/echo.ll
@@ -0,0 +1,34 @@
+; RUN: llvm-as < %s | llvm-dis > %t.orig
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
+; RUN: diff %t.orig %t.echo
+
+declare void @decl()
+
+define void @types() {
+  %1 = alloca half
+  %2 = alloca float
+  %3 = alloca double
+  %4 = alloca x86_fp80
+  %5 = alloca fp128
+  %6 = alloca ppc_fp128
+; TODO: label ?
+  %7 = alloca i7
+  %8 = alloca void (i1)*
+; TODO: struct
+  %9 = alloca [3 x i22]
+  %10 = alloca i328 addrspace(5)*
+  %11 = alloca <5 x i23*>
+; TODO: metadata ?
+  %12 = alloca x86_mmx
+  ret void
+}
+
+define i32 @add(i32 %a, i32 %b) {
+  %1 = add i32 %a, %b
+  ret i32 %1
+}
+
+define i32 @call() {
+  %1 = call i32 @add(i32 23, i32 19)
+  ret i32 %1
+}
Index: tools/llvm-c-test/CMakeLists.txt
===================================================================
--- tools/llvm-c-test/CMakeLists.txt
+++ tools/llvm-c-test/CMakeLists.txt
@@ -37,6 +37,7 @@
 add_llvm_tool(llvm-c-test
   calc.c
   disassemble.c
+  echo.cpp
   helpers.c
   include-all.c
   main.c
Index: tools/llvm-c-test/calc.c
===================================================================
--- tools/llvm-c-test/calc.c
+++ tools/llvm-c-test/calc.c
@@ -14,7 +14,6 @@
 \*===----------------------------------------------------------------------===*/
 
 #include "llvm-c-test.h"
-#include "llvm-c/Core.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
Index: tools/llvm-c-test/echo.cpp
===================================================================
--- /dev/null
+++ tools/llvm-c-test/echo.cpp
@@ -0,0 +1,464 @@
+/*===-- echo.c - tool for testing libLLVM and llvm-c API ------------------===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file implements the --echo commands in llvm-c-test.                   *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#include "llvm-c-test.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "llvm/ADT/DenseMap.h"
+
+#define TRUE 1
+#define FALSE 0
+
+using namespace llvm;
+
+typedef DenseMap<LLVMValueRef, LLVMValueRef> ValueMap;
+
+typedef struct {
+  LLVMValueRef Src;
+  LLVMValueRef Dst;
+} ValuePair;
+
+typedef struct {
+  size_t length;
+  ValuePair* ptr;
+} ValuesSlice;
+
+static LLVMTypeRef clone_type(LLVMTypeRef Src, LLVMContextRef Ctx) {
+  LLVMTypeKind Kind = LLVMGetTypeKind(Src);
+  switch (Kind) {
+    case LLVMVoidTypeKind:
+      return LLVMVoidTypeInContext(Ctx);
+    case LLVMHalfTypeKind:
+      return LLVMHalfTypeInContext(Ctx);
+    case LLVMFloatTypeKind:
+      return LLVMFloatTypeInContext(Ctx);
+    case LLVMDoubleTypeKind:
+      return LLVMDoubleTypeInContext(Ctx);
+    case LLVMX86_FP80TypeKind:
+      return LLVMX86FP80TypeInContext(Ctx);
+    case LLVMFP128TypeKind:
+      return LLVMFP128TypeInContext(Ctx);
+    case LLVMPPC_FP128TypeKind:
+      return LLVMPPCFP128TypeInContext(Ctx);
+    case LLVMLabelTypeKind:
+      return LLVMLabelTypeInContext(Ctx);
+    case LLVMIntegerTypeKind:
+      return LLVMIntTypeInContext(Ctx, LLVMGetIntTypeWidth(Src));
+    case LLVMFunctionTypeKind: {
+      unsigned ParamCount = LLVMCountParamTypes(Src);
+      LLVMTypeRef* Params = NULL;
+      if (ParamCount > 0) {
+        Params = (LLVMTypeRef*) malloc(ParamCount * sizeof(LLVMTypeRef));
+        LLVMGetParamTypes(Src, Params);
+        for (unsigned i = 0; i < ParamCount; i++) {
+          Params[i] = clone_type(Params[i], Ctx);
+        }
+      }
+
+      LLVMTypeRef FunTy = LLVMFunctionType(
+        clone_type(LLVMGetReturnType(Src), Ctx),
+        Params, ParamCount,
+        LLVMIsFunctionVarArg(Src)
+      );
+
+      if (ParamCount > 0) {
+        free(Params);
+      }
+
+      return FunTy;
+    }
+    case LLVMStructTypeKind:
+      break;
+    case LLVMArrayTypeKind:
+      return LLVMArrayType(
+        clone_type(LLVMGetElementType(Src), Ctx),
+        LLVMGetArrayLength(Src)
+      );
+    case LLVMPointerTypeKind:
+      return LLVMPointerType(
+        clone_type(LLVMGetElementType(Src), Ctx),
+        LLVMGetPointerAddressSpace(Src)
+      );
+    case LLVMVectorTypeKind:
+      return LLVMVectorType(
+        clone_type(LLVMGetElementType(Src), Ctx),
+        LLVMGetVectorSize(Src)
+      );
+    case LLVMMetadataTypeKind:
+      break;
+    case LLVMX86_MMXTypeKind:
+      return LLVMX86MMXTypeInContext(Ctx);
+    default:
+      break;
+  }
+
+  fprintf(stderr, "%d is not a supported typekind\n", Kind);
+  exit(-1);
+}
+
+static LLVMValueRef clone_literal(LLVMValueRef Src, LLVMContextRef Ctx) {
+  LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
+
+  LLVMTypeKind Kind = LLVMGetTypeKind(Ty);
+  switch (Kind) {
+    case LLVMIntegerTypeKind:
+      return LLVMConstInt(Ty, LLVMConstIntGetZExtValue(Src), FALSE);
+    default:
+      break;
+  }
+
+  fprintf(stderr, "%d is not a supported constant typekind\n", Kind);
+  exit(-1);
+}
+
+static LLVMModuleRef get_module(LLVMBuilderRef Builder) {
+  LLVMBasicBlockRef BB = LLVMGetInsertBlock(Builder);
+  LLVMValueRef Fn = LLVMGetBasicBlockParent(BB);
+  return LLVMGetGlobalParent(Fn);
+}
+
+static LLVMValueRef clone_instruction(LLVMValueRef Src, LLVMBuilderRef Builder, ValueMap &VMap) {
+  const char *Name = LLVMGetValueName(Src);
+
+  // Maybe it is a contant
+  if (LLVMIsConstant(Src)) {
+    LLVMModuleRef M = get_module(Builder);
+
+    // Maybe it is a symbol
+    if (LLVMIsGlobalValue(Src)) {
+      // Try function
+      LLVMValueRef Dst = LLVMGetNamedFunction(M, Name);
+      if (Dst != NULL) {
+        return Dst;
+      }
+
+      Dst = LLVMGetNamedGlobal(M, Name);
+      if (Dst != NULL) {
+        return Dst;
+      }
+
+      fprintf(stderr, "Could not find @%s\n", Name);
+      exit(-1);
+    }
+
+    // It must be a literal
+    LLVMContextRef Ctx = LLVMGetModuleContext(M);
+    return clone_literal(Src, Ctx);
+  }
+
+  // Maybe it is an undef
+  if (LLVMIsUndef(Src)) {
+    LLVMContextRef Ctx = LLVMGetModuleContext(get_module(Builder));
+    LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
+    return LLVMGetUndef(Ty);
+  }
+
+  // Check if this is somethign we already computed.
+  {
+    auto i = VMap.find(Src);
+    if (i != VMap.end()) {
+      return i->second;
+    }
+  }
+
+  // This is not in the map, generate.
+  LLVMValueRef Dst = NULL;
+
+  LLVMOpcode Op = LLVMGetInstructionOpcode(Src);
+  switch(Op) {
+    case LLVMRet: {
+      int OpCount = LLVMGetNumOperands(Src);
+      Dst = (OpCount == 0)
+        ? LLVMBuildRetVoid(Builder)
+        : LLVMBuildRet(
+            Builder,
+            clone_instruction(LLVMGetOperand(Src, 0), Builder, VMap));
+      break;
+    }
+    case LLVMBr:
+    case LLVMSwitch:
+    case LLVMIndirectBr:
+    case LLVMInvoke:
+    case LLVMUnreachable:
+      break;
+    case LLVMAdd: {
+      LLVMValueRef LHS = clone_instruction(LLVMGetOperand(Src, 0), Builder, VMap);
+      LLVMValueRef RHS = clone_instruction(LLVMGetOperand(Src, 1), Builder, VMap);
+      Dst = LLVMBuildAdd(Builder, LHS, RHS, Name);
+      break;
+    }
+    case LLVMAlloca: {
+      // TODO: Add a binding for AllocaInst::getAllocatedType
+      LLVMTypeRef Ty = LLVMGetElementType(LLVMTypeOf(Src));
+      Dst = LLVMBuildAlloca(Builder, Ty, Name);
+      break;
+    }
+    case LLVMCall: {
+      // TODO: Add binding for CallInst API
+      int ArgCount = LLVMGetNumOperands(Src) - 1;
+      LLVMValueRef* Args = (LLVMValueRef*) malloc(ArgCount * sizeof(LLVMValueRef));
+      for (int i = 0; i < ArgCount; i++) {
+        Args[i] = clone_instruction(LLVMGetOperand(Src, i), Builder, VMap);
+      }
+
+      LLVMValueRef Fn = clone_instruction(LLVMGetOperand(Src, ArgCount), Builder, VMap);
+      Dst = LLVMBuildCall(Builder, Fn, Args, ArgCount, Name);
+      free(Args);
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (Dst == NULL) {
+    fprintf(stderr, "%d is not a supported opcode\n", Op);
+    exit(-1);
+  }
+
+  // This is very inneffiscient, but we don't really care.
+  VMap[Src] = Dst;
+
+  return Dst;
+}
+
+static LLVMBasicBlockRef clone_bb(LLVMBasicBlockRef Src, LLVMValueRef Dst, ValueMap &VMap) {
+  // TODO: Extend C API to be able to get that name.
+  LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Dst, "");
+
+  LLVMValueRef First = LLVMGetFirstInstruction(Src);
+  LLVMValueRef Last = LLVMGetLastInstruction(Src);
+
+  if (First == NULL) {
+    if (Last != NULL) {
+      fprintf(stderr, "Has no first instruction, but last one\n");
+      exit(-1);
+    }
+
+    return BB;
+  }
+
+  LLVMContextRef Ctx = LLVMGetModuleContext(LLVMGetGlobalParent(Dst));
+  LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx);
+  LLVMPositionBuilderAtEnd(Builder, BB);
+
+  LLVMValueRef Cur = First;
+  LLVMValueRef Next = NULL;
+  while(TRUE) {
+    clone_instruction(Cur, Builder, VMap);
+    Next = LLVMGetNextInstruction(Cur);
+    if (Next == NULL) {
+      if (Cur != Last) {
+        fprintf(stderr, "Final instruction does not match Last\n");
+        exit(-1);
+      }
+
+      break;
+    }
+
+    LLVMValueRef Prev = LLVMGetPreviousInstruction(Next);
+    if (Prev != Cur) {
+      fprintf(stderr, "Next.Previous instruction is not Current\n");
+      exit(-1);
+    }
+
+    Cur = Next;
+  }
+
+  LLVMDisposeBuilder(Builder);
+  return BB;
+}
+
+static void clone_bbs(LLVMValueRef Src, LLVMValueRef Dst, ValueMap &VMap) {
+  unsigned Count = LLVMCountBasicBlocks(Src);
+  if (Count == 0) {
+    return;
+  }
+
+  LLVMBasicBlockRef First = LLVMGetFirstBasicBlock(Src);
+  LLVMBasicBlockRef Last = LLVMGetLastBasicBlock(Src);
+
+  LLVMBasicBlockRef Cur = First;
+  LLVMBasicBlockRef Next = NULL;
+  while(TRUE) {
+    clone_bb(Cur, Dst, VMap);
+    Count--;
+    Next = LLVMGetNextBasicBlock(Cur);
+    if (Next == NULL) {
+      if (Cur != Last) {
+        fprintf(stderr, "Final basic block does not match Last\n");
+        exit(-1);
+      }
+
+      break;
+    }
+
+    LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Next);
+    if (Prev != Cur) {
+      fprintf(stderr, "Next.Previous basic bloc is not Current\n");
+      exit(-1);
+    }
+
+    Cur = Next;
+  }
+
+  if (Count != 0) {
+    fprintf(stderr, "Basic block count does not match iterration\n");
+    exit(-1);
+  }
+}
+
+static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) {
+  unsigned Count = LLVMCountParams(Src);
+  if (Count != LLVMCountParams(Dst)) {
+    fprintf(stderr, "Parameter count mismatch\n");
+    exit(-1);
+  }
+
+  ValueMap VMap;
+  if (Count == 0) {
+    return VMap;
+  }
+
+  LLVMValueRef SrcFirst = LLVMGetFirstParam(Src);
+  LLVMValueRef DstFirst = LLVMGetFirstParam(Dst);
+  LLVMValueRef SrcLast = LLVMGetLastParam(Src);
+  LLVMValueRef DstLast = LLVMGetLastParam(Dst);
+
+  LLVMValueRef SrcCur = SrcFirst;
+  LLVMValueRef DstCur = DstFirst;
+  LLVMValueRef SrcNext = NULL;
+  LLVMValueRef DstNext = NULL;
+  while (TRUE) {
+    const char *Name = LLVMGetValueName(SrcCur);
+    LLVMSetValueName(DstCur, Name);
+
+    VMap[SrcCur] = DstCur;
+
+    Count--;
+    SrcNext = LLVMGetNextParam(SrcCur);
+    DstNext = LLVMGetNextParam(DstCur);
+    if (SrcNext == NULL && DstNext == NULL) {
+      if (SrcCur != SrcLast) {
+        fprintf(stderr, "SrcLast param does not match End\n");
+        exit(-1);
+      }
+
+      if (DstCur != DstLast) {
+        fprintf(stderr, "DstLast param does not match End\n");
+        exit(-1);
+      }
+
+      break;
+    }
+
+    if (SrcNext == NULL) {
+      fprintf(stderr, "SrcNext was unexpectedly null\n");
+      exit(-1);
+    }
+
+    if (DstNext == NULL) {
+      fprintf(stderr, "DstNext was unexpectedly null\n");
+      exit(-1);
+    }
+
+    LLVMValueRef SrcPrev = LLVMGetPreviousParam(SrcNext);
+    if (SrcPrev != SrcCur) {
+      fprintf(stderr, "SrcNext.Previous param is not Current\n");
+      exit(-1);
+    }
+
+    LLVMValueRef DstPrev = LLVMGetPreviousParam(DstNext);
+    if (DstPrev != DstCur) {
+      fprintf(stderr, "DstNext.Previous param is not Current\n");
+      exit(-1);
+    }
+
+    SrcCur = SrcNext;
+    DstCur = DstNext;
+  }
+
+  if (Count != 0) {
+    fprintf(stderr, "Parameter count does not match iterration\n");
+    exit(-1);
+  }
+
+  return VMap;
+}
+
+static LLVMValueRef clone_function(LLVMValueRef Src, LLVMModuleRef Dst) {
+  const char *Name = LLVMGetValueName(Src);
+  LLVMValueRef Fun = LLVMGetNamedFunction(Dst, Name);
+  if (Fun != NULL) {
+    return Fun;
+  }
+
+  LLVMTypeRef SrcTy = LLVMTypeOf(Src);
+  LLVMTypeRef DstTy = clone_type(SrcTy, LLVMGetModuleContext(Dst));
+  LLVMTypeRef FunTy = LLVMGetElementType(DstTy);
+
+  Fun = LLVMAddFunction(Dst, Name, FunTy);
+
+  ValueMap VMap = clone_params(Src, Fun);
+  clone_bbs(Src, Fun, VMap);
+
+  return Fun;
+}
+
+static void clone_functions(LLVMModuleRef Src, LLVMModuleRef Dst) {
+  LLVMValueRef Begin = LLVMGetFirstFunction(Src);
+  LLVMValueRef End = LLVMGetLastFunction(Src);
+
+  LLVMValueRef Cur = Begin;
+  LLVMValueRef Next = NULL;
+  while (TRUE) {
+    clone_function(Cur, Dst);
+    Next = LLVMGetNextFunction(Cur);
+    if (Next == NULL) {
+      if (Cur != End) {
+        fprintf(stderr, "Last function does not match End\n");
+        exit(-1);
+      }
+
+      break;
+    }
+
+    LLVMValueRef Prev = LLVMGetPreviousFunction(Next);
+    if (Prev != Cur) {
+      fprintf(stderr, "Next.Previous function is not Current\n");
+      exit(-1);
+    }
+
+    Cur = Next;
+  }
+}
+
+int echo(void) {
+  LLVMEnablePrettyStackTrace();
+
+  LLVMModuleRef Src = load_module_from_bitcode();
+
+  LLVMContextRef Ctx = LLVMContextCreate();
+  LLVMModuleRef Dst = LLVMModuleCreateWithNameInContext("<stdin>", Ctx);
+
+  clone_functions(Src, Dst);
+  char *Str = LLVMPrintModuleToString(Dst);
+  fputs(Str, stdout);
+
+  LLVMDisposeMessage(Str);
+  LLVMDisposeModule(Dst);
+  LLVMContextDispose(Ctx);
+
+  return 0;
+}
Index: tools/llvm-c-test/llvm-c-test.h
===================================================================
--- tools/llvm-c-test/llvm-c-test.h
+++ tools/llvm-c-test/llvm-c-test.h
@@ -13,10 +13,17 @@
 #ifndef LLVM_C_TEST_H
 #define LLVM_C_TEST_H
 
+#include "llvm-c/Core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 // helpers.c
 void tokenize_stdin(void (*cb)(char **tokens, int ntokens));
 
 // module.c
+LLVMModuleRef load_module_from_bitcode(void);
 int module_dump(void);
 int module_list_functions(void);
 int module_list_globals(void);
@@ -38,4 +45,11 @@
 // targets.c
 int targets_list(void);
 
+// echo.c
+int echo(void);
+
+#ifdef __cplusplus
+}
+#endif /* !defined(__cplusplus) */
+
 #endif
Index: tools/llvm-c-test/main.c
===================================================================
--- tools/llvm-c-test/main.c
+++ tools/llvm-c-test/main.c
@@ -13,7 +13,6 @@
 
 #include "llvm-c-test.h"
 #include "llvm-c/BitReader.h"
-#include "llvm-c/Core.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,6 +38,9 @@
   fprintf(stderr, "    Read lines of triple, hex ascii machine code from stdin "
                   "- print disassembly\n\n");
   fprintf(stderr, "  * --calc\n");
+  fprintf(stderr, "  * --echo\n");
+  fprintf(stderr,
+          "    Read object file form stdin - and print it back out\n\n");
   fprintf(
       stderr,
       "    Read lines of name, rpn from stdin - print generated module\n\n");
@@ -69,6 +71,8 @@
     return add_named_metadata_operand();
   } else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) {
     return set_metadata();
+  } else if (argc == 2 && !strcmp(argv[1], "--echo")) {
+    return echo();
   } else {
     print_usage();
   }
Index: tools/llvm-c-test/metadata.c
===================================================================
--- tools/llvm-c-test/metadata.c
+++ tools/llvm-c-test/metadata.c
@@ -13,7 +13,6 @@
 \*===----------------------------------------------------------------------===*/
 
 #include "llvm-c-test.h"
-#include "llvm-c/Core.h"
 
 int add_named_metadata_operand(void) {
   LLVMModuleRef m = LLVMModuleCreateWithName("Mod");
Index: tools/llvm-c-test/module.c
===================================================================
--- tools/llvm-c-test/module.c
+++ tools/llvm-c-test/module.c
@@ -14,12 +14,11 @@
 
 #include "llvm-c-test.h"
 #include "llvm-c/BitReader.h"
-#include "llvm-c/Core.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-static LLVMModuleRef load_module(void) {
+LLVMModuleRef load_module_from_bitcode(void) {
   LLVMMemoryBufferRef MB;
   LLVMModuleRef M;
   char *msg = NULL;
@@ -40,7 +39,7 @@
 }
 
 int module_dump(void) {
-  LLVMModuleRef M = load_module();
+  LLVMModuleRef M = load_module_from_bitcode();
 
   char *irstr = LLVMPrintModuleToString(M);
   puts(irstr);
@@ -52,7 +51,7 @@
 }
 
 int module_list_functions(void) {
-  LLVMModuleRef M = load_module();
+  LLVMModuleRef M = load_module_from_bitcode();
   LLVMValueRef f;
 
   f = LLVMGetFirstFunction(M);
@@ -93,7 +92,7 @@
 }
 
 int module_list_globals(void) {
-  LLVMModuleRef M = load_module();
+  LLVMModuleRef M = load_module_from_bitcode();
   LLVMValueRef g;
 
   g = LLVMGetFirstGlobal(M);