tcf-0.1.0 initial contribution
diff --git a/.cproject b/.cproject
new file mode 100755
index 0000000..94a4eba
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,1126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<?fileVersion 4.0.0?>

+

+<cproject>

+<storageModule moduleId="org.eclipse.cdt.core.settings">

+<cconfiguration id="0.586632354">

+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.586632354" moduleId="org.eclipse.cdt.core.settings" name="Default">

+<externalSettings/>

+<extensions>

+<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+</extensions>

+</storageModule>

+<storageModule moduleId="cdtBuildSystem" version="4.0.0">

+<configuration artifactName="tcf_agent" buildProperties="" description="" id="0.586632354" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">

+<folderInfo id="0.586632354." name="/" resourcePath="">

+<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.629729441" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">

+<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.629729441.1497928954" name=""/>

+<builder buildPath="${workspace_loc:/tcf_agent}" id="org.eclipse.cdt.build.core.settings.default.builder.2122878837" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.libs.2009918965" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.287150531" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.766656885" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.1130235898" name="UPC" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.392331765" languageId="org.eclipse.cdt.core.parser.upc.upc" languageName="UPC" sourceContentType="org.eclipse.cdt.core.parser.upc.upcSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.371530632" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1910112652" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.1537638852" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.710318778" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+</toolChain>

+</folderInfo>

+</configuration>

+</storageModule>

+

+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>

+<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>

+<storageModule moduleId="scannerConfiguration">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<scannerConfigBuildInfo instanceId="0.586632354">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061">

+<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="false"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061.1624802268">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+</storageModule>

+</cconfiguration>

+<cconfiguration id="0.586632354.1278891061">

+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.586632354.1278891061" moduleId="org.eclipse.cdt.core.settings" name="win32 DevStudio">

+<externalSettings/>

+<extensions>

+<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+</extensions>

+</storageModule>

+<storageModule moduleId="cdtBuildSystem" version="4.0.0">

+<configuration artifactName="tcf_agent" buildProperties="" description="" id="0.586632354.1278891061" name="win32 DevStudio" parent="org.eclipse.cdt.build.core.prefbase.cfg">

+<folderInfo id="0.586632354.1278891061." name="/" resourcePath="">

+<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.21355112" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">

+<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.21355112.397805010" name=""/>

+<builder arguments="" autoBuildTarget="all" buildPath="${workspace_loc:/tcf_agent}" cleanBuildTarget="clean" command="" enableAutoBuild="false" enableCleanBuild="false" enabledIncrementalBuild="false" id="org.eclipse.cdt.build.core.settings.default.builder.405250935" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelizationNumber="1" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.libs.927042990" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.912870361" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1307700115" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.1871552088" name="UPC" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.253767805" languageId="org.eclipse.cdt.core.parser.upc.upc" languageName="UPC" sourceContentType="org.eclipse.cdt.core.parser.upc.upcSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.1705508330" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.990630428" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.392253741" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">

+<option id="org.eclipse.cdt.build.core.settings.holder.symbols.133765132" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">

+<listOptionValue builtIn="false" value="WIN32"/>

+</option>

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.2133262814" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+</toolChain>

+</folderInfo>

+</configuration>

+</storageModule>

+

+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>

+<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>

+<storageModule moduleId="scannerConfiguration">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<scannerConfigBuildInfo instanceId="0.586632354">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061">

+<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="false"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061.1624802268">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+</storageModule>

+</cconfiguration>

+<cconfiguration id="0.586632354.1278891061.1624802268">

+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.586632354.1278891061.1624802268" moduleId="org.eclipse.cdt.core.settings" name="win32 Cygwin">

+<externalSettings/>

+<extensions>

+<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>

+</extensions>

+</storageModule>

+<storageModule moduleId="cdtBuildSystem" version="4.0.0">

+<configuration artifactName="tcf_agent" buildProperties="" description="" id="0.586632354.1278891061.1624802268" name="win32 Cygwin" parent="org.eclipse.cdt.build.core.prefbase.cfg">

+<folderInfo id="0.586632354.1278891061.1624802268." name="/" resourcePath="">

+<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.817366280" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">

+<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.817366280.1321601800" name=""/>

+<builder arguments="-fMakefile_cygwin.mak" autoBuildTarget="all" buildPath="${workspace_loc:/tcf_agent}" cleanBuildTarget="clean" command="make" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="org.eclipse.cdt.build.core.settings.default.builder.248686569" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelizationNumber="1" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.libs.2050088693" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>

+<tool id="org.eclipse.cdt.build.core.settings.holder.760047734" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.293829655" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.1467692607" name="UPC" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1382477290" languageId="org.eclipse.cdt.core.parser.upc.upc" languageName="UPC" sourceContentType="org.eclipse.cdt.core.parser.upc.upcSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.2054278284" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.825872592" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+<tool id="org.eclipse.cdt.build.core.settings.holder.60917234" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">

+<option id="org.eclipse.cdt.build.core.settings.holder.symbols.749525598" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">

+<listOptionValue builtIn="false" value="WIN32"/>

+</option>

+<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1931856410" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

+</tool>

+</toolChain>

+</folderInfo>

+</configuration>

+</storageModule>

+

+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>

+<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>

+<storageModule moduleId="scannerConfiguration">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<scannerConfigBuildInfo instanceId="0.586632354">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="false" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061">

+<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="false"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="false"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+<scannerConfigBuildInfo instanceId="0.586632354.1278891061.1624802268">

+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="makefileGenerator">

+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">

+<buildOutputProvider>

+<openAction enabled="true" filePath=""/>

+<parser enabled="true"/>

+</buildOutputProvider>

+<scannerInfoProvider id="specsFile">

+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>

+<parser enabled="true"/>

+</scannerInfoProvider>

+</profile>

+</scannerConfigBuildInfo>

+</storageModule>

+</cconfiguration>

+</storageModule>

+<storageModule moduleId="cdtBuildSystem" version="4.0.0">

+<project id="tcf_agent.null.1863878724" name="tcf_agent"/>

+</storageModule>

+</cproject>

diff --git a/.project b/.project
new file mode 100755
index 0000000..ab15138
--- /dev/null
+++ b/.project
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>tcf_agent</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/tcf_agent}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+	</natures>
+</projectDescription>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7a4717c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+CC=gcc
+CFLAGS=-g -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE
+OFILES=$(addsuffix .o,$(basename $(wildcard *.c)))
+HFILES=$(wildcard *.h)
+
+all: agent
+
+agent: $(OFILES)
+	$(CC) $(CFLAGS) -o $@ $(OFILES) -lpthread -lrt -lelf
+
+%.o: %.c $(HFILES)
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f *.o agent
diff --git a/Makefile_cygwin.mak b/Makefile_cygwin.mak
new file mode 100644
index 0000000..e797e4d
--- /dev/null
+++ b/Makefile_cygwin.mak
@@ -0,0 +1,16 @@
+CC=gcc -mconsole -mwin32 -mno-cygwin
+#CFLAGS=-O2 -DWIN32 -DNDEBUG -D_CONSOLE -D_MBCS
+CFLAGS=-g -DWIN32 -D_DEBUG -D_CONSOLE -D_MBCS
+OFILES=$(addsuffix .o,$(basename $(wildcard *.c)))
+HFILES=$(wildcard *.h)
+
+all: agent
+
+agent: $(OFILES)
+	$(CC) $(CFLAGS) -o $@ $(OFILES) -lkernel32 -luser32 -lshell32 -lWS2_32 -lIphlpapi
+
+%.o: %.c $(HFILES)
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f *.o agent
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000..172ebc6
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,80 @@
+          o   Shouldn't we separate command parsing from a service implementation?
+
+          o   we should use a typedef for addresses
+
+-        breakpoints.[ch]
+
+          o   We donÂ’t have any way to specify context specific breakpoints yet, right?  I think breakpoint
+              should always be associated with a context and since contexts can be execution contexts or containers
+              on different levels it is possible to describe thread specific breakpoints, process specific breakpoints,
+              system global breakpoint and any levels in-between.
+
+-        context.c
+
+          o   event_pid_stopped() using the PTRACE_EVENT_CLONE to determine if the new context is a thread is not correct.  The only
+              way I know of is to look at the Tgid field of /proc/<pid>/status
+
+-        runctrl.c
+
+          o   command_resume() and command_step_into() share so much code that they could be unified.
+
+          o   Sometimes you flush “broadcast_stream.flush(&broadcast_stream);”.  What is the logic/rules?
+
+          o   After prototype stage, the safe event mechanism needs to have finer granularity so it does not stop more than the process.
+
+          o   VxWorks: Need Component Description File for the agent: C:\WindRiver-2.6\vxworks-6.5\target\config\comps\vxWorks
+
+11/1/2007
+
+-        It would be really good to put comments on at least the ­­all global functions in headers.
+
+-        Complex structures would also be very good to put comments on.  For example in breakpoints.c
+
+-        Somehow we should make it clear what needs to be done to add another transport layer.
+         Perhaps have a template or a readme file for it.
+
+-        breakpoints.c, line 190: if (!bi->ctx->exited && bi->ctx->stopped) {
+
+          o   Why is bi->ctx->stopped test needed?  It looks like we forget to unpatch the instruction is the target
+               happens to be running when we get to this point since after the if the “planted” flag is unconditionally
+               cleared.  ShouldnÂ’t this be an assert instead?
+
+          o   Similar problem if context_write_mem() results in error then we clear the planted flag even though we havenÂ’t
+               really unplanted it.
+
+-        breakpoints.c, line 231: if (bi->ctx->exited || !bi->ctx->stopped) {
+
+          o   What is the inside this used for?
+
+-        streams.h: 
+
+          o   It would be good if the InputStream and OutputStream was designed so characters could be read/written without
+               causing a function call in the normal case.  Something similar to stdio getc/putc.
+
+-        channel.c in function channels_suspend(): Should we add “assert(!suspended);” to make sure it is not called multiple
+         times since we donÂ’t have a suspend count?
+
+-        context.c, line 891 & 928: 
+
+          o   should say “~(WORD_SIZE-1)” instead of “~3ul”
+
+-        processes.c, line 266: 
+
+          o   We should have an abstraction of the signal number or some way from the client to map between names and numbers
+               so clients donÂ’t have to be target dependent.
+
+-        registers.c:
+
+          o   Get/set commands does not handle reading multiple registers.  Should it?
+
+          o   Why are register values returned as strings?
+
+-        runctrl.c, line 326
+
+          o   Should it not return the error code to the client?
+
+-        stacktrace.c
+
+          o   line 176: DonÂ’t we need to check code[0] in this case?
+
+          o   Line 242: no error check on strtol.  Why not used id2pid?
diff --git a/agent.dsp b/agent.dsp
new file mode 100644
index 0000000..862e48b
--- /dev/null
+++ b/agent.dsp
@@ -0,0 +1,341 @@
+# Microsoft Developer Studio Project File - Name="agent" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 5.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=agent - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "agent.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "agent.mak" CFG="agent - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "agent - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "agent - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "agent - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "Release"

+# PROP BASE Intermediate_Dir "Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "Release"

+# PROP Intermediate_Dir "Release"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x409 /d "NDEBUG"

+# ADD RSC /l 0x409 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib WS2_32.lib Iphlpapi.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "agent - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "Debug"

+# PROP BASE Intermediate_Dir "Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "Debug"

+# PROP Intermediate_Dir "Debug"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x409 /d "_DEBUG"

+# ADD RSC /l 0x409 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib WS2_32.lib Iphlpapi.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "agent - Win32 Release"

+# Name "agent - Win32 Debug"

+# Begin Source File

+

+SOURCE=.\base64.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\base64.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\breakpoints.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\breakpoints.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\channel.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\channel.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\cmdline.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\cmdline.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\config.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\context.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\context.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\diagnostics.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\diagnostics.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\dwarf.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\dwarfio.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\dwarfio.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\elf.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\elf.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\errors.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\errors.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\events.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\events.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\exceptions.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\exceptions.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\expressions.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\expressions.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\filesystem.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\filesystem.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\json.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\json.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\linenumbers.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\linenumbers.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\link.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\main.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\mdep.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\mdep.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\memory.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\memory.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\myalloc.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\myalloc.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\processes.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\processes.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\protocol.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\protocol.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\proxy.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\proxy.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\registers.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\registers.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\runctrl.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\runctrl.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\stacktrace.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\stacktrace.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\streams.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\streams.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\symbols.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\symbols.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\sysmon.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\sysmon.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\tcf.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\test.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\test.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TODO.txt

+# End Source File

+# Begin Source File

+

+SOURCE=.\trace.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\trace.h

+# End Source File

+# End Target

+# End Project

diff --git a/agent.dsw b/agent.dsw
new file mode 100644
index 0000000..18f18f7
--- /dev/null
+++ b/agent.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00

+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!

+

+###############################################################################

+

+Project: "agent"=.\agent.dsp - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+}}}

+

+###############################################################################

+

+Global:

+

+Package=<5>

+{{{

+}}}

+

+Package=<3>

+{{{

+}}}

+

+###############################################################################

+

diff --git a/base64.c b/base64.c
new file mode 100644
index 0000000..e6e5f98
--- /dev/null
+++ b/base64.c
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements BASE64 encoding and decoding of binary data.
+ * BASE64 encoding is adapted from RFC 1421, with one change:
+ * BASE64 eliminates the "*" mechanism for embedded clear text.
+ * Also TCF version of the encoding does not allow characters outside of the BASE64 alphabet. 
+ */
+
+#if _WRS_KERNEL
+#  include <vxWorks.h>
+#endif
+#include <assert.h>
+#include "base64.h"
+#include "exceptions.h"
+#include "errors.h"
+
+static const char int2char[] = {
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
+    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+    'w', 'x', 'y', 'z', '0', '1', '2', '3',
+    '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+static const int char2int[] = {
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  62,  -1,  -1,  -1,  63,
+    52,  53,  54,  55,  56,  57,  58,  59,
+    60,  61,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,   0,   1,   2,   3,   4,   5,   6,
+     7,   8,   9,  10,  11,  12,  13,  14,
+    15,  16,  17,  18,  19,  20,  21,  22,
+    23,  24,  25,  -1,  -1,  -1,  -1,  -1,
+    -1,  26,  27,  28,  29,  30,  31,  32,
+    33,  34,  35,  36,  37,  38,  39,  40,
+    41,  42,  43,  44,  45,  46,  47,  48,
+    49, 50, 51
+};
+
+int write_base64(OutputStream * out, char * buf0, int len) {
+    int pos = 0;
+    unsigned char * buf = (unsigned char *)buf0;
+
+    while (pos < len) {
+        int byte0 = buf[pos++];
+        out->write(out, int2char[byte0 >> 2]);
+        if (pos == len) {
+            out->write(out, int2char[(byte0 << 4) & 0x3f]);
+            out->write(out, '=');
+            out->write(out, '=');
+        }
+        else {
+            int byte1 = buf[pos++];
+            out->write(out, int2char[(byte0 << 4) & 0x3f | (byte1 >> 4)]);
+            if (pos == len) {
+                out->write(out, int2char[(byte1 << 2) & 0x3f]);
+                out->write(out, '=');
+            }
+            else {
+                int byte2 = buf[pos++];
+                out->write(out, int2char[(byte1 << 2) & 0x3f | (byte2 >> 6)]);
+                out->write(out, int2char[byte2 & 0x3f]);
+            }
+        }
+    }
+    assert(pos == len);
+    return ((len + 2) / 3) * 4;
+}
+
+int read_base64(InputStream * inp, char * buf, int buf_size) {
+    int pos = 0;
+    int ch_max = sizeof(char2int) / sizeof(int);
+
+    while (pos + 3 <= buf_size) {
+        int n0, n1, n2, n3;
+        int ch0, ch1, ch2, ch3;
+
+        ch0 = inp->peek(inp);
+        if (ch0 < 0 || ch0 >= ch_max || (n0 = char2int[ch0]) < 0) break;
+        inp->read(inp);
+        ch1 = inp->read(inp);
+        ch2 = inp->read(inp);
+        ch3 = inp->read(inp);
+        if (ch1 < 0 || ch1 >= ch_max || (n1 = char2int[ch1]) < 0) exception(ERR_BASE64);
+        buf[pos++] = (char)((n0 << 2) | (n1 >> 4));
+        if (ch2 == '=') break;
+        if (ch2 < 0 || ch2 >= ch_max || (n2 = char2int[ch2]) < 0) exception(ERR_BASE64);
+        buf[pos++] = (char)((n1 << 4) | (n2 >> 2));
+        if (ch3 == '=') break;
+        if (ch3 < 0 || ch3 >= ch_max || (n3 = char2int[ch3]) < 0) exception(ERR_BASE64);
+        buf[pos++] = (char)((n2 << 6) | n3);
+    }
+    return pos;
+}
+
diff --git a/base64.h b/base64.h
new file mode 100644
index 0000000..6df638a
--- /dev/null
+++ b/base64.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements BASE64 encoding and decoding of binary data.
+ * BASE64 encoding is adapted from RFC 1421, with one change:
+ * BASE64 eliminates the "*" mechanism for embedded clear text.
+ * Also TCF version of the encoding does not allow characters outside of the BASE64 alphabet. 
+ */
+
+#ifndef D_base64
+#define D_base64
+
+#include "streams.h"
+
+/*
+ * Write BASE64 encoded array of bytes to output stream.
+ */
+extern int write_base64(OutputStream * out, char * buf, int len);
+
+/*
+ * Read BASE64 encoded array of bytes from input stream.
+ * Returns number of decoded bytes.
+ */
+extern int read_base64(InputStream * inp, char * buf, int buf_size);
+
+#endif
diff --git a/breakpoints.c b/breakpoints.c
new file mode 100644
index 0000000..9465210
--- /dev/null
+++ b/breakpoints.c
@@ -0,0 +1,964 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements Breakpoints service.
+ * The service maintains a list of breakpoints.
+ * Each breakpoint consists of one or more conditions that determine
+ * when a program's execution should be interrupted.
+ */
+
+#include "config.h"
+#if SERVICE_Breakpoints
+
+// TODO: breakpoint status reports
+// TODO: replant breakpoints when shared lib is loaded or unloaded
+
+#if defined(_WRS_KERNEL)
+#  include <vxWorks.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+#include "breakpoints.h"
+#include "expressions.h"
+#include "channel.h"
+#include "protocol.h"
+#include "errors.h"
+#include "trace.h"
+#include "runctrl.h"
+#include "context.h"
+#include "myalloc.h"
+#include "exceptions.h"
+#include "symbols.h"
+#include "json.h"
+#include "link.h"
+
+#ifdef BREAK_INST
+#  undef BREAK_INST
+#endif
+
+#if defined(_WRS_KERNEL)
+
+#include <private/vxdbgLibP.h>
+
+#elif defined(__i386__)
+
+static unsigned char BREAK_INST[] = { 0xcc };   /* breakpoint instruction */
+#define BREAK_SIZE 1    /* breakpoint instruction size */
+
+#else
+
+#error "Unknown CPU"
+
+#endif
+
+typedef struct BreakpointRef BreakpointRef;
+typedef struct BreakpointInfo BreakpointInfo;
+typedef struct BreakInstruction BreakInstruction;
+
+struct BreakpointRef {
+    LINK link_inp;
+    LINK link_bp;
+    InputStream * inp;
+    BreakpointInfo * bp;
+};
+
+struct BreakpointInfo {
+    LINK link_all;
+    LINK link_id;
+    LINK refs;
+    char id[64];
+    int enabled;
+    int unsupported;
+    int planted;
+    int deleted;
+    int error;
+    char * err_msg;
+    char * address;
+    char * condition;
+};
+
+struct BreakInstruction {
+    LINK link_all;
+    LINK link_adr;
+    Context * ctx;
+    int ctx_cnt;
+    unsigned long address;
+#if defined(_WRS_KERNEL)
+    VXDBG_CTX vxdbg_ctx;
+    VXDBG_BP_ID vxdbg_id;
+#else
+    char saved_code[BREAK_SIZE];
+#endif    
+    int error;
+    int skip;
+    BreakpointInfo ** refs;
+    int ref_size;
+    int ref_cnt;
+    int planted;
+};
+
+static const char * BREAKPOINTS = "Breakpoints";
+
+#define ADDR2INSTR_HASH_SIZE 1023
+#define addr2instr_hash(addr) (((addr) + ((addr) >> 8)) % ADDR2INSTR_HASH_SIZE)
+
+#define link_all2bi(A)  ((BreakInstruction *)((char *)(A) - (int)&((BreakInstruction *)0)->link_all))
+#define link_adr2bi(A)  ((BreakInstruction *)((char *)(A) - (int)&((BreakInstruction *)0)->link_adr))
+
+#define ID2BP_HASH_SIZE 1023
+
+#define link_all2bp(A)  ((BreakpointInfo *)((char *)(A) - (int)&((BreakpointInfo *)0)->link_all))
+#define link_id2bp(A)   ((BreakpointInfo *)((char *)(A) - (int)&((BreakpointInfo *)0)->link_id))
+
+#define INP2BR_HASH_SIZE 127
+
+#define link_inp2br(A)  ((BreakpointRef *)((char *)(A) - (int)&((BreakpointRef *)0)->link_inp))
+#define link_bp2br(A)   ((BreakpointRef *)((char *)(A) - (int)&((BreakpointRef *)0)->link_bp))
+
+static LINK breakpoints;
+static LINK id2bp[ID2BP_HASH_SIZE];
+
+static LINK instructions;
+static LINK addr2instr[ADDR2INSTR_HASH_SIZE];
+
+static LINK inp2br[INP2BR_HASH_SIZE];
+
+static int replanting = 0;
+
+static Context * expression_context = NULL;
+static int address_expression_identifier(char * name, Value * v);
+static int condition_expression_identifier(char * name, Value * v);
+static ExpressionContext bp_address_ctx = { address_expression_identifier, NULL };
+static ExpressionContext bp_condition_ctx = { condition_expression_identifier, NULL };
+
+static int id2bp_hash(char * id) {
+    unsigned hash = 0;
+    while (*id) hash = (hash >> 16) + hash + (unsigned char)*id++;
+    return hash % ID2BP_HASH_SIZE;
+}
+
+static void plant_instruction(BreakInstruction * bi) {
+    assert(!bi->planted);
+#if defined(_WRS_KERNEL)
+    bi->vxdbg_ctx.ctxId = bi->ctx_cnt == 1 ? bi->ctx->pid : 0;
+    bi->vxdbg_ctx.ctxId = 0;
+    bi->vxdbg_ctx.ctxType = VXDBG_CTX_TASK;
+    if (vxdbgBpAdd(vxdbg_clnt_id,
+            &bi->vxdbg_ctx, 0, BP_ACTION_STOP | BP_ACTION_NOTIFY,
+            0, 0, (INSTR *)bi->address, 0, 0, &bi->vxdbg_id) != OK) {
+        bi->error = errno;
+        assert(bi->error != 0);
+    }
+#else    
+    if (context_read_mem(bi->ctx, bi->address, bi->saved_code, BREAK_SIZE) < 0) {
+        bi->error = errno;
+    }
+    else if (context_write_mem(bi->ctx, bi->address, &BREAK_INST, BREAK_SIZE) < 0) {
+        bi->error = errno;
+    }
+#endif
+    bi->planted = bi->error == 0;
+}
+
+static int verify_instruction(BreakInstruction * bi) {
+    assert(bi->planted);
+#if defined(_WRS_KERNEL)
+    return bi->vxdbg_ctx.ctxId == (bi->ctx_cnt == 1 ? bi->ctx->pid : 0) &&
+           bi->vxdbg_ctx.ctxType == VXDBG_CTX_TASK;
+#else
+    return 1;
+#endif
+}
+
+static void remove_instruction(BreakInstruction * bi) {
+    assert(bi->planted);
+    assert(!bi->error);
+#ifdef _WRS_KERNEL
+    {
+        VXDBG_BP_DEL_INFO info;
+        memset(&info, 0, sizeof(info));
+        info.pClnt = vxdbg_clnt_id;
+        info.type = BP_BY_ID_DELETE;
+        info.info.id.bpId = bi->vxdbg_id;
+        if (vxdbgBpDelete(info) != OK) {
+            bi->error = errno;
+            assert(bi->error != 0);
+        }
+    }
+#else                
+    if (!bi->ctx->exited && bi->ctx->stopped) {
+        if (context_write_mem(bi->ctx, bi->address, bi->saved_code, BREAK_SIZE) < 0) {
+            bi->error = errno;
+        }
+    }
+#endif
+    bi->planted = 0;
+}
+
+static BreakInstruction * add_instruction(Context * ctx, unsigned long address) {
+    int hash = addr2instr_hash(address);
+    BreakInstruction * bi = (BreakInstruction *)loc_alloc_zero(sizeof(BreakInstruction));
+    list_add_last(&bi->link_all, &instructions);
+    list_add_last(&bi->link_adr, addr2instr + hash);
+    context_lock(ctx);
+    bi->ctx = ctx;
+    bi->address = address;
+    return bi;
+}
+
+static void clear_instruction_refs(void) {
+    LINK * l = instructions.next;
+    while (l != &instructions) {
+        BreakInstruction * bi = link_all2bi(l);
+        bi->ctx_cnt = 1;
+        bi->ref_cnt = 0;
+        l = l->next;
+    }
+}
+
+static void delete_unused_instructions(void) {
+    LINK * l = instructions.next;
+    while (l != &instructions) {
+        BreakInstruction * bi = link_all2bi(l);
+        l = l->next;
+        if (bi->skip) continue;
+        if (bi->ref_cnt == 0) {
+            list_remove(&bi->link_all);
+            list_remove(&bi->link_adr);
+            if (bi->planted) {
+                if (bi->ctx->exited || !bi->ctx->stopped) {
+                    LINK * qp = context_root.next;
+                    while (qp != &context_root) {
+                        Context * ctx = ctxl2ctxp(qp);
+                        qp = qp->next;
+                        if (ctx->mem == bi->ctx->mem && !ctx->exited && ctx->stopped) {
+                            assert(bi->ctx != ctx);
+                            context_unlock(bi->ctx);
+                            context_lock(ctx);
+                            bi->ctx = ctx;
+                            break;
+                        }
+                    }
+                }
+                remove_instruction(bi);
+            }
+            context_unlock(bi->ctx);
+            loc_free(bi->refs);
+            loc_free(bi);
+        }
+        else if (!bi->planted) {
+            plant_instruction(bi);
+        }
+        else if (!verify_instruction(bi)) {
+            remove_instruction(bi);
+            plant_instruction(bi);
+        }
+    }
+}
+
+static BreakInstruction * find_instruction(Context * ctx, unsigned long address) {
+    int hash = addr2instr_hash(address);
+    LINK * l = addr2instr[hash].next;
+    assert(!ctx->exited && ctx->stopped);
+    while (l != addr2instr + hash) {
+        BreakInstruction * bi = link_adr2bi(l);
+        l = l->next;
+        if (bi->ctx->mem == ctx->mem && bi->address == address) {
+            if (bi->ctx->exited || !bi->ctx->stopped) {
+                assert(bi->ctx != ctx);
+                context_unlock(bi->ctx);
+                context_lock(ctx);
+                bi->ctx = ctx;
+            }
+            return bi;
+        }
+    }
+    return NULL;
+}
+
+static int address_expression_identifier(char * name, Value * v) {
+    Symbol sym;
+    if (v == NULL) return 0;
+    memset(v, 0, sizeof(Value));
+    if (expression_context == NULL) {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    if (strcmp(name, "$thread") == 0) {
+        string_value(v, thread_id(expression_context));
+        return 0;
+    }
+    if (find_symbol(expression_context, name, &sym) < 0) {
+        if (errno != ERR_SYM_NOT_FOUND) return -1;
+    }
+    else {
+        v->type = VALUE_UNS;
+        v->value = sym.value;
+        return 0;
+    }
+    errno = ERR_SYM_NOT_FOUND;
+    return -1;
+}
+
+static void address_expression_error(BreakpointInfo * bp, char * msg) {
+    // TODO: per-context address expression error report
+    int size;
+    if (bp->error) return;
+    bp->error = errno;
+    if (msg == NULL) msg = get_expression_error_msg();
+    assert(bp->err_msg == NULL);
+    size = strlen(msg) + strlen(bp->address) + 64;
+    bp->err_msg = loc_alloc(size);
+    snprintf(bp->err_msg, size, "Invalid breakpoint address '%s': %s", bp->address, msg);
+}
+
+static void plant_breakpoint(BreakpointInfo * bp) {
+    LINK * qp;
+    char * p = NULL;
+    Value v;
+    int context_sensitive = 0;
+
+    assert(!bp->planted);
+    assert(bp->enabled);
+    bp->error = 0;
+    if (bp->err_msg != NULL) loc_free(bp->err_msg);
+
+    if (bp->address == NULL) {
+        bp->error = ERR_INV_EXPRESSION;
+        trace(LOG_ALWAYS, "No breakpoint address");
+        return;
+    }
+    expression_context = NULL;
+    if (evaluate_expression(&bp_address_ctx, bp->address, &v) < 0) {
+        if (errno != ERR_INV_CONTEXT) {
+            address_expression_error(bp, NULL);
+            trace(LOG_ALWAYS, "Error: %s", bp->err_msg);
+            return;
+        }
+        context_sensitive = 1;
+    }
+    if (!context_sensitive && v.type != VALUE_INT && v.type != VALUE_UNS) {
+        errno = ERR_INV_EXPRESSION;
+        address_expression_error(bp, "Must be integer number");
+        trace(LOG_ALWAYS, "Error: %s", bp->err_msg);
+        return;
+    }
+
+    for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+        BreakInstruction * bi = NULL;
+        Context * ctx = ctxl2ctxp(qp);
+
+        if (ctx->exited || ctx->exiting) continue;
+        assert(ctx->stopped);
+        if (context_sensitive) {
+            expression_context = ctx;
+            if (evaluate_expression(&bp_address_ctx, bp->address, &v) < 0) {
+                address_expression_error(bp, NULL);
+                trace(LOG_ALWAYS, "Error: %s", bp->err_msg);
+                continue;
+            }
+            if (v.type != VALUE_INT && v.type != VALUE_UNS) {
+                errno = ERR_INV_EXPRESSION;
+                address_expression_error(bp, "Must be integer number");
+                continue;
+            }
+        }
+        if (bp->condition != NULL) {
+            /* Optimize away the breakpoint if condition is always false for given context */
+            Value c;
+            expression_context = ctx;
+            if (evaluate_expression(&bp_address_ctx, bp->condition, &c) == 0) {
+                switch (c.type) {
+                case VALUE_INT:
+                case VALUE_UNS:
+                    if (c.value == 0) continue;
+                    break;
+                case VALUE_STR:
+                    if (c.str == NULL) continue;
+                    break;
+                }
+            }
+        }
+        bi = find_instruction(ctx, v.value);
+        if (bi == NULL) {
+            bi = add_instruction(ctx, v.value);
+        }
+        else if (bp->planted) {
+            int i = 0;
+            while (i < bi->ref_cnt && bi->refs[i] != bp) i++;
+            if (i < bi->ref_cnt) continue;
+        }
+        if (bi->ref_cnt >= bi->ref_size) {
+            bi->ref_size = bi->ref_size == 0 ? 8 : bi->ref_size * 2;
+            bi->refs = (BreakpointInfo **)loc_realloc(bi->refs, sizeof(BreakpointInfo *) * bi->ref_size);
+        }
+        bi->refs[bi->ref_cnt++] = bp;
+        if (bi->ctx != ctx) bi->ctx_cnt++;
+        if (bi->error) {
+            if (!bp->error) bp->error = bi->error;
+        }
+        else {
+            bp->planted = 1;
+        }
+    }
+    if (bp->planted) bp->error = 0;
+}
+
+static void event_replant_breakpoints(void *arg) {
+    LINK * l = breakpoints.next;
+    replanting = 0;
+    clear_instruction_refs();
+    while (l != &breakpoints) {
+        BreakpointInfo * bp = link_all2bp(l);
+        l = l->next;
+        if (bp->deleted) {
+            list_remove(&bp->link_all);
+            list_remove(&bp->link_id);
+            loc_free(bp->err_msg);
+            loc_free(bp->address);
+            loc_free(bp->condition);
+            loc_free(bp);
+            continue;
+        }
+        bp->planted = 0;
+        if (bp->enabled && !bp->unsupported) {
+            plant_breakpoint(bp);
+        }
+    }
+    delete_unused_instructions();
+}
+
+static void replant_breakpoints(void) {
+    if (list_is_empty(&breakpoints) && list_is_empty(&instructions)) return;
+    if (replanting) return;
+    replanting = 1;
+    post_safe_event(event_replant_breakpoints, NULL);
+}
+
+static int str_equ(char * x, char * y) {
+    if (x == y) return 1;
+    if (x == NULL) return 0;
+    if (y == NULL) return 0;
+    return strcmp(x, y) == 0;
+}
+
+static int copy_breakpoint_info(BreakpointInfo * dst, BreakpointInfo * src) {
+    int res = 0;
+    if (strcmp(dst->id, src->id) != 0) {
+        strcpy(dst->id, src->id);
+        res = 1;
+    }
+    if (dst->enabled != src->enabled) {
+        dst->enabled = src->enabled;
+        res = 1;
+    }
+    if (dst->unsupported != src->unsupported) {
+        dst->unsupported = src->unsupported;
+        res = 1;
+    }
+    if (!str_equ(dst->address, src->address)) {
+        loc_free(dst->address);
+        dst->address = src->address;
+        res = 1;
+    }
+    else {
+        loc_free(src->address);
+    }
+    src->address = NULL;
+    if (!str_equ(dst->condition, src->condition)) {
+        loc_free(dst->condition);
+        dst->condition = src->condition;
+        res = 1;
+    }
+    else {
+        loc_free(src->condition);
+    }
+    src->condition = NULL;
+    return res;
+}
+
+static BreakpointInfo * find_breakpoint(char * id) {
+    int hash = id2bp_hash(id);
+    LINK * l = id2bp[hash].next;
+    while (l != id2bp + hash) {
+        BreakpointInfo * bp = link_id2bp(l);
+        l = l->next;
+        if (strcmp(bp->id, id) == 0) return bp;
+    }
+    return NULL;
+}
+
+static BreakpointRef * find_breakpoint_ref(BreakpointInfo * bp, InputStream * inp) {
+    LINK * l;
+    if (bp == NULL) return NULL;
+    l = bp->refs.next;
+    while (l != &bp->refs) {
+        BreakpointRef * br = link_bp2br(l);
+        assert(br->bp == bp);
+        if (br->inp == inp) return br;
+        l = l->next;
+    }
+    return NULL;
+}
+
+static void add_breakpoint(InputStream * inp, BreakpointInfo * bp) {
+    BreakpointRef * r = NULL;
+    BreakpointInfo * i = NULL;
+    int chng = 0;
+    i = find_breakpoint(bp->id);
+    if (i == NULL) {
+        int hash = id2bp_hash(bp->id);
+        i = (BreakpointInfo *)loc_alloc_zero(sizeof(BreakpointInfo));
+        list_init(&i->refs);
+        list_add_last(&i->link_all, &breakpoints);
+        list_add_last(&i->link_id, id2bp + hash);
+    }
+    chng = copy_breakpoint_info(i, bp);
+    if (i->deleted) {
+        i->deleted = 0;
+        chng = 1;
+    }
+    r = find_breakpoint_ref(i, inp);
+    if (r == NULL) {
+        int inp_hash = (int)inp / 16 % INP2BR_HASH_SIZE;
+        r = (BreakpointRef *)loc_alloc_zero(sizeof(BreakpointRef));
+        list_add_last(&r->link_inp, inp2br + inp_hash);
+        list_add_last(&r->link_bp, &i->refs);
+        r->inp = inp;
+        r->bp = i;
+    }
+    else {
+        assert(r->bp == i);
+        assert(!list_is_empty(&i->refs));
+    }
+    if (chng) {
+        if (i->planted || i->enabled && !i->unsupported) replant_breakpoints();
+    }
+}
+
+static void remove_breakpoint(BreakpointInfo * bp) {
+    assert(list_is_empty(&bp->refs));
+    if (bp->planted) {
+        bp->deleted = 1;
+        replant_breakpoints();
+    }
+    else {
+        list_remove(&bp->link_all);
+        list_remove(&bp->link_id);
+        loc_free(bp->address);
+        loc_free(bp->condition);
+        loc_free(bp);
+    }
+}
+
+static void remove_ref(BreakpointRef * br) {
+    BreakpointInfo * bp = br->bp;
+    list_remove(&br->link_inp);
+    list_remove(&br->link_bp);
+    loc_free(br);
+    if (list_is_empty(&bp->refs)) remove_breakpoint(bp);
+}
+
+static void delete_breakpoint_refs(InputStream * inp) {
+    int hash = (int)inp / 16 % INP2BR_HASH_SIZE;
+    LINK * l = inp2br[hash].next;
+    while (l != &inp2br[hash]) {
+        BreakpointRef * br = link_inp2br(l);
+        l = l->next;
+        if (br->inp == inp) remove_ref(br);
+    }
+}
+
+static void read_breakpoint_properties(InputStream * inp, BreakpointInfo * bp) {
+    memset(bp, 0, sizeof(BreakpointInfo));
+    if (inp->read(inp) != '{') exception(ERR_JSON_SYNTAX);
+    if (inp->peek(inp) == '}') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            int ch;
+            char name[256];
+            json_read_string(inp, name, sizeof(name));
+            if (inp->read(inp) != ':') exception(ERR_JSON_SYNTAX);
+            if (strcmp(name, "ID") == 0) {
+                json_read_string(inp, bp->id, sizeof(bp->id));
+            }
+            else if (strcmp(name, "Address") == 0) {
+                bp->address = json_read_alloc_string(inp);
+            }
+            else if (strcmp(name, "Condition") == 0) {
+                bp->condition = json_read_alloc_string(inp);
+            }
+            else if (strcmp(name, "Enabled") == 0) {
+                bp->enabled = json_read_boolean(inp);
+            }
+            else {
+                bp->unsupported = 1;
+                json_skip_object(inp);
+            }
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == '}') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+}
+
+static void command_ini_bps(char * token, InputStream * inp, OutputStream * out) {
+    delete_breakpoint_refs(inp);
+    if (inp->read(inp) != '[') exception(ERR_PROTOCOL);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            int ch;
+            BreakpointInfo bp;
+            read_breakpoint_properties(inp, &bp);
+            add_breakpoint(inp, &bp);
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_bp_ids(char * token, InputStream * inp, OutputStream * out) {
+    // TODO: implement command_get_bp_ids()
+    exception(ERR_PROTOCOL);
+}
+
+static void command_get_properties(char * token, InputStream * inp, OutputStream * out) {
+    // TODO: implement command_get_properties()
+    exception(ERR_PROTOCOL);
+}
+
+static void command_get_status(char * token, InputStream * inp, OutputStream * out) {
+    // TODO: implement command_get_status()
+    exception(ERR_PROTOCOL);
+}
+
+static void command_bp_add(char * token, InputStream * inp, OutputStream * out) {
+    BreakpointInfo bp;
+    read_breakpoint_properties(inp, &bp);
+    add_breakpoint(inp, &bp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_bp_change(char * token, InputStream * inp, OutputStream * out) {
+    BreakpointInfo bp;
+    BreakpointInfo * p;
+    read_breakpoint_properties(inp, &bp);
+    p = find_breakpoint(bp.id);
+    if (p != NULL && copy_breakpoint_info(p, &bp)) {
+        if (p->planted || p->enabled && !p->unsupported) replant_breakpoints();
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_bp_enable(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != '[') exception(ERR_PROTOCOL);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            int ch;
+            char id[256];
+            BreakpointInfo * bp;
+            json_read_string(inp, id, sizeof(id));
+            bp = find_breakpoint(id);
+            if (bp != NULL && !bp->enabled) {
+                bp->enabled = 1;
+                if (!bp->deleted && !bp->unsupported) replant_breakpoints();
+            }
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_bp_disable(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != '[') exception(ERR_PROTOCOL);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            int ch;
+            char id[256];
+            BreakpointInfo * bp;
+            json_read_string(inp, id, sizeof(id));
+            bp = find_breakpoint(id);
+            if (bp != NULL && bp->enabled) {
+                bp->enabled = 0;
+                if (bp->planted) replant_breakpoints();
+            }
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_bp_remove(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != '[') exception(ERR_PROTOCOL);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            int ch;
+            char id[256];
+            BreakpointRef * br;
+            json_read_string(inp, id, sizeof(id));
+            br = find_breakpoint_ref(find_breakpoint(id), inp);
+            if (br != NULL) remove_ref(br);
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+int is_stopped_by_breakpoint(Context * ctx) {
+    BreakInstruction * bi;
+
+    assert(!ctx->exited);
+    assert(ctx->stopped);
+#ifdef _WRS_KERNEL
+    return ctx->stopped_by_bp;
+#else
+    if (ctx->signal != SIGTRAP) return 0;
+    if (ctx->event != 0) return 0;
+    if (ctx->regs_error) return 0;
+    if (ctx->stopped_by_bp) return 1;
+    bi = find_instruction(ctx, get_regs_PC(ctx->regs) - BREAK_SIZE);
+    if (bi == NULL || bi->skip || bi->error) return 0;
+    set_regs_PC(ctx->regs, get_regs_PC(ctx->regs) - BREAK_SIZE);
+    ctx->regs_dirty = 1;
+    ctx->stopped_by_bp = 1;
+    return 1;
+#endif    
+}
+
+static int condition_expression_identifier(char * name, Value * v) {
+    return address_expression_identifier(name, v);
+}
+
+int evaluate_breakpoint_condition(Context * ctx) {
+    int i;
+    BreakInstruction * bi = find_instruction(ctx, get_regs_PC(ctx->regs));
+    if (bi == NULL) return 0;
+    expression_context = ctx;
+    for (i = 0; i < bi->ref_cnt; i++) {
+        Value v;
+        BreakpointInfo * bp = bi->refs[i];
+        assert(bp->planted);
+        assert(bp->error == 0);
+        if (bp->deleted) continue;
+        if (bp->unsupported) continue;
+        if (!bp->enabled) continue;
+        if (bp->condition == NULL) return 1;
+        if (evaluate_expression(&bp_condition_ctx, bp->condition, &v) < 0) {
+            trace(LOG_ALWAYS, "%s: %s", get_expression_error_msg(), bp->condition);
+            return 1;
+        }
+        switch (v.type) {
+        case VALUE_INT:
+        case VALUE_UNS:
+            if (v.value) return 1;
+            break;
+        case VALUE_STR:
+            if (v.str != NULL) return 1;
+            break;
+        }
+    }
+    return 0;
+}
+
+#ifndef _WRS_KERNEL
+
+static void safe_restore_breakpoint(void * arg) {
+    SkipBreakpointInfo * sb = (SkipBreakpointInfo *)arg;
+    BreakInstruction * bi = find_instruction(sb->ctx, sb->address);
+
+    assert(sb->ctx->regs_error || get_regs_PC(sb->ctx->regs) != sb->address);
+    if (bi != NULL && bi->skip) {
+        assert(bi->error == 0);
+        bi->skip = 0;
+        plant_instruction(bi);
+    }
+    if (sb->done) sb->done(sb);
+    if (sb->out) stream_unlock(sb->out);
+    context_unlock(sb->ctx);
+    loc_free(sb);
+}
+
+static void safe_skip_breakpoint(void * arg) {
+    SkipBreakpointInfo * sb = (SkipBreakpointInfo *)arg;
+
+    assert(!sb->ctx->exited);
+    assert(sb->ctx->stopped);
+    assert(!sb->ctx->intercepted);
+    assert(!sb->ctx->regs_error);
+    assert(sb->address == get_regs_PC(sb->ctx->regs));
+    
+    if (sb->error == 0) {
+        BreakInstruction * bi = find_instruction(sb->ctx, sb->address);
+        if (bi != NULL && !bi->skip) {
+            if (bi->error) {
+                sb->error = bi->error;
+            }
+            else {
+                remove_instruction(bi);
+                bi->skip = 1;
+            }
+        }
+    }
+    if (sb->error == 0) {
+        post_safe_event(safe_restore_breakpoint, sb);
+        if (context_single_step(sb->ctx) < 0) {
+            sb->error = errno;
+        }
+        else if (sb->pending_intercept) {
+            sb->ctx->pending_intercept = 1;
+        }
+    }
+    else {
+        if (sb->done) sb->done(sb);
+        if (sb->out) stream_unlock(sb->out);
+        context_unlock(sb->ctx);
+        loc_free(sb);
+    }
+}
+
+#endif
+
+/*
+ * When a context is stopped by breakpoint, it is necessary to disable
+ * the breakpoint temporarily before the context can be resumed.
+ * This function function removes break instruction, then does single step
+ * over breakpoint location, then restores break intruction.
+ * Return: NULL if it is OK to resume context from current state,
+ * SkipBreakpointInfo pointer if context needs to step over a breakpoint.
+ */
+SkipBreakpointInfo * skip_breakpoint(Context * ctx) {
+    BreakInstruction * bi;
+    SkipBreakpointInfo * sb;
+
+    assert(!ctx->exited);
+    assert(ctx->stopped);
+
+#ifdef _WRS_KERNEL
+    /* VxWork debug library can skip breakpoint when neccesary, no code is needed here */
+    return NULL;
+#else
+    if (ctx->exited || ctx->exiting) return NULL;
+    assert(!ctx->regs_error);
+    bi = find_instruction(ctx, get_regs_PC(ctx->regs));
+    if (bi == NULL || bi->error) return NULL;
+    assert(!bi->skip);
+    sb = (SkipBreakpointInfo *)loc_alloc_zero(sizeof(SkipBreakpointInfo));
+    context_lock(ctx);
+    sb->ctx = ctx;
+    sb->address = get_regs_PC(ctx->regs);
+    post_safe_event(safe_skip_breakpoint, sb);
+    return sb;
+#endif
+}
+
+static void event_context_created_or_exited(Context * ctx) {
+    if (ctx->parent == NULL) replant_breakpoints();
+}
+
+static void channel_close_listener(InputStream * inp, OutputStream * out) {
+    delete_breakpoint_refs(inp);
+}
+
+void ini_breakpoints_service(void) {
+    int i;
+    static ContextEventListener listener = {
+        event_context_created_or_exited,
+        event_context_created_or_exited,
+        NULL,
+        NULL,
+        NULL,
+        NULL
+    };
+    add_context_event_listener(&listener);
+    list_init(&breakpoints);
+    list_init(&instructions);
+    for (i = 0; i < ADDR2INSTR_HASH_SIZE; i++) list_init(addr2instr + i);
+    for (i = 0; i < ID2BP_HASH_SIZE; i++) list_init(id2bp + i);
+    for (i = 0; i < INP2BR_HASH_SIZE; i++) list_init(inp2br + i);
+    add_channel_close_listener(channel_close_listener);
+    add_command_handler(BREAKPOINTS, "set", command_ini_bps);
+    add_command_handler(BREAKPOINTS, "add", command_bp_add);
+    add_command_handler(BREAKPOINTS, "change", command_bp_change);
+    add_command_handler(BREAKPOINTS, "enable", command_bp_enable);
+    add_command_handler(BREAKPOINTS, "disable", command_bp_disable);
+    add_command_handler(BREAKPOINTS, "remove", command_bp_remove);
+    add_command_handler(BREAKPOINTS, "getBreakpointIDs", command_get_bp_ids);
+    add_command_handler(BREAKPOINTS, "getProperties", command_get_properties);
+    add_command_handler(BREAKPOINTS, "getStatus", command_get_status);
+}
+
+#endif
diff --git a/breakpoints.h b/breakpoints.h
new file mode 100644
index 0000000..2e486d6
--- /dev/null
+++ b/breakpoints.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements Breakpoints service.
+ * The service maintains a list of breakpoints.
+ * Each breakpoint consists of one or more conditions that determine
+ * when a program's execution should be interrupted.
+ */
+
+#ifndef D_breakpoints
+#define D_breakpoints
+
+#include "context.h"
+#include "streams.h"
+
+typedef unsigned long address_t;
+
+typedef struct SkipBreakpointInfo SkipBreakpointInfo;
+
+struct SkipBreakpointInfo {
+    Context * ctx;
+    address_t address;
+    int pending_intercept;
+    void (*done)(SkipBreakpointInfo *);
+    OutputStream * out;
+    char token[256];
+    int error;
+};
+
+extern int is_stopped_by_breakpoint(Context * ctx);
+
+extern int evaluate_breakpoint_condition(Context * ctx);
+
+extern SkipBreakpointInfo * skip_breakpoint(Context * ctx);
+
+extern void ini_breakpoints_service(void);
+
+#endif
diff --git a/channel.c b/channel.c
new file mode 100644
index 0000000..dd952b6
--- /dev/null
+++ b/channel.c
@@ -0,0 +1,763 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Implements input and output stream over TCP/IP transport and UDP based auto discovery.
+ */
+
+#if _WRS_KERNEL
+#  include <vxWorks.h>
+#endif
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+#include "mdep.h"
+#include "tcf.h"
+#include "channel.h"
+#include "myalloc.h"
+#include "protocol.h"
+#include "events.h"
+#include "exceptions.h"
+#include "trace.h"
+#include "link.h"
+#include "json.h"
+
+#define ESC 3
+#define BUF_SIZE 0x1000
+#define CHANNEL_MAGIC 0x87208956
+
+typedef struct Channel Channel;
+
+struct Channel {
+    int magic;
+    LINK link;
+
+    int socket;
+    pthread_t thread;       /* Socket receiving thread */
+    int thread_exited;
+    pthread_mutex_t mutex;  /* Channel data access synchronization lock */
+    pthread_cond_t signal;
+    int long_msg;           /* Message is longer then buffer, handlig should start before receiving EOM */
+    int waiting_space;      /* Receiving thread is waiting for buffer space */
+    int waiting_data;       /* Dispatch thread is waiting for data to read (long messages only) */
+    int message_count;      /* Number of messages waiting to be dispatched */
+    int event_posted;       /* Message handling event is posted to event queue */
+    int lock_cnt;           /* Stream lock count, when > 0 channel cannot be deleted */
+    int handling_msg;       /* Stream mutex is locked for input message handling */
+
+    /* Input stream buffer */
+    InputStream inp;
+    unsigned char ibuf[BUF_SIZE];
+    int ibuf_inp;
+    int ibuf_out;
+    int eof;
+    int peek;
+
+    /* Output stream state */
+    OutputStream out;
+    char obuf[BUF_SIZE];
+    int obuf_inp;
+    int out_errno;
+};
+
+#define link2channel(A) ((Channel *)((char *)(A) - (int)&((Channel *)0)->link))
+
+static int ip_port = 0;
+static int tcp_server_socket = -1;
+static int udp_server_socket = -1;
+static pthread_t tcp_server_thread = 0;
+static pthread_t udp_server_thread = 0;
+static LINK channels;
+static int suspended = 0;
+
+static void write_all(OutputStream * out, int byte);
+static void flush_all(OutputStream * out);
+OutputStream broadcast_stream = { write_all, flush_all };
+
+static ChannelCloseListener close_listeners[16];
+static int close_listeners_cnt = 0;
+
+static void delete_channel(Channel * c) {
+    int i;
+    trace(LOG_PROTOCOL, "Deleting channel 0x%08x", c);
+    assert(c->lock_cnt == 0);
+    for (i = 0; i < close_listeners_cnt; i++) {
+        close_listeners[i](&c->inp, &c->out);
+    }
+    list_remove(&c->link);
+    c->magic = 0;
+    loc_free(c);
+}
+
+void stream_lock(OutputStream * out) {
+    Channel * channel = (Channel *)((char *)out - offsetof(Channel, out));
+    assert(is_dispatch_thread());
+    assert(channel->magic == CHANNEL_MAGIC);
+    channel->lock_cnt++;
+}
+
+void stream_unlock(OutputStream * out) {
+    Channel * channel = (Channel *)((char *)out - offsetof(Channel, out));
+    assert(is_dispatch_thread());
+    assert(channel->magic == CHANNEL_MAGIC);
+    assert(channel->lock_cnt > 0);
+    channel->lock_cnt--;
+    if (channel->lock_cnt == 0) delete_channel(channel);
+}
+
+int is_stream_closed(OutputStream * out) {
+    Channel * channel = (Channel *)((char *)out - offsetof(Channel, out));
+    assert(is_dispatch_thread());
+    assert(channel->magic == CHANNEL_MAGIC);
+    assert(channel->lock_cnt > 0);
+    return channel->socket < 0;
+}
+
+static void flush_stream(OutputStream * out) {
+    Channel * channel = (Channel *)((char *)out - offsetof(Channel, out));
+    assert(is_dispatch_thread());
+    assert(channel->magic == CHANNEL_MAGIC);
+    if (channel->obuf_inp == 0) return;
+    if (channel->socket < 0) return;
+    if (channel->out_errno) return;
+    if (send(channel->socket, channel->obuf, channel->obuf_inp, 0) < 0) {
+        int err = errno;
+        trace(LOG_PROTOCOL, "Can't sent() on channel 0x%08x: %d %s", channel, err, errno_to_str(err));
+        channel->out_errno = err;
+    }
+    else {
+        channel->obuf_inp = 0;
+    }
+}
+
+static void flush_all(OutputStream * out) {
+    LINK * l = channels.next;
+    assert(is_dispatch_thread());
+    assert(out == &broadcast_stream);
+    while (l != &channels) {
+        flush_stream(&link2channel(l)->out);
+        l = l->next;
+    }
+}
+
+static void write_stream(OutputStream * out, int byte) {
+    Channel * channel = (Channel *)((char *)out - offsetof(Channel, out));
+    int b0 = byte;
+    assert(is_dispatch_thread());
+    assert(channel->magic == CHANNEL_MAGIC);
+    if (channel->socket < 0) return;
+    if (channel->out_errno) return;
+    if (b0 < 0) byte = ESC;
+    channel->obuf[channel->obuf_inp++] = byte;
+    if (channel->obuf_inp == BUF_SIZE) flush_stream(out);
+    if (b0 < 0 || b0 == ESC) {
+        if (b0 == ESC) byte = 0;
+        else if (b0 == MARKER_EOM) byte = 1;
+        else if (b0 == MARKER_EOS) byte = 2;
+        else assert(0);
+        if (channel->socket < 0) return;
+        if (channel->out_errno) return;
+        channel->obuf[channel->obuf_inp++] = byte;
+        if (channel->obuf_inp == BUF_SIZE) flush_stream(out);
+    }
+}
+
+static void write_all(OutputStream * out, int byte) {
+    LINK * l = channels.next;
+    assert(is_dispatch_thread());
+    assert(out == &broadcast_stream);
+    while (l != &channels) {
+        write_stream(&link2channel(l)->out, byte);
+        l = l->next;
+    }
+}
+
+static int read_byte(Channel * channel) {
+    int res;
+    assert(channel->message_count > 0);
+    while (channel->ibuf_inp == channel->ibuf_out) {
+        assert(channel->long_msg);
+        assert(channel->message_count == 1);
+        if (channel->waiting_space) {
+            assert(!channel->waiting_data);
+            pthread_cond_signal(&channel->signal);
+            channel->waiting_space = 0;
+        }
+        if (channel->eof) return MARKER_EOS;
+        if (channel->socket < 0) return MARKER_EOS;
+        assert(!channel->waiting_data);
+        assert(!channel->waiting_space);
+        channel->waiting_data = 1;
+        pthread_cond_wait(&channel->signal, &channel->mutex);
+        assert(!channel->waiting_data);
+    }
+    res = channel->ibuf[channel->ibuf_out];
+    channel->ibuf_out = (channel->ibuf_out + 1) % BUF_SIZE;
+    return res;
+}
+
+static int read_stream(InputStream * inp) {
+    int b;
+    Channel * c = (Channel *)((char *)inp - offsetof(Channel, inp));
+
+    assert(is_dispatch_thread());
+    assert(c->magic == CHANNEL_MAGIC);
+
+    if (c->peek != MARKER_NULL) {
+        assert(c->peek != MARKER_EOM);
+        b = c->peek;
+        c->peek = MARKER_NULL;
+    }
+    else {
+        if (!c->handling_msg) {
+            pthread_mutex_lock(&c->mutex);
+            c->handling_msg = 1;
+        }
+        b = read_byte(c);
+        if (b == ESC) {
+            b = read_byte(c);
+            if (b == 0) {
+                b = ESC;
+            }
+            else if (b == 1) {
+                b = MARKER_EOM;
+                c->message_count--;
+                if (c->waiting_space) {
+                    assert(!c->waiting_data);
+                    pthread_cond_signal(&c->signal);
+                    c->waiting_space = 0;
+                }
+                pthread_mutex_unlock(&c->mutex);
+                c->handling_msg = 0;
+            }
+            else if (b == 2) {
+                b = MARKER_EOS;
+            }
+        }
+    }
+
+    return b;
+}
+
+static int peek_stream(InputStream * inp) {
+    Channel * c = (Channel *)((char *)inp - offsetof(Channel, inp));
+    return c->peek = read_stream(inp);
+}
+
+static void send_eof_and_close(Channel * c, int err) {
+    assert(c->magic == CHANNEL_MAGIC);
+    write_stream(&c->out, MARKER_EOS);
+    write_errno(&c->out, err);
+    c->out.write(&c->out, MARKER_EOM);
+    c->out.flush(&c->out);
+    trace(LOG_PROTOCOL, "Closing socket, channel 0x%08x", c);
+    closesocket(c->socket);
+    c->socket = -1;
+}
+
+static void handle_channel_msg(void * x) {
+    Trap trap;
+    Channel * c = (Channel *)x;
+    assert(is_dispatch_thread());
+    for (;;) {
+        assert(c->magic == CHANNEL_MAGIC);
+        if (!c->handling_msg) {
+            pthread_mutex_lock(&c->mutex);
+            c->handling_msg = 1;
+        }
+        assert(c->event_posted);
+        if (c->thread_exited && (c->socket < 0 || c->message_count == 0 || c->long_msg)) {
+            void * res = NULL;
+            c->event_posted = 0;
+            c->handling_msg = 0;
+            pthread_mutex_unlock(&c->mutex);
+            if (c->thread) pthread_join(c->thread, &res);
+            if (c->socket >= 0) send_eof_and_close(c, 0);
+            stream_unlock(&c->out);
+            return;
+        }
+        if (c->message_count == 0 || suspended) {
+            c->event_posted = 0;
+            c->handling_msg = 0;
+            pthread_mutex_unlock(&c->mutex);
+            break;
+        }
+        if (set_trap(&trap)) {
+            handle_protocol_message(&c->inp, &c->out);
+            clear_trap(&trap);
+        }
+        else {
+            trace(LOG_ALWAYS, "Exception handling protocol message: %d %s",
+                trap.error, errno_to_str(trap.error));
+            c->peek = MARKER_NULL;
+            c->ibuf_out = c->ibuf_inp;
+            c->message_count = 0;
+            send_eof_and_close(c, trap.error);
+        }
+    }
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+static void * stream_socket_handler(void * x) {
+    int i;
+    int esc = 0;
+    Channel * channel = (Channel *)x;
+    unsigned char pkt[BUF_SIZE];
+
+    pthread_mutex_lock(&channel->mutex);
+    while (!channel->eof && channel->socket >= 0) {
+        int err = 0;
+        int rd = 0;
+
+        pthread_mutex_unlock(&channel->mutex);
+        rd = recv(channel->socket, (void *)pkt, sizeof(pkt), 0);
+        err = errno;
+        assert(channel->magic == CHANNEL_MAGIC);
+        pthread_mutex_lock(&channel->mutex);
+
+        if (rd < 0) {
+            trace(LOG_ALWAYS, "Can't read from socket: %s", errno_to_str(errno));
+            if (channel->socket < 0) break;
+            channel->eof = 1;
+            break;
+        }
+
+        if (rd == 0) {
+            trace(LOG_PROTOCOL, "Socket is shutdown by remote peer, channel 0x%08x", channel);
+            channel->eof = 1;
+            break;
+        }
+
+        for (i = 0; i < rd && !channel->eof; i++) {
+            unsigned char ch = pkt[i];
+            int ibuf_next = (channel->ibuf_inp + 1) % BUF_SIZE;
+            while (ibuf_next == channel->ibuf_out) {
+                if (channel->message_count == 0 && !channel->long_msg) {
+                    channel->long_msg = 1;
+                    channel->message_count = 1;
+                    if (!suspended && !channel->event_posted) {
+                        post_event(handle_channel_msg, channel);
+                        channel->event_posted = 1;
+                    }
+                }
+                assert(channel->message_count > 0);
+                assert(!channel->waiting_data);
+                assert(!channel->waiting_space);
+                channel->waiting_space = 1;
+                pthread_cond_wait(&channel->signal, &channel->mutex);
+                assert(ibuf_next == (channel->ibuf_inp + 1) % BUF_SIZE);
+                assert(!channel->waiting_space);
+            }
+            if (esc) {
+                esc = 0;
+                switch (ch) {
+                case 0:
+                    /* ESC byte */
+                    break;
+                case 1:
+                    /* EOM - End Of Message */
+                    if (channel->long_msg) {
+                        channel->long_msg = 0;
+                        assert(channel->message_count == 1);
+                    }
+                    else {
+                        channel->message_count++;
+                        if (!suspended && !channel->event_posted) {
+                            post_event(handle_channel_msg, channel);
+                            channel->event_posted = 1;
+                        }
+                    }
+                    break;
+                case 2:
+                    /* EOS - End Of Stream */
+                    trace(LOG_PROTOCOL, "End of stream on channel 0x%08x", channel);
+                    channel->eof = 1;
+                    break;
+                default:
+                    /* Invalid escape sequence */
+                    trace(LOG_ALWAYS, "Protocol: Invalid escape sequence");
+                    channel->eof = 1;
+                    ch = 2;
+                    break;
+                }
+            }
+            else {
+                esc = ch == ESC;
+            }
+            channel->ibuf[channel->ibuf_inp] = ch;
+            channel->ibuf_inp = ibuf_next;
+            if (channel->waiting_data) {
+                assert(!channel->waiting_space);
+                pthread_cond_signal(&channel->signal);
+                channel->waiting_data = 0;
+            }
+        }
+    }
+    if (channel->waiting_data) {
+        assert(!channel->waiting_space);
+        pthread_cond_signal(&channel->signal);
+        channel->waiting_data = 0;
+    }
+    if (!channel->event_posted) {
+        post_event(handle_channel_msg, channel);
+        channel->event_posted = 1;
+    }
+    channel->thread_exited = 1;
+    pthread_mutex_unlock(&channel->mutex);
+    return NULL;
+}
+
+static void handle_channel_open(void * x) {
+    const int i = 1;
+    int socket = (int)x;
+    Channel * c = NULL;
+    int error;
+
+    if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
+        trace(LOG_ALWAYS, "Can't set TCP_NODELAY option on a socket: %s", errno_to_str(errno));
+        closesocket(socket);
+        return;
+    }
+
+    c = (Channel *)loc_alloc_zero(sizeof(Channel));
+    c->magic = CHANNEL_MAGIC;
+    pthread_mutex_init(&c->mutex, NULL);
+    pthread_cond_init(&c->signal, NULL);
+    c->socket = socket;
+    c->inp.read = read_stream;
+    c->inp.peek = peek_stream;
+    c->out.write = write_stream;
+    c->out.flush = flush_stream;
+    c->peek = MARKER_NULL;
+
+    list_add_last(&c->link, &channels);
+    stream_lock(&c->out);
+    trace(LOG_PROTOCOL, "Openned channel 0x%08x", c);
+
+    send_hello_message(&c->out);
+    flush_stream(&c->out);
+
+    error = pthread_create(&c->thread, &pthread_create_attr, stream_socket_handler, c);
+    if (error) {
+        trace(LOG_ALWAYS, "Can't create a thread: %d %s", error, errno_to_str(error));
+        send_eof_and_close(c, 0);
+        stream_unlock(&c->out);
+    }
+}
+
+static void * tcp_server_socket_handler(void * x) {
+    for (;;) {
+        struct sockaddr_in sockaddr;
+        int i = sizeof(sockaddr);
+        int socket = accept(tcp_server_socket, (struct sockaddr *)&sockaddr, &i);
+
+        if (socket < 0) {
+            trace(LOG_ALWAYS, "socket accept failed: %d %s", errno, errno_to_str(errno));
+            continue;
+        }
+        post_event(handle_channel_open, (void *)socket);
+    }
+    return 0;
+}
+
+static void event_locator_hello(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != '[') exception(ERR_PROTOCOL);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            char ch;
+            char service[256];
+            json_read_string(inp, service, sizeof(service));
+            // TODO: remember remote service names
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+}
+
+static void app_char(char * buf, int * pos, char ch) {
+    if (*pos < PKT_SIZE) buf[*pos] = ch;
+    (*pos)++;
+}
+
+static void app_str(char * buf, int * pos, char * str) {
+    while (*str) {
+        if (*pos < PKT_SIZE) buf[*pos] = *str;
+        (*pos)++;
+        str++;
+    }
+}
+
+static void udp_send_info2(struct sockaddr_in * src_addr, struct sockaddr_in * dst_addr) {
+    char str_port[32];
+    char buf[PKT_SIZE];
+    int i = 0;
+
+    buf[i++] = 'T';
+    buf[i++] = 'C';
+    buf[i++] = 'F';
+    buf[i++] = '1';
+    buf[i++] = UDP_ACK_INFO;
+    buf[i++] = 0;
+    buf[i++] = 0;
+    buf[i++] = 0;
+    snprintf(str_port, sizeof(str_port), "%d", ip_port);
+    app_str(buf, &i, "ID=");
+    app_str(buf, &i, "TCP:");
+    app_str(buf, &i, inet_ntoa(src_addr->sin_addr));
+    app_str(buf, &i, ":");
+    app_str(buf, &i, str_port);
+    app_char(buf, &i, 0);
+    app_str(buf, &i, "Name=");
+    app_str(buf, &i, "TCF Agent");
+    app_char(buf, &i, 0);
+    app_str(buf, &i, "OSName=");
+    app_str(buf, &i, get_os_name());
+    app_char(buf, &i, 0);
+    app_str(buf, &i, "TransportName=TCP");
+    app_char(buf, &i, 0);
+    app_str(buf, &i, "Host=");
+    app_str(buf, &i, inet_ntoa(src_addr->sin_addr));
+    app_char(buf, &i, 0);
+    app_str(buf, &i, "Port=");
+    app_str(buf, &i, str_port);
+    app_char(buf, &i, 0);
+    if (sendto(udp_server_socket, buf, i, 0, (struct sockaddr *)dst_addr, sizeof(*dst_addr)) < 0) {
+        trace(LOG_ALWAYS, "Can't send UDP packet to %s: %s",
+                inet_ntoa(dst_addr->sin_addr), errno_to_str(errno));
+    }
+}
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+static void udp_send_info(struct sockaddr_in * addr) {
+    /* If addr == NULL - broadcast */
+#ifdef WIN32
+    int i;
+    MIB_IPADDRTABLE * info = (MIB_IPADDRTABLE *)loc_alloc(sizeof(MIB_IPADDRTABLE));
+    ULONG out_buf_len = sizeof(MIB_IPADDRTABLE);
+    DWORD ret_val = GetIpAddrTable(info, &out_buf_len, 0);
+    if (ret_val == ERROR_INSUFFICIENT_BUFFER) {
+        loc_free(info);
+        info = (MIB_IPADDRTABLE *)loc_alloc(out_buf_len);
+        ret_val = GetIpAddrTable(info, &out_buf_len, 0);
+    }
+    if (ret_val != NO_ERROR) {
+        trace(LOG_ALWAYS, "GetIpAddrTable() error: %d\n", ret_val);
+        loc_free(info);
+        return;
+    }
+    for (i = 0; i < (int)info->dwNumEntries; i++) {
+        unsigned src_net_addr = info->table[i].dwAddr;
+        unsigned src_net_mask = info->table[i].dwMask;
+        struct sockaddr_in src_addr;
+        if (src_net_addr == 0) continue;
+        memset(&src_addr, 0, sizeof src_addr);
+        src_addr.sin_family = AF_INET;
+        src_addr.sin_port = htons((short)ip_port);
+        src_addr.sin_addr.s_addr = src_net_addr;
+        if (addr == NULL) {
+            struct sockaddr_in dst_addr;
+            memset(&dst_addr, 0, sizeof dst_addr);
+            dst_addr.sin_family = PF_INET;
+            dst_addr.sin_port = htons((short)ip_port);
+            dst_addr.sin_addr.s_addr = src_net_addr | ~src_net_mask;
+            udp_send_info2(&src_addr, &dst_addr);
+        }
+        else if ((src_net_addr & src_net_mask) == (addr->sin_addr.s_addr & src_net_mask)) {
+            udp_send_info2(&src_addr, addr);
+        }
+    }
+    loc_free(info);
+#else
+    char if_bbf[0x2000]; 
+    struct ifconf ifc;
+    char * cp;
+
+    memset(&ifc, 0, sizeof ifc); 
+    ifc.ifc_len = sizeof if_bbf; 
+    ifc.ifc_buf = if_bbf; 
+    if (ioctl(udp_server_socket, SIOCGIFCONF, &ifc) < 0) { 
+        trace(LOG_ALWAYS, "error: ioctl(SIOCGIFCONF) returned %d: %s", errno, errno_to_str(errno));
+        return; 
+    } 
+    cp = (char *)ifc.ifc_req;
+    while (cp < (char *)ifc.ifc_req + ifc.ifc_len) {
+        struct ifreq * ifreq_addr = (struct ifreq *)cp;
+        struct ifreq ifreq_mask = *ifreq_addr;
+        unsigned src_net_addr, src_net_mask;
+        cp += sizeof(ifreq_addr->ifr_name);
+        cp += MAX(SA_LEN(&ifreq_addr->ifr_addr), sizeof(ifreq_addr->ifr_addr));
+        if (ioctl(udp_server_socket, SIOCGIFNETMASK, &ifreq_mask) < 0) { 
+            trace(LOG_ALWAYS, "error: ioctl(SIOCGIFNETMASK) returned %d: %s", errno, errno_to_str(errno));
+            continue; 
+        }
+        src_net_addr = ((struct sockaddr_in *)&ifreq_addr->ifr_addr)->sin_addr.s_addr;
+        src_net_mask = ((struct sockaddr_in *)&ifreq_mask.ifr_netmask)->sin_addr.s_addr;
+        if (addr == NULL) {
+            struct sockaddr_in dst_addr;
+            memset(&dst_addr, 0, sizeof dst_addr);
+            dst_addr.sin_family = AF_INET;
+            dst_addr.sin_port = htons((short)ip_port);
+            dst_addr.sin_addr.s_addr = src_net_addr | ~src_net_mask;
+            udp_send_info2((struct sockaddr_in *)&ifreq_addr->ifr_addr, &dst_addr);
+        }
+        else if ((src_net_addr & src_net_mask) == (addr->sin_addr.s_addr & src_net_mask)) {
+            udp_send_info2((struct sockaddr_in *)&ifreq_addr->ifr_addr, addr);
+        }
+    }
+#endif
+}
+
+static void * udp_server_socket_handler(void * x) {
+    char buf[PKT_SIZE];
+    struct sockaddr_in addr;
+
+    memset(&addr, 0, sizeof addr);
+
+    udp_send_info(NULL);
+    for (;;) {
+        int addr_len = sizeof(addr);
+        int rd = recvfrom(udp_server_socket, buf, PKT_SIZE, 0,
+            (struct sockaddr *)&addr, &addr_len);
+        if (rd < 0) {
+            trace(LOG_ALWAYS, "UDP socket receive failed: %s", errno_to_str(errno));
+            continue;
+        }
+        if (rd == 0) continue;
+        if (buf[0] != 'T' || buf[1] != 'C' || buf[2] != 'F' || buf[3] != '1') {
+            trace(LOG_ALWAYS, "Received malformed UDP packet");
+            continue;
+        }
+        if (buf[4] == UDP_REQ_INFO) {
+            udp_send_info(&addr);
+        }
+    }
+    return NULL;
+}
+
+void channels_suspend(void) {
+    assert(is_dispatch_thread());
+    trace(LOG_PROTOCOL, "All channels suspended");
+    suspended = 1;
+}
+
+int are_channels_suspended(void) {
+    assert(is_dispatch_thread());
+    return suspended;
+}
+
+void channels_resume(void) {
+    LINK * l = channels.next;
+    assert(is_dispatch_thread());
+    assert(suspended);
+    trace(LOG_PROTOCOL, "All channels resumed");
+    suspended = 0;
+    while (l != &channels) {
+        Channel * c = link2channel(l);
+        pthread_mutex_lock(&c->mutex);
+        if (c->message_count > 0 && !c->event_posted) {
+            post_event(handle_channel_msg, c);
+            c->event_posted = 1;
+        }
+        pthread_mutex_unlock(&c->mutex);
+        l = l->next;
+    }
+}
+
+int channels_get_message_count(void) {
+    int cnt = 0;
+    LINK * l = channels.next;
+    assert(is_dispatch_thread());
+    while (l != &channels) {
+        Channel * c = link2channel(l);
+        pthread_mutex_lock(&c->mutex);
+        cnt += c->message_count;
+        pthread_mutex_unlock(&c->mutex);
+        l = l->next;
+    }
+    return cnt;
+}
+
+void add_channel_close_listener(ChannelCloseListener listener) {
+    assert(close_listeners_cnt < sizeof(close_listeners) / sizeof(ChannelCloseListener));
+    close_listeners[close_listeners_cnt++] = listener;
+}
+
+void ini_channel_manager(int port) {
+    const int i = 1;
+    struct sockaddr_in sockaddr;
+
+    add_event_handler("Locator", "Hello", event_locator_hello);
+
+    list_init(&channels);
+    ip_port = port;
+    memset(&sockaddr, 0, sizeof sockaddr);
+    sockaddr.sin_family = PF_INET;
+    sockaddr.sin_port = htons((short)port);
+    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    tcp_server_socket = socket(PF_INET, SOCK_STREAM, 0);
+    if (tcp_server_socket < 0) {
+        perror("Can't create a socket");
+        exit(1);
+    }
+    /* Allow rapid reuse of this port. */
+    if (setsockopt(tcp_server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) < 0) {
+        perror("Can't set options on a socket");
+        exit(1);
+    }
+    if (bind(tcp_server_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
+        perror("Can't bind server TCP socket address");
+        exit(1);
+    }
+    if (listen(tcp_server_socket, 16)) {
+        perror("Can't listen on server socket");
+        exit(1);
+    }
+    if (pthread_create(&tcp_server_thread, &pthread_create_attr, tcp_server_socket_handler, 0) != 0) {
+        perror("Can't create socket listener thread");
+        exit(1);
+    }
+
+    udp_server_socket = socket(PF_INET, SOCK_DGRAM, 0);
+    if (udp_server_socket < 0) {
+        perror("Can't create a socket");
+        exit(1);
+    }
+    if (setsockopt(udp_server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) < 0) {
+        perror("Can't set SO_REUSEADDR option on a socket");
+        exit(1);
+    }
+    if (setsockopt(udp_server_socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) {
+        perror("Can't set SO_BROADCAST option on a socket");
+        exit(1);
+    }
+    if (bind(udp_server_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
+        perror("Can't bind server UDP socket address");
+        exit(1);
+    }
+    if (pthread_create(&udp_server_thread, &pthread_create_attr, udp_server_socket_handler, 0) != 0) {
+        perror("Can't create a thread");
+        exit(1);
+    }
+
+#ifndef WIN32
+    signal(SIGPIPE, SIG_IGN);
+#endif
+}
diff --git a/channel.h b/channel.h
new file mode 100644
index 0000000..20cf01a
--- /dev/null
+++ b/channel.h
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Implements input and output stream over TCP/IP transport and UDP based auto discovery.
+ */
+
+#ifndef D_channel
+#define D_channel
+
+#include "streams.h"
+
+extern OutputStream broadcast_stream;
+
+/*
+ * Temporary suspend handling of incoming messages on all channels
+ */
+extern void channels_suspend(void);
+
+/*
+ * Returns 1 if handling of incoming messages is suspended.
+ */
+extern int are_channels_suspended(void);
+
+/*
+ * Resume handling of messages on all channels.
+ */
+extern void channels_resume(void);
+ 
+/*
+ * Return number of pending input messages on all channels.
+ */
+extern int channels_get_message_count(void);
+
+/*
+ * Lock OutputStream to prevent it from being deleted.
+ * A stream must be locked to keep a referense to it across event dispatch cycles.
+ */
+extern void stream_lock(OutputStream * out);
+extern void stream_unlock(OutputStream * out);
+
+/*
+ * Check if stream is closed. Onlu make sense when the stream is locked.
+ * Unlocked stream is deleted when closed.
+ */
+extern int is_stream_closed(OutputStream * out);
+
+/*
+ * Register channel close callback.
+ * Service implementation can use the callback to deallocate resources
+ * after a client disconnects.
+ */
+typedef void (*ChannelCloseListener)(InputStream *, OutputStream *);
+extern void add_channel_close_listener(ChannelCloseListener listener);
+ 
+/*
+ * Initialize channel manager.
+ * 'port' - listenig socket port.
+ */
+extern void ini_channel_manager(int port);
+
+#endif
diff --git a/cmdline.c b/cmdline.c
new file mode 100644
index 0000000..1d47d27
--- /dev/null
+++ b/cmdline.c
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Command line interpreter.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "mdep.h"
+#include "context.h"
+#include "events.h"
+#include "myalloc.h"
+
+static pthread_t interactive_thread;
+
+static void cmd_list_contexts(char *s) {
+    LINK * qp;
+    for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+        Context * ctx = ctxl2ctxp(qp);
+        printf("ctx %#x pid %d state %s\n", ctx, ctx->pid, context_state_name(ctx));
+    }
+}
+
+static void cmd_exit(char *s) {
+    exit(0);
+}
+
+static void event_cmd_line(void * arg) {
+    char * s = (char *)arg;
+    int len;
+    struct {
+        char *cmd;
+        void (*hnd)(char *);
+    } cmds[] = {
+        { "list-contexts",      cmd_list_contexts },
+        { "exit",               cmd_exit },
+        { 0 }
+    }, *cp;
+
+    while (*s && isspace(*s)) s++;
+    for (cp = cmds; cp->cmd != 0; cp++) {
+        len = strlen(cp->cmd);
+        if (strncmp(s, cp->cmd, len) == 0 && (s[len] == 0 || isspace(s[len]))) {
+            s += len;
+            while (*s && isspace(*s)) s++;
+            cp->hnd(s);
+            break;
+        }
+    }
+    if (cp->cmd == 0) {
+        fprintf(stderr, "unknown command: %s\n", s);
+    }
+    loc_free(arg);
+}
+
+static void * interactive_handler(void *x) {
+    char buf[1000];
+
+    while (fgets(buf, sizeof(buf), stdin) != NULL) {
+        char * s = (char *)loc_alloc(strlen(buf) + 1);
+        strcpy(s, buf);
+        post_event(event_cmd_line, s);
+    }
+    return NULL;
+}
+
+void ini_cmdline_handler(void) {
+    /* Create thread to read cmd line */
+    if (pthread_create(&interactive_thread, &pthread_create_attr, interactive_handler, 0) != 0) {
+        perror("pthread_create");
+        exit(1);
+    }
+}
+
diff --git a/cmdline.h b/cmdline.h
new file mode 100644
index 0000000..63392dd
--- /dev/null
+++ b/cmdline.h
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Command line interpreter.
+ */
+
+#ifndef D_cmdline
+#define D_cmdline
+
+extern void ini_cmdline_handler(void);
+
+#endif
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..e1660fb
--- /dev/null
+++ b/config.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This file contains "define" statements that control agent configuration.
+ * SERVICE_* definitions control which service implementations are included into the agent.
+ */
+
+#if defined(WIN32)
+#  define TARGET_WINDOWS    1
+#  define TARGET_VXWORKS    0
+#  define TARGET_LINUX      0
+#elif defined(_WRS_KERNEL)
+#  define TARGET_WINDOWS    0
+#  define TARGET_VXWORKS    1
+#  define TARGET_LINUX      0
+#else
+#  define TARGET_WINDOWS    0
+#  define TARGET_VXWORKS    0
+#  define TARGET_LINUX      1
+#endif
+
+#define SERVICE_RunControl      TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_Breakpoints     TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_Memory          TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_Registers       TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_StackTrace      TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_Symbols         TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_LineNumbers     TARGET_LINUX
+#define SERVICE_Processes       TARGET_LINUX || TARGET_VXWORKS
+#define SERVICE_FileSystem      TARGET_LINUX || TARGET_VXWORKS || TARGET_WINDOWS
+#define SERVICE_SysMonitor      TARGET_LINUX
+
+
+
diff --git a/context.c b/context.c
new file mode 100644
index 0000000..affdfde
--- /dev/null
+++ b/context.c
@@ -0,0 +1,1159 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module handles process/thread OS contexts and their state machine.
+ */
+
+#if defined(_WRS_KERNEL)
+#  include <vxWorks.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include "context.h"
+#include "events.h"
+#include "errors.h"
+#include "trace.h"
+#include "myalloc.h"
+
+#define CONTEXT_PID_ROOT_SIZE 1024
+#define CONTEXT_PID_HASH(PID) ((PID) % CONTEXT_PID_ROOT_SIZE)
+static LINK context_pid_root[CONTEXT_PID_ROOT_SIZE];
+static ContextEventListener * event_listeners = NULL;
+
+LINK context_root = { NULL, NULL };
+
+#define CASE(var) case var: return ""#var;
+char * signal_name(int signal) {
+#ifndef WIN32
+    switch (signal) {
+    CASE(SIGHUP)
+    CASE(SIGINT)
+    CASE(SIGQUIT)
+    CASE(SIGILL)
+    CASE(SIGTRAP)
+    CASE(SIGABRT)
+    CASE(SIGBUS)
+    CASE(SIGFPE)
+    CASE(SIGKILL)
+    CASE(SIGUSR1)
+    CASE(SIGSEGV)
+    CASE(SIGUSR2)
+    CASE(SIGPIPE)
+    CASE(SIGALRM)
+    CASE(SIGTERM)
+#ifndef _WRS_KERNEL
+    CASE(SIGSTKFLT)
+#endif
+    CASE(SIGCHLD)
+    CASE(SIGCONT)
+    CASE(SIGSTOP)
+    CASE(SIGTSTP)
+    CASE(SIGTTIN)
+    CASE(SIGTTOU)
+    CASE(SIGURG)
+    CASE(SIGXCPU)
+    CASE(SIGXFSZ)
+    CASE(SIGVTALRM)
+    CASE(SIGPROF)
+#ifndef _WRS_KERNEL
+    CASE(SIGWINCH)
+    CASE(SIGIO)
+    CASE(SIGPWR)
+#endif
+    CASE(SIGSYS)
+    }
+#endif
+    return NULL;
+}
+#undef CASE
+
+Context * context_find_from_pid(pid_t pid) {
+    LINK * qhp = &context_pid_root[CONTEXT_PID_HASH(pid)];
+    LINK * qp;
+
+    assert(is_dispatch_thread());
+    for (qp = qhp->next; qp != qhp; qp = qp->next) {
+        Context * ctx = pidl2ctxp(qp);
+        if (ctx->pid == pid && !ctx->exited) return ctx;
+    }
+    return NULL;
+}
+
+static Context * create_context(pid_t pid) {
+    LINK * qhp = &context_pid_root[CONTEXT_PID_HASH(pid)];
+    Context * ctx = (Context *)loc_alloc_zero(sizeof(Context));
+
+    assert(context_find_from_pid(pid) == NULL);
+    ctx->pid = pid;
+    ctx->ref_count = 1;
+    list_init(&ctx->children);
+    list_add_first(&ctx->ctxl, &context_root);
+    list_add_first(&ctx->pidl, qhp);
+    return ctx;
+}
+
+char * pid2id(pid_t pid, pid_t parent) {
+    static char s[64];
+    char * p = s + sizeof(s);
+    unsigned long n = (long)pid;
+    *(--p) = 0;
+    do {
+        *(--p) = (char)(n % 10 + '0');
+        n = n / 10;
+    }
+    while (n != 0);
+    if (parent != 0) {
+        n = (long)parent;
+        *(--p) = '.';
+        do {
+            *(--p) = (char)(n % 10 + '0');
+            n = n / 10;
+        }
+        while (n != 0);
+    }
+    *(--p) = 'P';
+    return p;
+}
+
+char * thread_id(Context * ctx) {
+    if (ctx->parent == NULL) return pid2id(ctx->pid, ctx->pid);
+    assert(ctx->parent->parent == NULL);
+    return pid2id(ctx->pid, ctx->parent->pid);
+}
+
+char * container_id(Context * ctx) {
+    if (ctx->parent != NULL) ctx = ctx->parent;
+    assert(ctx->parent == NULL);
+    return pid2id(ctx->pid, 0);
+}
+
+pid_t id2pid(char * id, pid_t * parent) {
+    pid_t pid = 0;
+    if (parent != NULL) *parent = 0;
+    if (id == NULL) return 0;
+    if (id[0] != 'P') return 0;
+    if (id[1] == 0) return 0;
+    pid = (pid_t)strtol(id + 1, &id, 10);
+    if (id[0] == '.') {
+        if (id[1] == 0) return 0;
+        if (parent != NULL) *parent = pid;
+        pid = (pid_t)strtol(id + 1, &id, 10);
+    }
+    if (id[0] != 0) return 0;
+    return pid;
+}
+
+Context * id2ctx(char * id) {
+    pid_t pid = id2pid(id, NULL);
+    if (pid == 0) return NULL;
+    return context_find_from_pid(pid);
+}
+
+void context_lock(Context * ctx) {
+    assert(ctx->ref_count > 0);
+    ctx->ref_count++;
+}
+
+void context_unlock(Context * ctx) {
+    if (--(ctx->ref_count) == 0) {
+        assert(list_is_empty(&ctx->children));
+        assert(ctx->parent == NULL);
+        list_remove(&ctx->ctxl);
+        list_remove(&ctx->pidl);
+        loc_free(ctx);
+    }
+}
+
+char * context_state_name(Context * ctx) {
+    if (ctx->exited) return "exited";
+    if (ctx->intercepted) return "intercepted";
+    if (ctx->stopped) return "stopped";
+    return "running";
+}
+
+static void event_context_created(Context * ctx) {
+    ContextEventListener * listener = event_listeners;
+    while (listener != NULL) {
+        if (listener->context_created != NULL) listener->context_created(ctx);
+        listener = listener->next;
+    }
+}
+
+static void event_context_changed(Context * ctx) {
+    ContextEventListener * listener = event_listeners;
+    while (listener != NULL) {
+        if (listener->context_changed != NULL) listener->context_changed(ctx);
+        listener = listener->next;
+    }
+}
+
+static void event_context_stopped(Context * ctx) {
+    ContextEventListener * listener = event_listeners;
+    while (listener != NULL) {
+        if (listener->context_stopped != NULL) listener->context_stopped(ctx);
+        listener = listener->next;
+    }
+}
+
+static void event_context_started(Context * ctx) {
+    ContextEventListener * listener = event_listeners;
+    while (listener != NULL) {
+        if (listener->context_started != NULL) listener->context_started(ctx);
+        listener = listener->next;
+    }
+}
+
+static void event_context_exited(Context * ctx) {
+    ContextEventListener * listener = event_listeners;
+    while (listener != NULL) {
+        if (listener->context_exited != NULL) listener->context_exited(ctx);
+        listener = listener->next;
+    }
+}
+
+#ifdef WIN32
+
+/*
+ * On Windows context management is not supported yet.
+ */
+
+char * event_name(int event) {
+    return "Unknown";
+}
+
+int context_attach(pid_t pid, Context ** res) {
+    errno = EINVAL;
+    return -1;
+}
+
+int context_stop(Context * ctx) {
+    errno = EINVAL;
+    return -1;
+}
+
+int context_continue(Context * ctx) {
+    errno = EINVAL;
+    return -1;
+}
+
+int context_single_step(Context * ctx) {
+    errno = EINVAL;
+    return -1;
+}
+
+int context_read_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+    errno = EINVAL;
+    return -1;
+}
+
+int context_write_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+    errno = EINVAL;
+    return -1;
+}
+
+static void init(void) {
+}
+
+#elif defined(_WRS_KERNEL)
+
+/* TODO: RTP support */
+
+#include <taskHookLib.h>
+#include <private/vxdbgLibP.h>
+
+#define TRACE_EVENT_STEP        2
+
+#define EVENT_HOOK_IGNORE       1
+#define EVENT_HOOK_BREAKPOINT   2
+#define EVENT_HOOK_STEP_DONE    3
+#define EVENT_HOOK_STOP         4
+#define EVENT_HOOK_TASK_ADD     5
+#define EVENT_HOOK_TASK_DEL     6
+
+struct event_info {
+    int                 event;
+    VXDBG_CTX           current_ctx;    /* context that hit breakpoint */
+    VXDBG_CTX           stopped_ctx;    /* context stopped by the breakpoint */
+    REG_SET             regs;           /* task registers before exception */
+    UINT32              addr;           /* breakpoint addr */
+    int                 bp_info_ok;     /* breakpoint information available */
+    VXDBG_BP_INFO       bp_info;        /* breakpoint information */
+    SEM_ID              delete_signal;
+};
+
+VXDBG_CLNT_ID vxdbg_clnt_id = 0;
+
+#define MAX_EVENTS 64
+static struct event_info events[MAX_EVENTS];
+static int events_inp = 0;
+static int events_out = 0;
+static int events_buf_overflow = 0;
+static spinlockIsr_t events_lock;
+static VX_COUNTING_SEMAPHORE(events_signal_mem);
+static SEM_ID events_signal;
+static pthread_t events_thread;
+static WIND_TCB * main_thread;
+
+char * event_name(int event) {
+    switch (event) {
+    case 0: return "none";
+    case TRACE_EVENT_STEP: return "Single Step"; 
+    }
+    return NULL;
+}
+
+static struct event_info * event_info_alloc(int event) {
+    int nxt;
+    struct event_info * info;
+    SPIN_LOCK_ISR_TAKE(&events_lock);
+    if (events_buf_overflow) {
+        SPIN_LOCK_ISR_GIVE(&events_lock);
+        return NULL;
+    }
+    info = events + events_inp;
+    nxt = (events_inp + 1) % MAX_EVENTS;
+    if (nxt == events_out) {
+        events_buf_overflow = 1;
+        semGive(events_signal);
+        SPIN_LOCK_ISR_GIVE(&events_lock);
+        return NULL;
+    }
+    memset(info, 0, sizeof(struct event_info));
+    info->event = event;
+    events_inp = nxt;
+    return info;
+}
+
+static void event_info_post(struct event_info * info) {
+    assert(info != NULL);
+    semGive(events_signal);
+    SPIN_LOCK_ISR_GIVE(&events_lock);
+}
+
+int context_attach(pid_t pid, Context ** res) {
+    struct event_info * info;
+    Context * ctx = create_context(pid);
+
+    ctx->mem = taskIdSelf();
+    assert(ctx->ref_count == 1);
+    event_context_created(ctx);
+    if (taskIsStopped(pid)) {
+        ctx->pending_intercept = 1;
+        info = event_info_alloc(EVENT_HOOK_STOP);
+        if (info != NULL) {
+            info->stopped_ctx.ctxId = pid;
+            event_info_post(info);
+        }
+    }
+    if (res != NULL) *res = ctx;
+    return 0;
+}
+
+int context_stop(Context * ctx) {
+    struct event_info * info;
+    VXDBG_CTX vxdbg_ctx;
+
+    assert(is_dispatch_thread());
+    assert(!ctx->stopped);
+    assert(!ctx->exited);
+    assert(!ctx->regs_dirty);
+    assert(!ctx->intercepted);
+    if (ctx->pending_intercept) {
+        trace(LOG_CONTEXT, "context: stop ctx %#x pid %d", ctx, ctx->pid);
+    }
+    else {
+        trace(LOG_CONTEXT, "context: temporary stop ctx %#x pid %d", ctx, ctx->pid);
+    }
+    
+    vxdbg_ctx.ctxId = ctx->pid;
+    vxdbg_ctx.ctxType = VXDBG_CTX_TASK;
+    if (vxdbgStop(vxdbg_clnt_id, &vxdbg_ctx) != OK) return -1;
+    assert(taskIsStopped(ctx->pid));
+    
+    info = event_info_alloc(EVENT_HOOK_STOP);
+    if (info != NULL) {
+        info->stopped_ctx.ctxId = ctx->pid;
+        event_info_post(info);
+    }
+    return 0;
+}
+
+static int kill_context(Context * ctx) {
+    ctx->pending_signals &= ~(1 << SIGKILL);
+    if (taskDelete(ctx->pid) != OK) return -1;
+    ctx->stopped = 0;
+    event_context_started(ctx);
+    ctx->exiting = 0;
+    ctx->exited = 1;
+    event_context_exited(ctx);
+    if (ctx->parent != NULL) {
+        list_remove(&ctx->cldl);
+        context_unlock(ctx->parent);
+        ctx->parent = NULL;
+    }
+    context_unlock(ctx);
+    return 0;
+}
+
+int context_continue(Context * ctx) {
+    VXDBG_CTX vxdbg_ctx;
+    
+    assert(is_dispatch_thread());
+    assert(ctx->stopped);
+    assert(!ctx->pending_intercept);
+    assert(!ctx->exited);
+    assert(!ctx->pending_step);
+    trace(LOG_CONTEXT, "context: resume ctx %#x, pid %d", ctx, ctx->pid);
+
+    if (ctx->regs_dirty) {
+        if (taskRegsSet(ctx->pid, &ctx->regs) != OK) return -1;
+        ctx->regs_dirty = 0;
+    }
+    
+    if (ctx->pending_signals & (1 << SIGKILL)) {
+        return kill_context(ctx);
+    }
+
+    vxdbg_ctx.ctxId = ctx->pid;
+    vxdbg_ctx.ctxType = VXDBG_CTX_TASK;
+    if (vxdbgCont(vxdbg_clnt_id, &vxdbg_ctx) != OK) return -1;
+    ctx->stopped = 0;
+    event_context_started(ctx);
+    return 0;
+}
+
+int context_single_step(Context * ctx) {
+    VXDBG_CTX vxdbg_ctx;
+    struct event_info * info;
+    
+    assert(is_dispatch_thread());
+    assert(ctx->stopped);
+    assert(!ctx->pending_intercept);
+    assert(!ctx->pending_step);
+    assert(!ctx->exited);
+    trace(LOG_CONTEXT, "context: single step ctx %#x, pid %d", ctx, ctx->pid);
+
+    if (ctx->regs_dirty) {
+        if (taskRegsSet(ctx->pid, &ctx->regs) != OK) return -1;
+        ctx->regs_dirty = 0;
+    }
+
+    if (ctx->pending_signals & (1 << SIGKILL)) {
+        return kill_context(ctx);
+    }
+
+    vxdbg_ctx.ctxId = ctx->pid;
+    vxdbg_ctx.ctxType = VXDBG_CTX_TASK;
+    if (vxdbgStep(vxdbg_clnt_id, &vxdbg_ctx, NULL, NULL) != OK) return -1;
+    ctx->pending_step = 1;
+    ctx->stopped = 0;
+    event_context_started(ctx);
+    return 0;
+}
+
+int context_read_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+#ifdef  _WRS_PERSISTENT_SW_BP
+    vxdbgMemRead((void *)address, buf, size);
+#else    
+    bcopy((void *)address, buf, size);
+#endif    
+    return 0;
+}
+
+int context_write_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+#ifdef  _WRS_PERSISTENT_SW_BP
+    vxdbgMemWrite((void *)address, buf, size);
+#else
+    bcopy(buf, (void *)address, size);
+#endif    
+    return 0;
+}
+
+static void event_handler(void * arg) {
+    struct event_info * info = (struct event_info *)arg;
+    Context * current_ctx = context_find_from_pid(info->current_ctx.ctxId); 
+    Context * stopped_ctx = context_find_from_pid(info->stopped_ctx.ctxId);
+    
+    switch (info->event) {
+    case EVENT_HOOK_BREAKPOINT:
+        if (stopped_ctx == NULL) break;
+        assert(!stopped_ctx->stopped);
+        assert(!stopped_ctx->regs_dirty);
+        assert(!stopped_ctx->intercepted);
+        stopped_ctx->regs_error = 0;
+        stopped_ctx->regs = info->regs;
+        stopped_ctx->signal = SIGTRAP;
+        assert(get_regs_PC(stopped_ctx->regs) == info->addr);
+        stopped_ctx->event = 0;
+        stopped_ctx->stopped_by_bp = info->bp_info_ok;
+        stopped_ctx->bp_info = info->bp_info;
+        if (current_ctx != NULL) stopped_ctx->bp_pid = current_ctx->pid;
+        stopped_ctx->pending_step = 0;
+        stopped_ctx->stopped = 1;
+        event_context_stopped(stopped_ctx);
+        break;
+    case EVENT_HOOK_STEP_DONE:
+        if (current_ctx == NULL) break;
+        assert(!current_ctx->stopped);
+        assert(!current_ctx->regs_dirty);
+        assert(!current_ctx->intercepted);
+        current_ctx->regs_error = 0;
+        current_ctx->regs = info->regs;
+        current_ctx->signal = SIGTRAP;
+        current_ctx->event = TRACE_EVENT_STEP;
+        current_ctx->pending_step = 0;
+        current_ctx->stopped = 1;
+        event_context_stopped(current_ctx);
+        break;
+    case EVENT_HOOK_STOP:
+        if (stopped_ctx == NULL) break;
+        assert(!stopped_ctx->stopped);
+        stopped_ctx->regs_error = 0;
+        if (taskRegsGet(stopped_ctx->pid, &stopped_ctx->regs) != OK) {
+            stopped_ctx->regs_error = errno;
+            assert(stopped_ctx->regs_error != 0);
+        }
+        stopped_ctx->signal = SIGSTOP;
+        stopped_ctx->event = 0;
+        stopped_ctx->pending_step = 0;
+        stopped_ctx->stopped = 1;
+        event_context_stopped(stopped_ctx);
+        break;
+    case EVENT_HOOK_TASK_ADD:
+        if (current_ctx == NULL) break;
+        assert(stopped_ctx == NULL);
+        stopped_ctx = create_context((pid_t)info->stopped_ctx.ctxId);
+        assert(stopped_ctx->ref_count == 1);
+        stopped_ctx->mem = current_ctx->mem;
+        stopped_ctx->parent = current_ctx->parent != NULL ? current_ctx->parent : current_ctx;
+        stopped_ctx->parent->ref_count++;
+        list_add_first(&stopped_ctx->cldl, &stopped_ctx->parent->children);
+        event_context_created(stopped_ctx);
+        break;
+    case EVENT_HOOK_TASK_DEL:
+        if (stopped_ctx != NULL) {
+            assert(!stopped_ctx->stopped);
+            assert(!stopped_ctx->intercepted);
+            assert(!stopped_ctx->exited);
+            stopped_ctx->pending_step = 0;
+            stopped_ctx->exiting = 0;
+            stopped_ctx->exited = 1;
+            event_context_exited(stopped_ctx);
+            if (stopped_ctx->parent != NULL) {
+                list_remove(&stopped_ctx->cldl);
+                context_unlock(stopped_ctx->parent);
+                stopped_ctx->parent = NULL;
+            }
+            context_unlock(stopped_ctx);
+        }
+        semGive(info->delete_signal);
+        break;
+    default:
+        assert(0);
+        break;
+    }
+    loc_free(info);
+}
+
+static void event_error(void * arg) {
+    trace(LOG_ALWAYS, "Fatal error: VXDBG events buffer overflow");
+    exit(1);
+}
+
+static void * event_thread_func(void * arg) {
+    struct event_info * info;
+    
+    taskPrioritySet(0, VX_TASK_PRIORITY_MIN);
+    for (;;) {
+        semTake(events_signal, WAIT_FOREVER);
+        info = (struct event_info *)loc_alloc(sizeof(struct event_info));
+        
+        SPIN_LOCK_ISR_TAKE(&events_lock);
+        if (events_buf_overflow && events_inp == events_out) {
+            SPIN_LOCK_ISR_GIVE(&events_lock);
+            break;
+        }
+        assert(events_inp != events_out);
+        *info = events[events_out];
+        events_out = (events_out + 1) % MAX_EVENTS;
+        SPIN_LOCK_ISR_GIVE(&events_lock);
+        
+        if (info->event != EVENT_HOOK_IGNORE) {
+            post_event(event_handler, info);
+        }
+    }
+    post_event(event_error, NULL);
+}
+
+static void vxdbg_event_hook(
+        VXDBG_CTX *     current_ctx,    /* context that hit breakpoint */
+        VXDBG_CTX *     stopped_ctx,    /* context stopped by the breakpoint */
+        REG_SET *       regs,           /* task registers before exception */
+        UINT32	        addr,           /* breakpoint addr */
+        VXDBG_BP_INFO *	bp_info) {      /* breakpoint information */
+    
+    struct event_info * info = event_info_alloc(EVENT_HOOK_BREAKPOINT);
+    if (info != NULL) {
+        if (stopped_ctx == NULL) info->event = EVENT_HOOK_STEP_DONE;
+        if (current_ctx != NULL) info->current_ctx = *current_ctx;
+        if (stopped_ctx != NULL) info->stopped_ctx = *stopped_ctx;
+        if (regs != NULL) info->regs = *regs;
+        info->addr = addr;
+        if (bp_info != NULL) {
+            info->bp_info_ok = 1;
+            info->bp_info = *bp_info;
+        }
+        event_info_post(info);
+    }
+}
+
+static void task_create_hook(WIND_TCB * tcb) {
+    struct event_info * info = event_info_alloc(EVENT_HOOK_TASK_ADD);
+    if (info != NULL) {
+        info->current_ctx.ctxId = taskIdSelf();
+        info->stopped_ctx.ctxId = (UINT32)tcb;
+        event_info_post(info);
+    }
+}
+
+static void task_delete_hook(WIND_TCB * tcb) {
+    if (tcb != main_thread && taskIdCurrent != main_thread) {
+        struct event_info * info = event_info_alloc(EVENT_HOOK_TASK_DEL);
+        if (info != NULL) {
+            VX_COUNTING_SEMAPHORE(signal_mem);
+            SEM_ID signal = info->delete_signal = semCInitialize(signal_mem, SEM_Q_FIFO, 0);
+            info->current_ctx.ctxId = taskIdSelf();
+            info->stopped_ctx.ctxId = (UINT32)tcb;
+            event_info_post(info);
+            semTake(signal, WAIT_FOREVER);
+            semTerminate(signal);
+        }
+    }
+}
+
+static void init(void) {
+    SPIN_LOCK_ISR_INIT(&events_lock, 0);
+    main_thread = taskIdCurrent;
+    if ((events_signal = semCInitialize(events_signal_mem, SEM_Q_FIFO, 0)) == NULL) {
+        perror("semCInitialize");
+        exit(1);
+    }
+    vxdbg_clnt_id = vxdbgClntRegister(EVT_BP);
+    if (vxdbg_clnt_id == NULL) {
+        perror("vxdbgClntRegister");
+        exit(1);
+    }
+    taskCreateHookAdd((FUNCPTR)task_create_hook);
+    taskDeleteHookAdd((FUNCPTR)task_delete_hook);
+    vxdbgHookAdd(vxdbg_clnt_id, EVT_BP, vxdbg_event_hook);
+    vxdbgHookAdd(vxdbg_clnt_id, EVT_TRACE, vxdbg_event_hook);	
+    if (pthread_create(&events_thread, &pthread_create_attr, event_thread_func, NULL) != 0) {
+        perror("pthread_create");
+        exit(1);
+    }
+}
+
+#else
+
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sched.h>
+
+#define PTRACE_SETOPTIONS       0x4200
+#define PTRACE_GETEVENTMSG      0x4201
+#define PTRACE_GETSIGINFO       0x4202
+#define PTRACE_SETSIGINFO       0x4203
+
+#define PTRACE_O_TRACESYSGOOD   0x00000001
+#define PTRACE_O_TRACEFORK      0x00000002
+#define PTRACE_O_TRACEVFORK     0x00000004
+#define PTRACE_O_TRACECLONE     0x00000008
+#define PTRACE_O_TRACEEXEC      0x00000010
+#define PTRACE_O_TRACEVFORKDONE 0x00000020
+#define PTRACE_O_TRACEEXIT      0x00000040
+
+#define PTRACE_EVENT_FORK       1
+#define PTRACE_EVENT_VFORK      2
+#define PTRACE_EVENT_CLONE      3
+#define PTRACE_EVENT_EXEC       4
+#define PTRACE_EVENT_VFORK_DONE 5
+#define PTRACE_EVENT_EXIT       6
+
+#define USE_ESRCH_WORKAROUND    1
+
+#define WORD_SIZE   4
+
+#define PTRACE_FLAGS ( \
+    PTRACE_O_TRACEFORK | \
+    PTRACE_O_TRACEVFORK | \
+    PTRACE_O_TRACECLONE | \
+    PTRACE_O_TRACEEXEC | \
+    PTRACE_O_TRACEVFORKDONE | \
+    PTRACE_O_TRACEEXIT)
+
+struct pid_exit_info {
+    pid_t       pid;
+    int         value;
+};
+
+struct pid_stop_info {
+    pid_t       pid;
+    int         signal;
+    int         event;
+};
+
+static pthread_t wpid_thread;
+static pid_t my_pid = 0;
+static pthread_mutex_t waitpid_lock;
+static pthread_cond_t waitpid_cond;
+static int attach_flag = 0;
+
+char * event_name(int event) {
+    switch (event) {
+    case 0: return "none";
+    case PTRACE_EVENT_FORK: return "fork";  
+    case PTRACE_EVENT_VFORK: return "vfork";  
+    case PTRACE_EVENT_CLONE: return "clone";  
+    case PTRACE_EVENT_EXEC: return "exec";  
+    case PTRACE_EVENT_VFORK_DONE: return "vfork-done";  
+    case PTRACE_EVENT_EXIT: return "exit";  
+    default:
+        trace(LOG_ALWAYS, "event_name() called with unexpected event code %d", event);
+        return "unknown";
+    }
+}
+
+int context_attach(pid_t pid, Context ** res) {
+    Context * ctx = NULL;
+    pthread_mutex_lock(&waitpid_lock);
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) {
+        int err = errno;
+        trace(LOG_ALWAYS, "error: ptrace(PTRACE_ATTACH) failed: pid %d, error %d %s",
+            pid, err, errno_to_str(err));
+        pthread_mutex_unlock(&waitpid_lock);
+        errno = err;
+        return -1;
+    }
+    ctx = create_context(pid);
+    /* TODO: context_attach works only for main task in a process */
+    ctx->mem = pid;
+    assert(ctx->ref_count == 1);
+    event_context_created(ctx);
+    attach_flag = 1;
+    pthread_cond_signal(&waitpid_cond);
+    pthread_mutex_unlock(&waitpid_lock);
+    if (res != NULL) *res = ctx;
+    return 0;
+}
+
+int context_stop(Context * ctx) {
+    assert(is_dispatch_thread());
+    assert(!ctx->exited);
+    assert(!ctx->stopped);
+    assert(!ctx->regs_dirty);
+    assert(!ctx->intercepted);
+    if (ctx->pending_intercept) {
+        trace(LOG_CONTEXT, "context: suspending ctx %#x pid %d", ctx, ctx->pid);
+    }
+    else {
+        trace(LOG_CONTEXT, "context: temporary suspending ctx %#x pid %d", ctx, ctx->pid);
+    }
+    if (tkill(ctx->pid, SIGSTOP) < 0) {
+        int err = errno;
+        trace(LOG_ALWAYS, "error: tkill(SIGSTOP) failed: ctx %#x, pid %d, error %d %s",
+            ctx, ctx->pid, err, errno_to_str(err));
+        errno = err;
+        return -1;
+    }
+    return 0;
+}
+
+int context_continue(Context * ctx) {
+    int signal = 0;
+    if (ctx->pending_signals != 0) {
+        while ((ctx->pending_signals & (1 << signal)) == 0) signal++;
+    }
+    assert(signal != SIGSTOP);
+    assert(signal != SIGTRAP);
+    assert(is_dispatch_thread());
+    assert(ctx->stopped);
+    assert(!ctx->pending_intercept);
+    assert(!ctx->pending_step);
+    assert(!ctx->exited);
+    trace(LOG_CONTEXT, "context: resuming ctx %#x, pid %d, with signal %d", ctx, ctx->pid, signal);
+#ifdef __i386__
+    /* Bug in ptrace: trap flag is not cleared after single step */
+    if (ctx->regs.eflags & 0x100) {
+        ctx->regs.eflags &= ~0x100;
+        ctx->regs_dirty = 1;
+    }
+#endif
+    if (ctx->regs_dirty) {
+        if (ptrace(PTRACE_SETREGS, ctx->pid, 0, &ctx->regs) < 0) {
+            int err = errno;
+#if USE_ESRCH_WORKAROUND
+            if (err == ESRCH) {
+                ctx->regs_dirty = 0;
+                ctx->stopped = 0;
+                event_context_started(ctx);
+                return 0;
+            }
+#endif
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#x, pid %d, error %d %s",
+                ctx, ctx->pid, err, errno_to_str(err));
+            errno = err;
+            return -1;
+        }
+        ctx->regs_dirty = 0;
+    }
+    if (ptrace(PTRACE_CONT, ctx->pid, 0, signal) < 0) {
+        int err = errno;
+#if USE_ESRCH_WORKAROUND
+        if (err == ESRCH) {
+            ctx->stopped = 0;
+            event_context_started(ctx);
+            return 0;
+        }
+#endif
+        trace(LOG_ALWAYS, "error: ptrace(PTRACE_CONT, ...) failed: ctx %#x, pid %d, error %d %s",
+            ctx, ctx->pid, err, errno_to_str(err));
+        errno = err;
+        return -1;
+    }
+    ctx->pending_signals &= ~(1 << signal);
+    ctx->stopped = 0;
+    event_context_started(ctx);
+    return 0;
+}
+
+int context_single_step(Context * ctx) {
+    assert(is_dispatch_thread());
+    assert(ctx->stopped);
+    assert(!ctx->pending_intercept);
+    assert(!ctx->pending_step);
+    assert(!ctx->exited);
+    trace(LOG_CONTEXT, "context: single step ctx %#x, pid %d", ctx, ctx->pid);
+    if (ctx->regs_dirty) {
+        if (ptrace(PTRACE_SETREGS, ctx->pid, 0, &ctx->regs) < 0) {
+            int err = errno;
+#if USE_ESRCH_WORKAROUND
+            if (err == ESRCH) {
+                ctx->regs_dirty = 0;
+                ctx->pending_step = 1;
+                ctx->stopped = 0;
+                event_context_started(ctx);
+                return 0;
+            }
+#endif
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#x, pid %d, error %d %s",
+                ctx, ctx->pid, err, errno_to_str(err));
+            errno = err;
+            return -1;
+        }
+        ctx->regs_dirty = 0;
+    }
+    if (ptrace(PTRACE_SINGLESTEP, ctx->pid, 0, 0) < 0) {
+        int err = errno;
+#if USE_ESRCH_WORKAROUND
+        if (err == ESRCH) {
+            ctx->stopped = 0;
+            ctx->pending_step = 1;
+            event_context_started(ctx);
+            return 0;
+        }
+#endif
+        trace(LOG_ALWAYS, "error: ptrace(PTRACE_SINGLESTEP, ...) failed: ctx %#x, pid %d, error %d %s",
+            ctx, ctx->pid, err, errno_to_str(err));
+        errno = err;
+        return -1;
+    }
+    ctx->pending_step = 1;
+    ctx->stopped = 0;
+    event_context_started(ctx);
+    return 0;
+}
+
+int context_write_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+    unsigned long word_addr;
+    assert(is_dispatch_thread());
+    assert(!ctx->exited);
+    assert(ctx->stopped);
+    trace(LOG_CONTEXT, "context: write memory ctx %#x, pid %d, address 0x%08x, size %d", ctx, ctx->pid, address, size);
+    for (word_addr = address & ~3ul; word_addr < address + size; word_addr += WORD_SIZE) {
+        int i;
+        unsigned int word = 0;
+        if (word_addr < address || word_addr + WORD_SIZE > address + size) {
+            errno = 0;
+            word = ptrace(PTRACE_PEEKDATA, ctx->pid, word_addr, 0);
+            if (errno != 0) {
+                int err = errno;
+                trace(LOG_ALWAYS, "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#x, pid %d, error %d %s",
+                    ctx, ctx->pid, err, errno_to_str(err));
+                errno = err;
+                return -1;
+            }
+        }
+        for (i = 0; i < WORD_SIZE; i++) {
+            if (word_addr + i >= address && word_addr + i < address + size) {
+                // TODO: big endian support
+                ((unsigned char *)&word)[i] = ((unsigned char *)buf)[word_addr + i - address];
+            }
+        }
+        if (ptrace(PTRACE_POKEDATA, ctx->pid, word_addr, word) < 0) {
+            int err = errno;
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_POKEDATA, ...) failed: ctx %#x, pid %d, error %d %s",
+                ctx, ctx->pid, err, errno_to_str(err));
+            errno = err;
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int context_read_mem(Context * ctx, unsigned long address, void * buf, size_t size) {
+    unsigned long word_addr;
+    assert(is_dispatch_thread());
+    assert(!ctx->exited);
+    assert(ctx->stopped);
+    trace(LOG_CONTEXT, "context: read memory ctx %#x, pid %d, address 0x%08x, size %d", ctx, ctx->pid, address, size);
+    for (word_addr = address & ~3ul; word_addr < address + size; word_addr += WORD_SIZE) {
+        int i;
+        unsigned int word = 0;
+        errno = 0;
+        word = ptrace(PTRACE_PEEKDATA, ctx->pid, word_addr, 0);
+        if (errno != 0) {
+            int err = errno;
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#x, pid %d, error %d %s",
+                ctx, ctx->pid, err, errno_to_str(err));
+            errno = err;
+            return -1;
+        }
+        for (i = 0; i < WORD_SIZE; i++) {
+            if (word_addr + i >= address && word_addr + i < address + size) {
+                // TODO: big endian support
+                ((unsigned char *)buf)[word_addr + i - address] = ((unsigned char *)&word)[i];
+            }
+        }
+    }
+    return 0;
+}
+
+static void event_pid_exited(void *arg) {
+    struct pid_exit_info *eap = arg;
+    Context * ctx;
+
+    ctx = context_find_from_pid(eap->pid);
+    if (ctx == NULL) {
+        trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d", eap->pid, eap->value);
+    }
+    else {
+        trace(LOG_EVENTS, "event: ctx %#x, pid %d, exit status %d", ctx, eap->pid, eap->value);
+        assert(!ctx->stopped);
+        assert(!ctx->intercepted);
+        assert(!ctx->exited);
+        /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing
+         * between PTRACE_CONT and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0.
+         */
+        ctx->exiting = 0;
+        ctx->exited = 1;
+        event_context_exited(ctx);
+        if (ctx->parent != NULL) {
+            list_remove(&ctx->cldl);
+            context_unlock(ctx->parent);
+            ctx->parent = NULL;
+        }
+        context_unlock(ctx);
+    }
+    loc_free(eap);
+}
+
+static void event_pid_stopped(void * arg) {
+    unsigned long msg = 0;
+    Context * ctx = NULL;
+    Context * ctx2 = NULL;
+    struct pid_stop_info * eap = arg;
+
+    trace(LOG_EVENTS, "event: pid %d stopped, signal %d, event %s",
+        eap->pid, eap->signal, event_name(eap->event));
+
+    ctx = context_find_from_pid(eap->pid);
+    if (ctx == NULL) {
+        trace(LOG_ALWAYS, "error: invalid event: pid %d is not traced", eap->pid);
+        return;
+    }
+    assert(!ctx->exited);
+    assert(!ctx->stopped || eap->event == 0 || eap->event == PTRACE_EVENT_EXIT);
+    if (ctx->trace_flags != PTRACE_FLAGS) {
+        if (ptrace(PTRACE_SETOPTIONS, ctx->pid, 0, PTRACE_FLAGS) < 0) {
+            int err = errno;
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETOPTIONS) failed: pid %d, error %d %s",
+                ctx->pid, err, errno_to_str(err));
+        }
+        else {
+            ctx->trace_flags = PTRACE_FLAGS;
+        }
+    }
+
+    switch (eap->event) {
+    case PTRACE_EVENT_FORK:
+    case PTRACE_EVENT_VFORK:
+    case PTRACE_EVENT_CLONE:
+        if (ptrace(PTRACE_GETEVENTMSG, eap->pid, 0, &msg) < 0) {
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETEVENTMSG) failed; pid %d, error %d %s",
+                eap->pid, errno, errno_to_str(errno));
+            break;
+        }
+        assert(msg != 0);
+        ctx2 = create_context(msg);
+        assert(ctx2->parent == NULL);
+        if (eap->event == PTRACE_EVENT_CLONE) {
+            ctx2->mem = ctx->mem;
+            ctx2->parent = ctx->parent != NULL ? ctx->parent : ctx;
+            ctx2->parent->ref_count++;
+            list_add_first(&ctx2->cldl, &ctx2->parent->children);
+        }
+        else {
+            ctx2->mem = ctx2->pid;
+        }
+        assert(ctx2->mem != 0);
+        event_context_created(ctx2);
+        break;
+
+    case PTRACE_EVENT_EXEC:
+        event_context_changed(ctx);
+        break;
+    }
+
+    if (eap->signal != SIGSTOP && eap->signal != SIGTRAP) {
+        ctx->pending_signals |= 1 << eap->signal;
+    }
+
+    if (eap->signal == SIGTRAP && eap->event == PTRACE_EVENT_EXIT) {
+        ctx->exiting = 1;
+        ctx->regs_dirty = 0;
+    }
+
+    if (!ctx->stopped || !ctx->intercepted) {
+        unsigned long pc0 = get_regs_PC(ctx->regs);
+        assert(!ctx->regs_dirty);
+        assert(!ctx->intercepted);
+        ctx->regs_error = 0;
+        if (ptrace(PTRACE_GETREGS, ctx->pid, 0, &ctx->regs) < 0) {
+#if USE_ESRCH_WORKAROUND
+            if (errno == ESRCH) {
+                /* Racing condition: somebody resumed this context while we are handling stop event.
+                 *
+                 * One possible cause: main thread has exited forcing children to exit too.
+                 * I beleive it is a bug in PTRACE implementation - PTRACE should delay exiting of
+                 * a context while it is stopped, but it does not, which causes a nasty racing.
+                 *
+                 * Workaround: Ignore current event, assume context is running.
+                 */
+                loc_free(eap);
+                return;
+            }
+#endif
+            ctx->regs_error = errno;
+            trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETREGS) failed; pid %d, error %d %s",
+                ctx->pid, errno, errno_to_str(errno));
+        }
+
+        trace(LOG_EVENTS, "event: pid %d stopped at PC = %d (0x%08x)",
+            ctx->pid, get_regs_PC(ctx->regs), get_regs_PC(ctx->regs));
+
+        if (eap->signal == SIGSTOP && ctx->pending_step && ctx->regs_error == 0 && pc0 == get_regs_PC(ctx->regs)) {
+            trace(LOG_EVENTS, "event: pid %d, single step failed because of pending SIGSTOP, retrying");
+            ptrace(PTRACE_SINGLESTEP, ctx->pid, 0, 0);
+        }
+        else {
+            ctx->signal = eap->signal;
+            ctx->event = eap->event;
+            ctx->pending_step = 0;
+            ctx->stopped = 1;
+            event_context_stopped(ctx);
+        }
+    }
+
+    loc_free(eap);
+}
+
+static void *wpid_handler(void *x) {
+    pid_t pid;
+    int status;
+    struct timeval timeout;
+
+    for (;;) {
+        attach_flag = 0;
+        if ((pid = waitpid(-1, &status, WUNTRACED | __WALL)) == (pid_t)-1) {
+            if (errno == ECHILD) {
+                pthread_mutex_lock(&waitpid_lock);
+                if (!attach_flag) pthread_cond_wait(&waitpid_cond, &waitpid_lock);
+                pthread_mutex_unlock(&waitpid_lock);
+                continue;
+            }
+            perror("waitpid");
+            exit(1);
+        }
+        trace(LOG_WAITPID, "waitpid: pid %d status %#x", pid, status);
+        if (WIFEXITED(status) || WIFSIGNALED(status)) {
+            struct pid_exit_info *eap;
+
+            eap = loc_alloc(sizeof *eap);
+            eap->pid = pid;
+            eap->value = WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status);
+            post_event(event_pid_exited, eap);
+        }
+        else if (WIFSTOPPED(status)) {
+            struct pid_stop_info *eap;
+
+            eap = loc_alloc(sizeof *eap);
+            eap->pid = pid;
+            eap->signal = WSTOPSIG(status);
+            eap->event = status >> 16;
+            post_event(event_pid_stopped, eap);
+        }
+        else {
+            trace(LOG_ALWAYS, "unexpected status (0x%x) from waitpid (pid %d)", status, pid);
+        }
+    }
+}
+
+static void init(void) {
+    pthread_mutex_init(&waitpid_lock, NULL);
+    pthread_cond_init(&waitpid_cond, NULL);
+    my_pid = getpid();
+    /* Create thread to get process events using waitpid() */
+    if (pthread_create(&wpid_thread, &pthread_create_attr, wpid_handler, NULL) != 0) {
+        perror("pthread_create");
+        exit(1);
+    }
+}
+
+#endif
+
+void add_context_event_listener(ContextEventListener * listener) {
+    listener->next = event_listeners;
+    event_listeners = listener;
+}
+
+void ini_contexts(void) {
+    int i;
+
+    list_init(&context_root);
+    for (i = 0; i < CONTEXT_PID_ROOT_SIZE; i++) {
+        list_init(&context_pid_root[i]);
+    }
+    init();
+}
diff --git a/context.h b/context.h
new file mode 100644
index 0000000..802e9f7
--- /dev/null
+++ b/context.h
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module handles process/thread OS contexts and their state machine.
+ */
+
+#ifndef D_context
+#define D_context
+
+#include <sys/types.h>
+#include "mdep.h"
+#include "link.h"
+
+extern LINK context_root;
+
+#define ctxl2ctxp(A)    ((Context *)((char *)(A) - (int)&((Context *)0)->ctxl))
+#define pidl2ctxp(A)    ((Context *)((char *)(A) - (int)&((Context *)0)->pidl))
+#define cldl2ctxp(A)    ((Context *)((char *)(A) - (int)&((Context *)0)->cldl))
+
+typedef struct Context Context;
+
+struct Context {
+    LINK                ctxl;
+    LINK                pidl;
+    LINK                cldl;
+    LINK                children;
+    Context *           parent;
+    unsigned int        ref_count;          /* reference count, see context_lock() and context_unlock() */
+    pid_t               pid;                /* process or thread identifier */
+    pid_t               mem;                /* context memory space identifier */
+    int                 stopped;            /* OS kernel has stopped this context */
+    int                 stopped_by_bp;      /* stopped by breakpoint */
+    int                 exiting;            /* context is about to exit */
+    int                 exited;             /* context exited */
+    int                 intercepted;        /* context is reported to a host as suspended */
+    int                 pending_step;       /* context is executing single instruction step */
+    int                 pending_intercept;  /* host is waiting for this context to be suspended */
+    int                 pending_safe_event; /* safe events are waiting for this context to be stopped */
+    unsigned long       pending_signals;    /* bitset of signals that were received, but not handled yet */
+    int                 signal;             /* signal that stopped this context */
+    int                 event;              /* tracing event code when signal is SIGTRAP */
+    REG_SET             regs;               /* copy of context registers, updated when context stops */
+    int                 regs_error;         /* if not 0, 'regs' is invalid */
+    int                 regs_dirty;         /* if not 0, 'regs' is modified and needs to be saved before context is continued */
+    void *              stack_trace;
+    int                 trace_flags;
+#if defined(_WRS_KERNEL)
+    VXDBG_BP_INFO       bp_info;            /* breakpoint information */
+    pid_t               bp_pid;             /* process or thread that hit breakpoint */
+#endif
+};
+
+extern void ini_contexts(void);
+
+extern char * event_name(int event);
+extern char * signal_name(int signal);
+extern char * context_state_name(Context * ctx);
+
+/*
+ * Convert PID to TCF Context ID
+ */
+extern char * pid2id(pid_t pid, pid_t parent);
+
+/*
+ * Get context thread ID
+ */
+extern char * thread_id(Context * ctx);
+
+/*
+ * Get context container ID
+ */
+extern char * container_id(Context * ctx);
+
+/*
+ * Convert TCF Context ID to PID
+ */
+extern pid_t id2pid(char * id, pid_t * parent);
+
+/* 
+ * Search Context record by TCF Context ID
+ */
+extern Context * id2ctx(char * id);
+
+/*
+ * Find a context by PID
+ */
+extern Context * context_find_from_pid(pid_t pid);
+
+/*
+ * Start tracing of a process.
+ */
+extern int context_attach(pid_t pid, Context ** ctx);
+
+/*
+ * Increment reference counter of Context object.
+ * While ref count > 0 object will not be deleted even when context exits.
+ */
+extern void context_lock(Context * ctx);
+
+/*
+ * Decrement reference counter.
+ * If ref count == 0, delete Context object.
+ */
+extern void context_unlock(Context * ctx);
+
+extern int context_stop(Context * ctx);
+extern int context_continue(Context * ctx);
+extern int context_single_step(Context * ctx);
+extern int context_write_mem(Context * ctx, unsigned long address, void * buf, size_t size);
+extern int context_read_mem(Context * ctx, unsigned long address, void * buf, size_t size);
+
+typedef struct ContextEventListener {
+    void (*context_created)(Context * ctx);
+    void (*context_exited)(Context * ctx);
+    void (*context_stopped)(Context * ctx);
+    void (*context_started)(Context * ctx);
+    void (*context_changed)(Context * ctx);
+    struct ContextEventListener * next;
+} ContextEventListener;
+
+extern void add_context_event_listener(ContextEventListener * listener);
+
+#ifdef _WRS_KERNEL
+extern VXDBG_CLNT_ID vxdbg_clnt_id;
+#endif
+
+#endif
diff --git a/diagnostics.c b/diagnostics.c
new file mode 100644
index 0000000..85ac3bd
--- /dev/null
+++ b/diagnostics.c
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Diagnostics service.
+ * This service is used for framework and agents testing.
+ */
+
+#include "config.h"
+#if defined(_WRS_KERNEL)
+#  include <vxWorks.h>
+#endif
+#include <signal.h>
+#include <assert.h>
+#include <stdio.h>
+#include "diagnostics.h"
+#include "protocol.h"
+#include "json.h"
+#include "exceptions.h"
+#include "runctrl.h"
+#include "symbols.h"
+#include "test.h"
+
+static const char * DIAGNOSTICS = "Diagnostics";
+
+static void command_echo(char * token, InputStream * inp, OutputStream * out) {
+    char str[0x1000];
+    int len = json_read_string(inp, str, sizeof(str));
+    if (len >= sizeof(str)) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    json_write_string_len(out, str, len);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_test_list(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+#if defined(WIN32)
+    write_stringz(out, "[]");
+#elif defined(_WRS_KERNEL)
+    write_stringz(out, "[\"RCBP1\"]");
+#else
+    write_stringz(out, "[\"RCBP1\"]");
+#endif
+    out->write(out, MARKER_EOM);
+}
+
+static void command_run_test(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    pid_t pid = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (strcmp(id, "RCBP1") == 0) {
+        if (run_test_process(&pid) < 0) err = errno;
+    }
+    else {
+        err = EINVAL;
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    json_write_string(out, err ? NULL : pid2id(pid, 0));
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void event_terminate(void * arg) {
+    Context * ctx = arg;
+    LINK * qp = ctx->children.next;
+    while (qp != &ctx->children) {
+        cldl2ctxp(qp)->pending_signals |= 1 << SIGKILL;
+        qp = qp->next;
+    }
+    ctx->pending_signals |= 1 << SIGKILL;
+    context_unlock(ctx);
+}
+
+static void command_cancel_test(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    Context * ctx = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+#if SERVICE_RunControl
+    ctx = id2ctx(id);
+    if (ctx != NULL && !ctx->exited) {
+        context_lock(ctx);
+        post_safe_event(event_terminate, ctx);
+    }
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_symbol(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    char name[0x1000];
+    Context * ctx;
+    Symbol sym;
+    int error = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    json_read_string(inp, name, sizeof(name));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    
+#if SERVICE_RunControl && SERVICE_Symbols
+    ctx = id2ctx(id);
+    if (ctx == NULL || ctx->exited) {
+        error = ERR_INV_CONTEXT;
+    }
+    else if (find_symbol(ctx, name, &sym) < 0) {
+        error = errno;
+    }
+#else
+    ctx = NULL;
+    error = EINVAL;
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, error);
+    if (error != 0) {
+        write_stringz(out, "null");
+    }
+    else {
+        out->write(out, '{');
+        json_write_string(out, "Abs");
+        out->write(out, ':');
+        json_write_boolean(out, sym.abs);
+        out->write(out, ',');
+        json_write_string(out, "Value");
+        out->write(out, ':');
+        json_write_ulong(out, sym.value);
+        if (sym.section != NULL) {
+            out->write(out, ',');
+            json_write_string(out, "Section");
+            out->write(out, ':');
+            json_write_string(out, sym.section);
+        }
+        if (sym.storage != NULL) {
+            out->write(out, ',');
+            json_write_string(out, "Storage");
+            out->write(out, ':');
+            json_write_string(out, sym.storage);
+        }
+        out->write(out, '}');
+        out->write(out, 0);
+    }
+    out->write(out, MARKER_EOM);
+}
+
+void ini_diagnostics_service(void) {
+    add_command_handler(DIAGNOSTICS, "echo", command_echo);
+    add_command_handler(DIAGNOSTICS, "getTestList", command_get_test_list);
+    add_command_handler(DIAGNOSTICS, "runTest", command_run_test);
+    add_command_handler(DIAGNOSTICS, "cancelTest", command_cancel_test);
+    add_command_handler(DIAGNOSTICS, "getSymbol", command_get_symbol);
+}
+
diff --git a/diagnostics.h b/diagnostics.h
new file mode 100644
index 0000000..09f6e09
--- /dev/null
+++ b/diagnostics.h
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Diagnostics service.
+ * This service is used for framework and agents testing.
+ */
+
+#ifndef D_diagnostics
+#define D_diagnostics
+
+extern void ini_diagnostics_service(void);
+
+#endif
diff --git a/dwarf.h b/dwarf.h
new file mode 100644
index 0000000..e5dace7
--- /dev/null
+++ b/dwarf.h
@@ -0,0 +1,563 @@
+/*******************************************************************************
+ * Copyright (c) 1996 - 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * DWARF Debugging Information Format.
+ */
+
+#define TAG_padding		    0x0000
+#define TAG_array_type		    0x0001
+#define TAG_class_type		    0x0002
+#define TAG_entry_point		    0x0003
+#define TAG_enumeration_type	    0x0004
+#define TAG_formal_parameter	    0x0005
+#define TAG_global_subroutine	    0x0006
+#define TAG_global_variable	    0x0007
+#define TAG_imported_declaration    0x0008
+#define TAG_label		    0x000a
+#define TAG_lexical_block	    0x000b
+#define TAG_local_variable	    0x000c
+#define TAG_member		    0x000d
+#define TAG_pointer_type	    0x000f
+#define TAG_reference_type	    0x0010
+#define TAG_compile_unit	    0x0011
+#define TAG_source_file		    0x0011
+#define TAG_string_type		    0x0012
+#define TAG_structure_type	    0x0013
+#define TAG_subroutine		    0x0014
+#define TAG_subroutine_type	    0x0015
+#define TAG_typedef		    0x0016
+#define TAG_union_type		    0x0017
+#define TAG_unspecified_parameters  0x0018
+#define TAG_variant		    0x0019
+#define TAG_common_block	    0x001a
+#define TAG_common_inclusion	    0x001b
+#define TAG_inheritance		    0x001c
+#define TAG_inlined_subroutine	    0x001d
+#define TAG_module		    0x001e
+#define TAG_ptr_to_member_type	    0x001f
+#define TAG_set_type		    0x0020
+#define TAG_subrange_type	    0x0021
+#define TAG_with_stmt		    0x0022
+#define TAG_access_declaration	    0x0023
+#define TAG_base_type		    0x0024
+#define TAG_catch_block		    0x0025
+#define TAG_const_type		    0x0026
+#define TAG_constant		    0x0027
+#define TAG_enumerator		    0x0028
+#define TAG_file_type		    0x0029
+#define TAG_friend		    0x002a
+#define TAG_namelist		    0x002b
+#define TAG_namelist_item	    0x002c
+#define TAG_packed_type		    0x002d
+#define TAG_subprogram		    0x002e
+#define TAG_template_type_param	    0x002f
+#define TAG_template_value_param    0x0030
+#define TAG_thrown_type		    0x0031
+#define TAG_try_block		    0x0032
+#define TAG_variant_part	    0x0033
+#define TAG_variable		    0x0034
+#define TAG_volatile_type	    0x0035
+#define TAG_dwarf_procedure	    0x0036
+#define TAG_restrict_type	    0x0037
+#define TAG_interface_type	    0x0038
+#define TAG_namespace		    0x0039
+#define TAG_imported_module	    0x003a
+#define TAG_unspecified_type	    0x003b
+#define TAG_partial_unit	    0x003c
+#define TAG_imported_unit	    0x003d
+#define TAG_mutable_type	    0x003e
+#define TAG_condition               0x003f
+#define TAG_shared_type             0x0040
+#define TAG_lo_user		    0x4080
+#define TAG_wrs_thrown_object	    0x4080
+#define TAG_wrs_throw_breakpoint    0x4081
+#define TAG_wrs_catch_breakpoint    0x4082
+#define TAG_wrs_extern_subroutine   0x4083
+#define TAG_hi_user		    0xffff
+
+#define CHILDREN_no		    0x00
+#define CHILDREN_yes		    0x01
+
+#define FORM_ADDR		    0x0001
+#define FORM_REF		    0x0002
+#define FORM_BLOCK2		    0x0003
+#define FORM_BLOCK4		    0x0004
+#define FORM_DATA2		    0x0005
+#define FORM_DATA4		    0x0006
+#define FORM_DATA8		    0x0007
+#define FORM_STRING		    0x0008
+#define FORM_BLOCK		    0x0009
+#define FORM_BLOCK1		    0x000a
+#define FORM_DATA1		    0x000b
+#define FORM_FLAG		    0x000c
+#define FORM_SDATA		    0x000d
+#define FORM_STRP		    0x000e
+#define FORM_UDATA		    0x000f
+#define FORM_REF_ADDR		    0x0010
+#define FORM_REF1		    0x0011
+#define FORM_REF2		    0x0012
+#define FORM_REF4		    0x0013
+#define FORM_REF8		    0x0014
+#define FORM_REF_UDATA		    0x0015
+#define FORM_INDIRECT		    0x0016
+
+#define AT_sibling		    0x0001
+#define AT_location		    0x0002
+#define AT_name			    0x0003
+#define AT_fund_type		    0x0005
+#define AT_mod_fund_type	    0x0006
+#define AT_user_def_type	    0x0007
+#define AT_mod_u_d_type		    0x0008
+#define AT_ordering                 0x0009
+#define AT_subscr_data	            0x000a
+#define AT_byte_size                0x000b
+#define AT_bit_offset	            0x000c
+#define AT_bit_size                 0x000d
+#define AT_element_list	            0x000f
+#define AT_stmt_list                0x0010
+#define AT_low_pc                   0x0011
+#define AT_high_pc                  0x0012
+#define AT_language                 0x0013
+#define AT_member                   0x0014
+#define AT_discr	            0x0015
+#define AT_discr_value	            0x0016
+#define AT_visibility		    0x0017
+#define AT_import		    0x0018
+#define AT_string_length	    0x0019
+#define AT_common_reference         0x001a
+#define AT_comp_dir                 0x001b
+#define AT_const_value	            0x001c
+#define AT_constaining_type         0x001d
+#define AT_default_value	    0x001e
+#define AT_friends                  0x001f
+#define AT_inline                   0x0020
+#define AT_is_optional              0x0021
+#define AT_lower_bound              0x0022
+#define AT_program                  0x0023
+#define AT_private                  0x0024
+#define AT_producer                 0x0025
+#define AT_protected                0x0026
+#define AT_prototyped               0x0027
+#define AT_public                   0x0028
+#define AT_pure_virtual             0x0029
+#define AT_return_addr              0x002a
+#define AT_specification_v1         0x002b
+#define AT_start_scope              0x002c
+#define AT_stride_size              0x002e
+#define AT_upper_bound              0x002f
+#define AT_virtual                  0x0030
+#define AT_abstract_origin	    0x0031
+#define AT_accessibility	    0x0032
+#define AT_address_class	    0x0033
+#define AT_artificial		    0x0034
+#define AT_base_types		    0x0035
+#define AT_calling_convention	    0x0036
+#define AT_count		    0x0037
+#define AT_data_member_location	    0x0038
+#define AT_decl_column		    0x0039
+#define AT_decl_file		    0x003a
+#define AT_decl_line		    0x003b
+#define AT_declaration		    0x003c
+#define AT_distr_list		    0x003d
+#define AT_encoding		    0x003e
+#define AT_external		    0x003f
+#define AT_frame_base		    0x0040
+#define AT_friend		    0x0041
+#define AT_identifier_case	    0x0042
+#define AT_macro_info		    0x0043
+#define AT_namelist_info	    0x0044  /* typo? item */
+#define AT_priority		    0x0045
+#define AT_segment		    0x0046
+#define AT_specification_v2	    0x0047  /* v2 */
+#define AT_static_link		    0x0048
+#define AT_type			    0x0049
+#define AT_use_location		    0x004a
+#define AT_variable_parameter	    0x004b
+#define AT_virtuality		    0x004c
+#define AT_vtable_elem_location	    0x004d
+#define AT_allocated		    0x004e  /* v3 */
+#define AT_associated		    0x004f  /* v3 */
+#define AT_mangled                  0x0050  /* v1 */
+#define AT_data_location	    0x0050  /* v2 */
+#define AT_stride		    0x0051  /* v3 */
+#define AT_entry_pc		    0x0052  /* v3 */
+#define AT_use_UTF8		    0x0053  /* v3 */
+#define AT_extension		    0x0054  /* v3 */
+#define AT_ranges		    0x0055  /* v3 */
+#define AT_trampoline		    0x0056  /* v3 */
+#define AT_call_column		    0x0057  /* v3 */
+#define AT_call_file		    0x0058  /* v3 */
+#define AT_call_line		    0x0059  /* v3 */
+#define AT_description		    0x005a  /* v3 */
+#define AT_lo_user_v1               0x0200
+#define AT_hi_user_v1               0x03ff
+#define AT_push_mask                0x0220
+#define AT_frame_size               0x0221
+#define AT_main_unit		    0x0222
+#define AT_stack_use		    0x0223
+#define AT_source_file_names        0x0800
+#define AT_source_info              0x0810
+#define AT_lo_user_v2		    0x2000
+#define AT_wrs_options		    0x2001
+#define AT_hi_user_v2		    0x3fff
+
+
+#define OP_reg                      0x01  /* v1 */
+#define OP_basereg                  0x02  /* v1 */
+#define OP_addr                     0x03
+#define OP_const                    0x04  /* v1 */
+#define OP_deref2                   0x05  /* v1 */
+#define OP_deref                    0x06
+#define OP_add                      0x07  /* v1 */
+#define OP_const1u		    0x08
+#define OP_const1s		    0x09
+#define OP_const2u		    0x0a
+#define OP_const2s		    0x0b
+#define OP_const4u		    0x0c
+#define OP_const4s		    0x0d
+#define OP_const8u		    0x0e
+#define OP_const8s		    0x0f
+#define OP_constu		    0x10
+#define OP_consts		    0x11
+#define OP_dup			    0x12
+#define OP_drop			    0x13
+#define OP_over			    0x14
+#define OP_pick			    0x15
+#define OP_swap			    0x16
+#define OP_rot			    0x17
+#define OP_xderef		    0x18
+#define OP_abs			    0x19
+#define OP_and			    0x1a
+#define OP_div			    0x1b
+#define OP_minus		    0x1c
+#define OP_mod			    0x1d
+#define OP_mul			    0x1e
+#define OP_neg			    0x1f
+#define OP_not			    0x20
+#define OP_or			    0x21
+#define OP_plus			    0x22
+#define OP_plus_uconst		    0x23
+#define OP_shl			    0x24
+#define OP_shr			    0x25
+#define OP_shra			    0x26
+#define OP_xor			    0x27
+#define OP_bra			    0x28
+#define OP_eq			    0x29
+#define OP_ge			    0x2a
+#define OP_gt			    0x2b
+#define OP_le			    0x2c
+#define OP_lt			    0x2d
+#define OP_ne			    0x2e
+#define OP_skip			    0x2f
+#define OP_lit0			    0x30
+#define OP_lit1			    0x31
+#define OP_lit2 		    0x32
+#define OP_lit3			    0x33
+#define OP_lit4			    0x34
+#define OP_lit5			    0x35
+#define OP_lit6			    0x36
+#define OP_lit7			    0x37
+#define OP_lit8			    0x38
+#define OP_lit9			    0x39
+#define OP_lit10		    0x3a
+#define OP_lit11		    0x3b
+#define OP_lit12		    0x3c
+#define OP_lit13		    0x3d
+#define OP_lit14		    0x3e
+#define OP_lit15		    0x3f
+#define OP_lit16		    0x40
+#define OP_lit17		    0x41
+#define OP_lit18		    0x42
+#define OP_lit19		    0x43
+#define OP_lit20		    0x44
+#define OP_lit21		    0x45
+#define OP_lit22		    0x46
+#define OP_lit23		    0x47
+#define OP_lit24		    0x48
+#define OP_lit25		    0x49
+#define OP_lit26		    0x4a
+#define OP_lit27		    0x4b
+#define OP_lit28		    0x4c
+#define OP_lit29		    0x4d
+#define OP_lit30		    0x4e
+#define OP_lit31		    0x4f
+#define OP_reg0			    0x50
+#define OP_reg1			    0x51
+#define OP_reg2 		    0x52
+#define OP_reg3			    0x53
+#define OP_reg4			    0x54
+#define OP_reg5			    0x55
+#define OP_reg6			    0x56
+#define OP_reg7			    0x57
+#define OP_reg8			    0x58
+#define OP_reg9			    0x59
+#define OP_reg10		    0x5a
+#define OP_reg11		    0x5b
+#define OP_reg12		    0x5c
+#define OP_reg13		    0x5d
+#define OP_reg14		    0x5e
+#define OP_reg15		    0x5f
+#define OP_reg16		    0x60
+#define OP_reg17		    0x61
+#define OP_reg18		    0x62
+#define OP_reg19		    0x63
+#define OP_reg20		    0x64
+#define OP_reg21		    0x65
+#define OP_reg22		    0x66
+#define OP_reg23		    0x67
+#define OP_reg24		    0x68
+#define OP_reg25		    0x69
+#define OP_reg26		    0x6a
+#define OP_reg27		    0x6b
+#define OP_reg28		    0x6c
+#define OP_reg29		    0x6d
+#define OP_reg30		    0x6e
+#define OP_reg31		    0x6f
+#define OP_breg0		    0x70
+#define OP_breg1		    0x71
+#define OP_breg2 		    0x72
+#define OP_breg3		    0x73
+#define OP_breg4		    0x74
+#define OP_breg5		    0x75
+#define OP_breg6		    0x76
+#define OP_breg7		    0x77
+#define OP_breg8		    0x78
+#define OP_breg9		    0x79
+#define OP_breg10		    0x7a
+#define OP_breg11		    0x7b
+#define OP_breg12		    0x7c
+#define OP_breg13		    0x7d
+#define OP_breg14		    0x7e
+#define OP_breg15		    0x7f
+#define OP_breg16		    0x80
+#define OP_breg17		    0x81
+#define OP_breg18		    0x82
+#define OP_breg19		    0x83
+#define OP_breg20		    0x84
+#define OP_breg21		    0x85
+#define OP_breg22		    0x86
+#define OP_breg23		    0x87
+#define OP_breg24		    0x88
+#define OP_breg25		    0x89
+#define OP_breg26		    0x8a
+#define OP_breg27		    0x8b
+#define OP_breg28		    0x8c
+#define OP_breg29		    0x8d
+#define OP_breg30		    0x8e
+#define OP_breg31		    0x8f
+#define OP_regx			    0x90
+#define OP_fbreg		    0x91
+#define OP_bregx		    0x92
+#define OP_piece		    0x93
+#define OP_deref_size		    0x94
+#define OP_xderef_size		    0x95
+#define OP_nop			    0x96
+#define OP_push_object_address	    0x97
+#define OP_call2		    0x98
+#define OP_call4		    0x99
+#define OP_calli		    0x9a  /* typo? */
+#define OP_ref  		    0x9a
+#define OP_call_ref  		    0x9a
+#define OP_bit_piece                0x9d
+#define OP_lo_user		    0xe0
+#define OP_hi_user		    0xff
+
+#define FT_char                     0x0001
+#define FT_signed_char              0x0002
+#define FT_unsigned_char            0x0003
+#define FT_short                    0x0004
+#define FT_signed_short             0x0005
+#define FT_unsigned_short           0x0006
+#define FT_integer                  0x0007
+#define FT_signed_integer           0x0008
+#define FT_unsigned_integer         0x0009
+#define FT_long                     0x000a
+#define FT_signed_long              0x000b
+#define FT_unsigned_long            0x000c
+#define FT_pointer                  0x000d
+#define FT_float                    0x000e
+#define FT_dbl_prec_float           0x000f
+#define FT_ext_prec_float	    0x0010
+#define FT_complex                  0x0011
+#define FT_dbl_prec_complex         0x0012
+#define FT_void                     0x0014
+#define FT_boolean                  0x0015
+#define FT_ext_prec_complex         0x0016
+#define FT_label                    0x0017
+#define FT_lo_user                  0x8000
+#define FT_hi_user                  0xffff
+#define	FT_longlong		    0x8008
+#define	FT_signed_longlong	    0x8108
+#define	FT_unsigned_longlong	    0x8208
+#define	FT_vector_signed_char	    0xa002
+#define	FT_vector_unsigned_char	    0xa003
+#define	FT_vector_signed_short	    0xa005
+#define	FT_vector_unsigned_short    0xa006
+#define	FT_vector_signed_int	    0xa008
+#define	FT_vector_unsigned_int      0xa009
+#define	FT_vector_float	      	    0xa00e
+#define FT_ev64_s16		    0xb005
+#define FT_ev64_u16		    0xb006
+#define FT_ev64_s32		    0xb008
+#define FT_ev64_u32		    0xb009
+#define FT_ev64_s64		    0xb208
+#define FT_ev64_u64		    0xb209
+#define FT_ev64_fs		    0xb00e
+#define FT_ev64_opaque		    0xb020
+
+#define MOD_pointer_to              0x01
+#define MOD_reference_to            0x02
+#define MOD_const                   0x03
+#define MOD_volatile                0x04
+#define MOD_lo_user                 0x80
+#define MOD_hi_user                 0xff
+
+#define LANG_C89                    0x00000001
+#define LANG_C                      0x00000002
+#define LANG_ADA83                  0x00000003
+#define LANG_C_PLUS_PLUS            0x00000004
+#define LANG_COBOL74                0x00000005
+#define LANG_COBOL85                0x00000006
+#define LANG_FORTRAN77              0x00000007
+#define LANG_FORTRAN90              0x00000008
+#define LANG_PASCAL83               0x00000009
+#define LANG_MODULA2                0x0000000a
+#define LANG_JAVA		    0x0000000b  /* v3 */
+#define LANG_C99 		    0x0000000c  /* v3 */
+#define LANG_ADA95	    	    0x0000000d  /* v3 */
+#define LANG_FORTRAN95              0x0000000e  /* v3 */
+#define LANG_PLI		    0x0000000f
+#define LANG_lo_user                0x00008000
+#define LANG_hi_user                0x0000ffff
+
+#define ORD_row_major               0
+#define ORD_col_major               1
+
+#define FMT_FT_C_C                  0x0
+#define FMT_FT_C_X                  0x1
+#define FMT_FT_X_C                  0x2
+#define FMT_FT_X_X                  0x3
+#define FMT_UT_C_C                  0x4
+#define FMT_UT_C_X                  0x5
+#define FMT_UT_X_C                  0x6
+#define FMT_UT_X_X                  0x7
+#define FMT_ET                      0x8
+
+#define DW_ATE_address		    0x01
+#define DW_ATE_boolean		    0x02
+#define DW_ATE_complex_float	    0x03
+#define DW_ATE_float		    0x04
+#define DW_ATE_signed		    0x05
+#define DW_ATE_signed_char	    0x06
+#define DW_ATE_unsigned		    0x07
+#define DW_ATE_unsigned_char	    0x08
+#define DW_ATE_imaginary_float	    0x09  /* v3 */
+#define DW_ATE_lo_user		    0x80
+#define DW_ATE_hi_user		    0xff
+
+#define DW_LNS_copy		    1
+#define DW_LNS_advance_pc	    2
+#define DW_LNS_advance_line	    3
+#define DW_LNS_set_file		    4
+#define DW_LNS_set_column	    5
+#define DW_LNS_negate_stmt	    6
+#define DW_LNS_set_basic_block	    7
+#define DW_LNS_const_add_pc	    8
+#define DW_LNS_fixed_advance_pc	    9
+#define DW_LNS_set_prologue_end	    0xa  /* v3 */
+#define DW_LNS_set_epilogue_begin   0xb  /* v3 */
+#define DW_LNS_set_isa		    0xc  /* v3 */
+#define DW_LNS_expected_opcode_base 0xd  /* highest standard opcode plus one */
+#define DW_LNS_vendor_extension	    0x100
+#define DW_LNS_special_opcode	    0x101
+
+#define DW_LNE_end_sequence	    1
+#define DW_LNE_set_address	    2
+#define DW_LNE_define_file	    3
+#define DW_LNE_lo_user		    0x80  /* v3 */
+#define DW_LNE_hi_user		    0xff  /* v3 */
+
+#define ACCESS_public		    1
+#define ACCESS_protected	    2
+#define ACCESS_private		    3
+
+#define VIS_local		    1
+#define VIS_exported		    2
+#define VIS_qualified		    3
+
+#define VIRTUALITY_none		    0
+#define VIRTUALITY_virtual	    1
+#define VIRTUALITY_pure_virtual     2
+
+#define ID_case_sensitive	    0
+#define ID_up_case		    1
+#define ID_down_case		    2
+#define ID_case_insensitive	    3
+
+#define CC_normal		    0x01
+#define CC_program		    0x02
+#define CC_nocall 		    0x03
+#define CC_lo_user		    0x40
+#define CC_hi_user		    0xff
+
+#define INL_not_inlined		    0
+#define INL_inlined		    1
+#define INL_declared_not_inlined    2
+#define INL_declared_inlined        3
+
+#define DSC_label		    0
+#define DSC_range		    1
+
+#define MACINFO_define		    1
+#define MACINFO_undef		    2
+#define MACINFO_start_file	    3
+#define MACINFO_end_file	    4
+#define MACINFO_vendor_ext	    0xff
+
+/* The following three defines represent */
+/* the high 2 bits only.		 */
+#define CFA_advance_loc		    0x01
+#define CFA_offset		    0x02
+#define CFA_restore	    	    0x03
+
+#define CFA_nop			    0x00
+#define CFA_set_loc		    0x01
+#define CFA_advance_loc1	    0x02
+#define CFA_advance_loc2	    0x03
+#define CFA_advance_loc4	    0x04
+#define CFA_offset_extended         0x05
+#define CFA_restore_extended        0x06
+#define CFA_undefined		    0x07
+#define CFA_same_value		    0x08
+#define CFA_register  		    0x09
+#define CFA_remember_state	    0x0a
+#define CFA_restore_state	    0x0b
+#define CFA_def_cfa		    0x0c
+#define CFA_def_cfa_register	    0x0d
+#define CFA_def_cfa_offset  	    0x0e
+#define CFA_def_cfa_expression      0x0f
+#define CFA_expression        	    0x10  /* v3 */
+#define CFA_offset_extended_sf	    0x11  /* v3 */
+#define CFA_def_cfa_sf        	    0x12  /* v3 */
+#define CFA_def_cfa_offset_sf       0x13  /* v3 */
+#define CFA_lo_user		    0x1c
+#define CFA_hi_user		    0x3f
+
+
+#define ADDR_none		    0
+#define ADDR_near16		    1
+#define ADDR_far16		    2
+#define ADDR_huge16		    3
+#define ADDR_near32		    4
+#define ADDR_far32		    5
+
+
diff --git a/dwarfio.c b/dwarfio.c
new file mode 100644
index 0000000..7b55d19
--- /dev/null
+++ b/dwarfio.c
@@ -0,0 +1,728 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements low-level functions for reading DWARF debug information.
+ *
+ * Functions in this module use exceptions to report errors, see exceptions.h
+ */
+#include "config.h"
+#if SERVICE_LineNumbers
+
+#include <assert.h>
+#include <string.h>
+#include "dwarfio.h"
+#include "dwarf.h"
+#include "myalloc.h"
+#include "exceptions.h"
+
+#define INP_BUF_SIZE            0x1000
+#define ABBREV_TABLE_SIZE       1021
+
+struct DIO_Abbreviation {
+    U2_T mTag;
+    U1_T mChildren;
+    U4_T mAttrLen;
+    U2_T mAttrs[2];
+};
+
+typedef struct DIO_Abbreviation DIO_Abbreviation;
+
+struct DIO_AbbrevSet {
+    struct DIO_AbbrevSet * mNext;
+    ELF_File * mFile;
+    U8_T mOffset;
+    DIO_Abbreviation ** mTable;
+    U4_T mSize;
+};
+
+typedef struct DIO_AbbrevSet DIO_AbbrevSet;
+
+struct DIO_Cache {
+    U1_T * mStringTable;
+    U4_T mStringTableSize;
+    DIO_AbbrevSet ** mAbbrevTable;
+};
+
+typedef struct DIO_Cache DIO_Cache;
+
+U4_T dio_gVersion = 0;
+U1_T dio_g64bit = 0;
+U1_T dio_gAddressSize = 4;
+U8_T dio_gUnitPos = 0;
+U4_T dio_gUnitSize = 0;
+U8_T dio_gEntryPos = 0;
+
+U8_T dio_gFormRef;
+U8_T dio_gFormData = 0;
+U1_T dio_gFormDataSize = 0;
+U4_T dio_gFormBlockSize = 0;
+U1_T * dio_gFormBlockBuf = NULL;
+
+static ELF_Section * sSection;
+static U1_T sBigEndian;
+static DIO_Abbreviation ** sAbbrevTable = NULL;
+static U4_T sAbbrevTableSize = 0;
+static U1_T * sInpBuf = NULL;
+static U4_T sBufPos;
+static U4_T sBufLen;
+static U8_T sDataPos;
+
+static void dio_CloseELF(ELF_File * File) {
+    U4_T n, m;
+    DIO_Cache * Cache = (DIO_Cache *)File->dwarf_cache;
+
+    if (Cache == NULL) return;
+    for (n = 0; n < ABBREV_TABLE_SIZE; n++) {
+        DIO_AbbrevSet * Set = Cache->mAbbrevTable[n];
+        while (Set != NULL) {
+            DIO_AbbrevSet * Next = Set->mNext;
+            for (m = 0; m < Set->mSize; m++) {
+                loc_free(Set->mTable[m]);
+            }
+            loc_free(Set->mTable);
+            loc_free(Set);
+            Set = Next;
+        }
+    }
+    loc_free(Cache->mAbbrevTable);
+    File->dwarf_cache = NULL;
+}
+
+static DIO_Cache * dio_GetCache(ELF_File * File) {
+    static int Inited = 0;
+    DIO_Cache * Cache = (DIO_Cache *)File->dwarf_cache;
+
+    if (!Inited) {
+        elf_add_close_listener(dio_CloseELF);
+        Inited = 1;
+    }
+    if (Cache == NULL) {
+        Cache = (DIO_Cache *)(File->dwarf_cache = loc_alloc_zero(sizeof(DIO_Cache)));
+    }
+    return Cache;
+}
+
+void dio_EnterSection(ELF_Section * Section, U8_T Offset) {
+    sSection = Section;
+    sDataPos = Offset;
+    sBufPos = 0;
+    sBufLen = 0;
+    sBigEndian = Section->file->big_endian;
+
+    if (sInpBuf == NULL) {
+        sInpBuf = (U1_T *)loc_alloc(INP_BUF_SIZE);
+    }
+}
+
+void dio_ExitSection() {
+    sSection = NULL;
+    sDataPos = 0;
+    sBufPos = 0;
+    sBufLen = 0;
+}
+
+U8_T dio_GetPos() {
+    return sDataPos;
+}
+
+void dio_Skip(U8_T Bytes) {
+    sDataPos += Bytes;
+    if (sBufPos + Bytes >= sBufLen) {
+        sBufPos = 0;
+        sBufLen = 0;
+    }
+    else {
+        sBufPos += (U4_T)Bytes;
+    }
+}
+
+void dio_Read(U1_T * Buf, U4_T Size) {
+    assert(sSection->size >= sDataPos + Size);
+    if (sBufPos < sBufLen) {
+        U4_T FromBuf = Size < sBufLen - sBufPos ? Size : sBufLen - sBufPos;
+        memcpy(Buf, sInpBuf + sBufPos, FromBuf);
+        sBufPos += FromBuf;
+        Buf += FromBuf;
+        Size -= FromBuf;
+        sDataPos += FromBuf;
+    }
+    if (Size > 0) {
+        U4_T Rd = 0;
+        if (elf_read(sSection, sDataPos, Buf, Size, &Rd) < 0) exception(errno);
+        if (Rd < Size) exception(ERR_EOF);
+        assert(sBufPos >= sBufLen);
+        sDataPos += Size;
+    }
+}
+
+U1_T dio_ReadU1F(void) {
+    U1_T c;
+    if (sDataPos >= sSection->size) exception(ERR_EOF);
+    if (sBufPos < sBufLen) {
+        c = sInpBuf[sBufPos++];
+    }
+    else if (sBufPos >= sBufLen) {
+        U4_T Rd = 0;
+        U8_T Size = sSection->size - sDataPos;
+        if (Size > INP_BUF_SIZE) Size = INP_BUF_SIZE;
+        if (elf_read(sSection, sDataPos, sInpBuf, (U4_T)Size, &Rd) < 0) exception(errno);
+        if (Rd == 0) exception(ERR_EOF);
+        sBufLen = Rd;
+	c = sInpBuf[0];
+        sBufPos = 1;
+    }
+    sDataPos++;
+    return c;
+}
+
+U1_T dio_ReadU1(void) {
+    return sBufPos >= sBufLen ? dio_ReadU1F() : (sDataPos++, sInpBuf[sBufPos++]);
+}
+
+#define dio_ReadU1() (sBufPos >= sBufLen ? dio_ReadU1F() : (sDataPos++, sInpBuf[sBufPos++]))
+
+U2_T dio_ReadU2(void) {
+    U1_T x0 = dio_ReadU1();
+    U1_T x1 = dio_ReadU1();
+    return sBigEndian ? (x0 << 8) | x1 : x0 | (x1 << 8);
+}
+                
+U4_T dio_ReadU4(void) {
+    U2_T x0 = dio_ReadU2();
+    U2_T x1 = dio_ReadU2();
+    return sBigEndian ? (x0 << 16) | x1 : x0 | (x1 << 16);
+}
+
+U8_T dio_ReadU8(void) {
+    U8_T x0 = dio_ReadU4();
+    U8_T x1 = dio_ReadU4();
+    return sBigEndian ? (x0 << 32) | x1 : x0 | (x1 << 32);
+}
+
+U4_T dio_ReadLEB128(void) {
+    U4_T res = 0;
+    int i = 0;
+    for (;; i += 7) {
+	U1_T n = dio_ReadU1();
+	res |= (n & 0x7Fu) << i;
+	if ((n & 0x80) == 0) break;
+    }
+    return res;
+}
+
+U8_T dio_ReadU8LEB128(void) {
+    U8_T res = 0;
+    int i = 0;
+    for (;; i += 7) {
+	U1_T n = dio_ReadU1();
+	res |= (n & 0x7Fu) << i;
+	if ((n & 0x80) == 0) break;
+    }
+    return res;
+}
+
+I8_T dio_ReadI8LEB128(void) {
+    U8_T res = 0;
+    int i = 0;
+    for (;; i += 7) {
+	U1_T n = dio_ReadU1();
+	res |= (n & 0x7Fu) << i;
+        if ((n & 0x80) == 0) {
+	    res |= -(n & 0x40) << i;
+            break;
+        }
+    }
+    return (I8_T)res;
+}
+
+U8_T dio_ReadUX(int Size) {
+    switch (Size) {
+    case 2:
+        return dio_ReadU2();
+    case 4:
+        return dio_ReadU4();
+    case 8:
+        return dio_ReadU8();
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+U8_T dio_ReadAddress(void) {
+    switch (dio_gAddressSize) {
+    case 2:
+        return dio_ReadU2();
+    case 4:
+        return dio_ReadU4();
+    case 8:
+        return dio_ReadU8();
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+static void dio_CheckBlockBufCapacity(U4_T Size) {
+    static U4_T BufSize = 0;
+    if (BufSize < Size) { 
+        BufSize = BufSize == 0 ? 0x100 : BufSize * 2;
+        dio_gFormBlockBuf = (U1_T *)loc_realloc(dio_gFormBlockBuf, BufSize);
+    }
+}
+
+char * dio_ReadString(void) {
+    char * Res = NULL;
+    U4_T Length = 0;
+    for (;;) {
+        U1_T Char = dio_ReadU1();
+        dio_CheckBlockBufCapacity(Length + 1);
+        dio_gFormBlockBuf[Length++] = Char;
+        if (Char == 0) break;
+    }
+    if (Length == 1) return NULL;
+    Res = (char *)loc_alloc(Length);
+    strcpy(Res, (char *)dio_gFormBlockBuf);
+    return Res;
+}
+
+U8_T dio_ReadAddrBuf(U1_T * Buf) {
+    int i;
+    U8_T Addr = 0;
+    for (i = 0; i < dio_gAddressSize; i++) {
+        U8_T Byte = (U8_T)Buf[i];
+        if (sBigEndian) {
+            Addr |= Byte << ((dio_gAddressSize - i - 1) * 8);
+        }
+        else {
+            Addr |= Byte << (i * 8);
+        }
+    }
+    return Addr;
+}
+
+static U1_T * dio_LoadStringTable(U4_T * StringTableSize) {
+    ELF_File * File = sSection->file;
+    DIO_Cache * Cache = dio_GetCache(File);
+
+    if (Cache->mStringTable == NULL) {
+        U4_T ID;
+        ELF_Section * Section = NULL;
+
+        for (ID = 1; ID < File->section_cnt; ID++) {
+            if (strcmp(File->sections[ID]->name, ".debug_str") == 0) {
+                if (Section != NULL) {
+                    str_exception(ERR_DWARF, "more then one .debug_str section in a file");
+                }
+                Section = File->sections[ID];
+                assert(Section->file == File);
+            }
+        }
+
+        if (Section == NULL) {
+            str_exception(ERR_DWARF, "section .debug_str not found");
+        }
+
+        Cache->mStringTableSize = (size_t)Section->size;
+        if (elf_load(Section, &Cache->mStringTable) < 0) {
+            str_exception(ERR_DWARF, "invalid .debug_str section");
+        }
+    }
+
+    *StringTableSize = Cache->mStringTableSize;
+    return Cache->mStringTable;
+}
+
+static void dio_ReadFormAddr(void) {
+    dio_gFormRef = dio_ReadAddress();
+}
+
+static void dio_ReadFormBlock(U2_T Attr, U4_T Size) {
+    U1_T * Buf;
+    dio_gFormBlockSize = Size;
+    dio_CheckBlockBufCapacity(Size);
+    Buf = dio_gFormBlockBuf;
+    while (Size > 0) {
+        *Buf++ = dio_ReadU1();
+        Size--;
+    }
+}
+
+static void dio_ReadFormData(U2_T Attr, U1_T Size, U8_T Data) {
+    dio_gFormData = Data;
+    dio_gFormDataSize = Size;
+}
+
+static void dio_ReadFormFlag(void) {
+    dio_gFormData = dio_ReadU1();
+    dio_gFormDataSize = 1;
+}
+
+static void dio_ReadFormRef(void) {
+    dio_gFormRef = dio_ReadU4();
+}
+
+static void dio_ReadFormRelRef(U8_T Offset) {
+    if (dio_gUnitSize > 0 && Offset >= dio_gUnitSize) {
+        str_exception(ERR_DWARF, "invalid REF attribute value");
+    }
+    dio_gFormRef = dio_gUnitPos + Offset;
+}
+
+static void dio_ReadFormRefAddr(void) {
+    U4_T Size = dio_gAddressSize;
+    if (dio_gVersion >= 3) Size = dio_g64bit ? 8 : 4;
+    dio_gFormRef = dio_ReadUX(Size);
+}
+
+static void dio_ReadFormString(void) {
+    dio_gFormBlockSize = 0;
+    for (;;) {
+        U1_T Char = dio_ReadU1();
+        dio_CheckBlockBufCapacity(dio_gFormBlockSize + 1);
+        dio_gFormBlockBuf[dio_gFormBlockSize++] = Char;
+        if (Char == 0) break;
+    }
+}
+
+static void dio_ReadFormStringRef(void) {
+    U8_T Offset = dio_ReadUX(dio_g64bit ? 8 : 4);
+    U4_T StringTableSize = 0;
+    U1_T * StringTable = dio_LoadStringTable(&StringTableSize);
+    dio_gFormBlockSize = 0;
+    for (;;) {
+        U1_T Char;
+        if (Offset >= StringTableSize) {
+            str_exception(ERR_DWARF, "invalid FORM_STRP attribute");
+        }
+        dio_CheckBlockBufCapacity(dio_gFormBlockSize + 1);
+        Char = StringTable[Offset++];
+        dio_gFormBlockBuf[dio_gFormBlockSize++] = Char;
+        if (Char == 0) break;
+    }
+}
+
+static void dio_ReadAttribute(U2_T Attr, U2_T Form) {
+    switch (Form) {
+    case FORM_ADDR      : dio_ReadFormAddr(); break;
+    case FORM_REF       : dio_ReadFormRef(); break;
+    case FORM_BLOCK1    : dio_ReadFormBlock(Attr, dio_ReadU1()); break;
+    case FORM_BLOCK2    : dio_ReadFormBlock(Attr, dio_ReadU2()); break;
+    case FORM_BLOCK4    : dio_ReadFormBlock(Attr, dio_ReadU4()); break;
+    case FORM_BLOCK     : dio_ReadFormBlock(Attr, dio_ReadLEB128()); break;
+    case FORM_DATA1     : dio_ReadFormData(Attr, 1, dio_ReadU1()); break;
+    case FORM_DATA2     : dio_ReadFormData(Attr, 2, dio_ReadU2()); break;
+    case FORM_DATA4     : dio_ReadFormData(Attr, 4, dio_ReadU4()); break;
+    case FORM_DATA8     : dio_ReadFormData(Attr, 8, dio_ReadU8()); break;
+    case FORM_SDATA     : dio_ReadFormData(Attr, 8, dio_ReadI8LEB128()); break;
+    case FORM_UDATA     : dio_ReadFormData(Attr, 8, dio_ReadU8LEB128()); break;
+    case FORM_FLAG      : dio_ReadFormFlag(); break;
+    case FORM_STRING    : dio_ReadFormString(); break;
+    case FORM_STRP      : dio_ReadFormStringRef(); break;
+    case FORM_REF_ADDR  : dio_ReadFormRefAddr(); break;
+    case FORM_REF1      : dio_ReadFormRelRef(dio_ReadU1()); break;
+    case FORM_REF2      : dio_ReadFormRelRef(dio_ReadU2()); break;
+    case FORM_REF4      : dio_ReadFormRelRef(dio_ReadU4()); break;
+    case FORM_REF8      : dio_ReadFormRelRef(dio_ReadU8()); break;
+    case FORM_REF_UDATA : dio_ReadFormRelRef(dio_ReadLEB128()); break;
+    default: str_exception(ERR_DWARF, "invalid FORM");
+    }
+}
+
+static void dio_ReadEntry(DIO_EntryCallBack CallBack) {
+    DIO_Abbreviation * Abbr = NULL;
+    U2_T Tag = 0;
+    U4_T AttrPos = 0;
+    U4_T EntrySize = 0;
+    int Init = 1;
+    dio_gEntryPos = dio_GetPos();
+    if (dio_gVersion >= 2) {
+        U4_T AbbrCode = dio_ReadLEB128();
+        if (AbbrCode == 0) return;
+        if (AbbrCode >= sAbbrevTableSize || sAbbrevTable[AbbrCode] == NULL) {
+            str_exception(ERR_DWARF, "invalid abbreviation table");
+        }
+        Abbr =  sAbbrevTable[AbbrCode];
+        Tag = Abbr->mTag;
+    }
+    else {
+        EntrySize = dio_ReadU4();
+        if (EntrySize < 8) {
+            while (EntrySize > 4) {
+                dio_ReadU1();
+                EntrySize--;
+            }
+            return;
+        }
+        Tag = dio_ReadU2();
+    }
+    for (;;) {
+	U2_T Attr = 0;
+	U2_T Form = 0;
+        if (Init) {
+            Form = 1;
+            Init = 0;
+        }
+	else if (Abbr != NULL) {
+            if (AttrPos < Abbr->mAttrLen) {
+		Attr = Abbr->mAttrs[AttrPos++];
+		Form = Abbr->mAttrs[AttrPos++];
+		if (Form == FORM_INDIRECT) Form = (U2_T)dio_ReadLEB128();
+            }
+	}
+	else {
+            if (dio_GetPos() < dio_gEntryPos + EntrySize) {
+		Attr = dio_ReadU2();
+		Form = Attr & 0xF;
+		Attr = (Attr & 0xfff0) >> 4;
+            }
+	}
+        if (Attr != 0 && Form != 0) dio_ReadAttribute(Attr, Form);
+        if (Tag == TAG_compile_unit) {
+            if (Attr == AT_sibling && dio_gUnitSize == 0) {
+                dio_ChkRef(Form);
+                assert(dio_gVersion == 1);
+                dio_gUnitSize = (U4_T)(dio_gFormRef - dio_gUnitPos);
+                assert(dio_gUnitPos < dio_GetPos());
+                assert(dio_gUnitPos + dio_gUnitSize >= dio_GetPos());
+            }
+            else if (Attr == 0 && Form == 0) {
+                if (dio_gUnitSize == 0) str_exception(ERR_DWARF, "missing compilation unit sibling attribute");
+            }
+        }
+        CallBack(Tag, Attr, Form);
+        if (Attr == 0 && Form == 0) break;
+    }
+}
+
+static void dio_FindAbbrevTable(U4_T Offset, DIO_Abbreviation *** AbbrevTable, U4_T * AbbrevTableSize);
+
+void dio_ReadUnit(DIO_EntryCallBack CallBack) {
+    dio_gUnitPos = dio_GetPos();
+    dio_g64bit = 0;
+    if (dio_gVersion >= 2) {
+        dio_gUnitSize = dio_ReadU4();
+        if (dio_gUnitSize == 0xffffffffu) {
+            dio_g64bit = 1;
+            str_exception(ERR_DWARF, "64-bit DWARF is not supported yet");
+        }
+        else {
+            dio_gUnitSize += 4;
+        }
+        dio_gVersion = dio_ReadU2();
+        dio_FindAbbrevTable(dio_ReadU4(), &sAbbrevTable, &sAbbrevTableSize);
+        dio_gAddressSize = dio_ReadU1();
+    }
+    else {
+        dio_gUnitSize = 0;
+        dio_gVersion = 1;
+        dio_gAddressSize = 4;
+        sAbbrevTable = NULL;
+        sAbbrevTableSize = 0;
+    }
+    while (dio_gUnitSize == 0 || dio_GetPos() < dio_gUnitPos + dio_gUnitSize) {
+        dio_ReadEntry(CallBack);
+    }
+}
+
+#define dio_AbbrevTableHash(File, Offset) (((int)(File) + (int)(Offset)) / 4 % ABBREV_TABLE_SIZE)
+
+static int dio_IsAbbrevSectionLoaded(ELF_File * File) {
+    DIO_Cache * Cache = dio_GetCache(File);
+    
+    if (Cache->mAbbrevTable != NULL) {
+        U4_T Hash = dio_AbbrevTableHash(File, 0);
+        DIO_AbbrevSet * AbbrevSet = Cache->mAbbrevTable[Hash];
+        while (AbbrevSet != NULL) {
+            if (AbbrevSet->mFile == File) return 1;
+            AbbrevSet = AbbrevSet->mNext;
+        }
+    }
+    return 0;
+}
+
+void dio_LoadAbbrevTable(ELF_File * File) {
+    U4_T ID;
+    U8_T TableOffset = 0;
+    ELF_Section * Section = NULL;
+    static U2_T * AttrBuf = NULL;
+    static U4_T AttrBufSize = 0;
+    DIO_Abbreviation ** AbbrevTable = NULL;
+    U4_T AbbrevTableSize = 0;
+    DIO_Cache * Cache = dio_GetCache(File);
+
+    if (dio_IsAbbrevSectionLoaded(File)) return;
+
+    assert(sSection == NULL);
+    for (ID = 1; ID < File->section_cnt; ID++) {
+        if (strcmp(File->sections[ID]->name, ".debug_abbrev") == 0) {
+            if (Section != NULL) {
+                str_exception(ERR_DWARF, "more then one .debug_abbrev section in a file");
+            }
+            Section = File->sections[ID];
+        }
+    }
+    if (Section == NULL) return;
+    dio_EnterSection(Section, 0);
+    for (;;) {
+	U4_T AttrPos = 0;
+        U2_T Tag = 0;
+        U1_T Children = 0;
+	U4_T ID = dio_ReadLEB128();
+        if (ID == 0) {
+            /* End of compilation unit */
+            U4_T Hash = dio_AbbrevTableHash(File, TableOffset);
+            DIO_AbbrevSet * AbbrevSet = (DIO_AbbrevSet *)loc_alloc_zero(sizeof(DIO_AbbrevSet));
+            AbbrevSet->mFile = File;
+            AbbrevSet->mOffset = TableOffset;
+            AbbrevSet->mTable = AbbrevTable;
+            AbbrevSet->mSize = AbbrevTableSize;
+            if (Cache->mAbbrevTable == NULL) {
+                Cache->mAbbrevTable = (DIO_AbbrevSet **)loc_alloc_zero(sizeof(DIO_AbbrevSet *) * ABBREV_TABLE_SIZE);
+            }
+            AbbrevSet->mNext = Cache->mAbbrevTable[Hash];
+            Cache->mAbbrevTable[Hash] = AbbrevSet;
+            AbbrevTable = NULL;
+            AbbrevTableSize = 0;
+            if (dio_GetPos() >= Section->size) break;
+            TableOffset = dio_GetPos();
+            continue;
+        }
+	if (ID >= 0x1000000) str_exception(ERR_DWARF, "invalid abbreviation table");
+	if (ID >= AbbrevTableSize) {
+            U4_T Size = AbbrevTableSize;
+	    AbbrevTableSize = ID + 1024u;
+	    AbbrevTable = (DIO_Abbreviation **)loc_realloc(AbbrevTable, sizeof(DIO_Abbreviation *) * AbbrevTableSize);
+            memset(AbbrevTable + Size, 0, sizeof(DIO_Abbreviation *) * (AbbrevTableSize - Size));
+	}
+	Tag = (U2_T)dio_ReadLEB128();
+	Children = (U2_T)dio_ReadU1() != 0;
+	for (;;) {
+	    U4_T Attr = dio_ReadLEB128();
+	    U4_T Form = dio_ReadLEB128();
+            if (Attr >= 0x10000 || Form >= 0x10000) str_exception(ERR_DWARF, "invalid abbreviation table");
+	    if (Attr == 0 && Form == 0) {
+                DIO_Abbreviation * Abbr = AbbrevTable[ID];
+                assert(Abbr == NULL);
+                Abbr = (DIO_Abbreviation *)loc_alloc_zero(sizeof(DIO_Abbreviation) + sizeof(U2_T) * (AttrPos - 2));
+                Abbr->mTag = Tag;
+                Abbr->mChildren = Children;
+                Abbr->mAttrLen = AttrPos;
+                memcpy(Abbr->mAttrs, AttrBuf, sizeof(U2_T) * AttrPos);
+                AbbrevTable[ID] = Abbr;
+		break;
+	    }
+	    if (AttrBufSize < AttrPos + 2) {
+		AttrBufSize = AttrPos + 256;
+		AttrBuf = (U2_T *)loc_realloc(AttrBuf, sizeof(U2_T) * AttrBufSize);
+	    }
+	    AttrBuf[AttrPos++] = (U2_T)Attr;
+	    AttrBuf[AttrPos++] = (U2_T)Form;
+	}
+    }
+    assert(AbbrevTable == NULL);
+    assert(AbbrevTableSize == 0);
+    dio_ExitSection();
+}
+
+static void dio_FindAbbrevTable(U4_T Offset, DIO_Abbreviation *** AbbrevTable, U4_T * AbbrevTableSize) {
+    DIO_Cache * Cache = dio_GetCache(sSection->file);
+    if (Cache->mAbbrevTable != NULL) {
+        U4_T Hash = dio_AbbrevTableHash(sSection->file, Offset);
+        DIO_AbbrevSet * AbbrevSet = Cache->mAbbrevTable[Hash];
+        while (AbbrevSet != NULL) {
+            if (AbbrevSet->mFile == sSection->file && AbbrevSet->mOffset == Offset) {
+                *AbbrevTable = AbbrevSet->mTable;
+                *AbbrevTableSize = AbbrevSet->mSize;
+                return;
+            }
+            AbbrevSet = AbbrevSet->mNext;
+        }
+    }
+    str_exception(ERR_DWARF, "invalid abbreviation table offset");
+    *AbbrevTable = NULL;
+    *AbbrevTableSize = 0;
+}
+
+void dio_ChkFlag(U2_T Form) {
+    switch (Form) {
+    case FORM_FLAG      :
+	return;
+    }
+    str_exception(ERR_DWARF, "FORM_FLAG expected");
+}
+
+void dio_ChkRef(U2_T Form) {
+    switch (Form) {
+    case FORM_REF       :
+    case FORM_REF_ADDR  :
+    case FORM_REF1      :
+    case FORM_REF2      :
+    case FORM_REF4      :
+    case FORM_REF8      :
+    case FORM_REF_UDATA :
+	return;
+    }
+    str_exception(ERR_DWARF, "FORM_REF* expected");
+}
+
+void dio_ChkAddr(U2_T Form) {
+    switch (Form) {
+    case FORM_ADDR      :
+	return;
+    }
+    str_exception(ERR_DWARF, "FORM_ADDR expected");
+}
+
+void dio_ChkData(U2_T Form) {
+    switch (Form) {
+    case FORM_DATA1     :
+    case FORM_DATA2     :
+    case FORM_DATA4     :
+    case FORM_DATA8     :
+    case FORM_SDATA     :
+    case FORM_UDATA     :
+	return;
+    }
+    str_exception(ERR_DWARF, "FORM_DATA* expected");
+}
+
+void dio_ChkBlock(U2_T Form, U1_T ** Buf, U4_T * Size) {
+    switch (Form) {
+    case FORM_BLOCK1    :
+    case FORM_BLOCK2    :
+    case FORM_BLOCK4    :
+    case FORM_BLOCK     :
+        *Size = dio_gFormBlockSize;
+        *Buf = dio_gFormBlockBuf;
+        break;
+    case FORM_DATA1     :
+    case FORM_DATA2     :
+    case FORM_DATA4     :
+    case FORM_DATA8     :
+    case FORM_SDATA     :
+    case FORM_UDATA     :
+        *Size = dio_gFormDataSize;
+        *Buf = (U1_T *)&dio_gFormData;
+        break;
+    default:
+        str_exception(ERR_DWARF, "FORM_BLOCK expected");
+    }
+}
+
+void dio_ChkString(U2_T Form) {
+    if (Form == FORM_STRING) return;
+    if (Form == FORM_STRP) return;
+    str_exception(ERR_DWARF, "FORM_STRING expected");
+}
+
+#endif
diff --git a/dwarfio.h b/dwarfio.h
new file mode 100644
index 0000000..395c08f
--- /dev/null
+++ b/dwarfio.h
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements low-level functions for reading DWARF debug information.
+ *
+ * Functions in this module use exceptions to report errors, see exceptions.h
+ */
+#ifndef D_dwarfio
+#define D_dwarfio
+
+#include "elf.h"
+
+extern U4_T dio_gVersion;
+extern U1_T dio_g64bit;
+extern U1_T dio_gAddressSize;
+extern U8_T dio_gUnitPos;
+extern U4_T dio_gUnitSize;
+extern U8_T dio_gEntryPos;
+
+extern U8_T dio_gFormRef;
+extern U8_T dio_gFormData;
+extern U1_T dio_gFormDataSize;
+extern U1_T * dio_gFormBlockBuf;
+extern U4_T dio_gFormBlockSize;
+
+extern void dio_EnterSection(ELF_Section * Section, U8_T Offset);
+extern void dio_ExitSection(void);
+
+extern void dio_Skip(U8_T Bytes);
+extern void dio_Read(U1_T * Buf, U4_T Size);
+extern U8_T dio_GetPos(void);
+
+extern U1_T dio_ReadU1(void);
+extern U2_T dio_ReadU2(void);
+extern U4_T dio_ReadU4(void);
+extern U8_T dio_ReadU8(void);
+
+extern U4_T dio_ReadLEB128(void);
+extern U8_T dio_ReadU8LEB128(void);
+extern I8_T dio_ReadI8LEB128(void);
+
+extern U8_T dio_ReadUX(int Size);
+extern U8_T dio_ReadAddress(void);
+
+extern char * dio_ReadString(void);
+
+extern U8_T dio_ReadAddrBuf(U1_T * Buf);
+
+typedef void (*DIO_EntryCallBack)(U2_T /* Tag */, U2_T /* Attr */, U2_T /* Form */);
+/*
+ * CallBack is called berore each DWARF entry with Atrr = 0 and Form = 1,
+ * then is is called for each entry attribute with appropriate Attr and Form values,
+ * and then called after the entry with Attr = 0 and Form = 0.
+ * This sequence is repeated for each entry in the debug info unit.
+ */
+extern void dio_ReadUnit(DIO_EntryCallBack CallBack);
+
+extern void dio_LoadAbbrevTable(ELF_File * File);
+
+extern void dio_ChkFlag(U2_T Form);
+extern void dio_ChkRef(U2_T Form);
+extern void dio_ChkAddr(U2_T Form);
+extern void dio_ChkData(U2_T Form);
+extern void dio_ChkBlock(U2_T Form, U1_T ** Buf, U4_T * Size);
+extern void dio_ChkString(U2_T Form);
+
+#endif
+
diff --git a/elf.c b/elf.c
new file mode 100644
index 0000000..8476ca8
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements reading and caching of ELF files.
+ */
+#include "config.h"
+#if SERVICE_LineNumbers || SERVICE_Symbols
+
+#include <assert.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "elf.h"
+#include "myalloc.h"
+
+#if defined(_WRS_KERNEL)
+#elif defined(WIN32)
+#else
+#  include <libelf.h>
+#  define USE_LIBELF
+#endif
+
+#define MAX_CACHED_FILES 8
+
+static ELF_File * files = NULL;
+static ELFCloseListener * listeners = NULL;
+static U4_T listeners_cnt = 0;
+static U4_T listeners_max = 0;
+
+static void elf_dispose(ELF_File * file) {
+    U4_T n;
+    assert(file->ref_cnt == 0);
+    for (n = 0; n < listeners_cnt; n++) {
+        listeners[n](file);
+    }
+#ifdef USE_LIBELF
+    if (file->libelf_cache != NULL) elf_end(file->libelf_cache);
+#endif
+    if (file->fd >= 0) close(file->fd);
+    if (file->sections != NULL) {
+        for (n = 0; n < file->section_cnt; n++) {
+            loc_free(file->sections[n]);
+        }
+        loc_free(file->sections);
+    }
+    free(file->name);
+    loc_free(file);
+}
+
+ELF_File * elf_open(char * file_name) {
+    int cnt = 0;
+    int error = 0;
+    struct_stat st;
+    ELF_File * prev = NULL;
+    ELF_File * file = files;
+
+    file_name = canonicalize_file_name(file_name);
+    if (file_name == NULL) return NULL;
+    if (stat(file_name, &st) < 0) {
+        error = errno;
+        free(file_name);
+        errno = error;
+        return NULL;
+    }
+    while (file != NULL) {
+        if (strcmp(file->name, file_name) == 0 &&
+                file->dev == st.st_dev &&
+                file->ino == st.st_ino &&
+                file->mtime == st.st_mtime) {
+            if (prev != NULL) {
+                prev->next = file->next;
+                file->next = files;
+                files = file;
+            }
+            file->ref_cnt++;
+            free(file_name);
+            return file;
+        }
+        if (cnt >= MAX_CACHED_FILES && file->ref_cnt == 0) {
+            prev->next = file->next;
+            elf_dispose(file);
+            file = prev->next;
+        }
+        else {
+            prev = file;
+            file = file->next;
+            cnt++;
+        }
+    }
+
+    file = (ELF_File *)loc_alloc_zero(sizeof(ELF_File));
+    file->name = file_name;
+    file->dev = st.st_dev;
+    file->ino = st.st_ino;
+    file->mtime = st.st_mtime;
+#ifdef _WRS_KERNEL
+    if ((file->fd = open(file->name, O_RDONLY, 0)) < 0) {
+#else        
+    if ((file->fd = open(file->name, O_RDONLY)) < 0) {
+#endif
+        error = errno;
+    }
+
+#ifdef USE_LIBELF
+    if (error == 0) {
+        Elf * elf;
+        Elf32_Ehdr * ehdr;
+        /* Obtain the ELF descriptor */
+        (void)elf_version(EV_CURRENT);
+        if ((elf = elf_begin(file->fd, ELF_C_READ, NULL)) == NULL) {
+            error = errno;
+        }
+        else {
+            file->libelf_cache = elf;
+            if ((ehdr = elf32_getehdr(elf)) == NULL) {
+                error = errno;
+            }
+        }
+        if (error == 0) {
+            size_t snum = 0;
+            size_t shstrndx = 0;
+            if (elf_getshnum(elf, &snum) < 0) error = errno;
+            if (error == 0) {
+                file->sections = (ELF_Section **)loc_alloc_zero(sizeof(ELF_Section *) * snum);
+                file->section_cnt = snum;
+                if (elf_getshstrndx(elf, &shstrndx) < 0) error = errno;
+            }
+            if (error == 0) {
+                /* Iterate sections */
+                Elf_Scn * scn = NULL;
+                while ((scn = elf_nextscn(elf, scn)) != NULL) {
+                    Elf32_Shdr * shdr = NULL;
+                    char * name = NULL;
+                    ELF_Section * sec = NULL;
+                    if ((shdr = elf32_getshdr(scn)) == NULL) {
+                        error = errno;
+                        break;
+                    }
+                    if ((name = elf_strptr(elf, shstrndx, shdr->sh_name)) == NULL) {
+                        error = errno;
+                        break;
+                    }
+                    sec = (ELF_Section *)loc_alloc(sizeof(ELF_Section));
+                    sec->file = file;
+                    sec->index = elf_ndxscn(scn);
+                    sec->name = name;
+                    sec->type = shdr->sh_type;
+                    sec->offset = shdr->sh_offset;
+                    sec->size = shdr->sh_size;
+                    sec->flags = shdr->sh_flags;
+                    sec->addr = shdr->sh_addr;
+                    sec->link = shdr->sh_link;
+                    sec->info = shdr->sh_info;
+                    assert(sec->index < snum);
+                    file->sections[sec->index] = sec;
+                }
+            }
+        }
+    }
+#else
+    if (error == 0) {
+        error = EINVAL;
+    }
+#endif
+    if (error != 0) {
+        elf_dispose(file);
+        errno = error;
+        return NULL;
+    }
+    file->ref_cnt = 1;
+    file->next = files;
+    return files = file;
+}
+
+int elf_load(ELF_Section * section, U1_T ** address) {
+#ifdef USE_LIBELF
+    Elf * elf = (Elf *)section->file->libelf_cache;
+    Elf_Scn * scn = elf_getscn(elf, section->index);
+    Elf_Data * data = elf_getdata(scn, NULL);
+    if (data == NULL) return -1;
+    assert(data->d_buf != NULL && data->d_size == section->size);
+    *address = data->d_buf;
+    return 0;
+#else
+    *address = NULL;
+    errno = EINVAL;
+    return -1;
+#endif
+}
+
+int elf_read(ELF_Section * section, U8_T offset, U1_T * buf, U4_T size, U4_T * rd_len) {
+#ifdef USE_LIBELF
+    U4_T rd = size;
+    Elf * elf = (Elf *)section->file->libelf_cache;
+    Elf_Scn * scn = elf_getscn(elf, section->index);
+    Elf_Data * data = elf_getdata(scn, NULL);
+    if (data == NULL) return -1;
+    assert(data->d_buf != NULL && data->d_size == section->size);
+    assert(offset < section->size);
+    if (offset + rd > section->size) rd = (U4_T)(section->size - offset);
+    memcpy(buf, data->d_buf + offset, rd);
+    *rd_len = rd;
+    return 0;
+#else
+    *rd_len = 0;
+    errno = EINVAL;
+    return -1;
+#endif
+}
+
+void elf_close(ELF_File * file) {
+    assert(file != NULL);
+    assert(file->ref_cnt > 0);
+    file->ref_cnt--;
+}
+
+void elf_add_close_listener(ELFCloseListener listener) {
+    if (listeners_cnt >= listeners_max) {
+        listeners_max = listeners_max == 0 ? 16 : listeners_max * 2;
+        listeners = (ELFCloseListener *)loc_realloc(listeners, sizeof(ELFCloseListener) * listeners_max);
+    }
+    listeners[listeners_cnt++] = listener;
+}
+
+#endif
diff --git a/elf.h b/elf.h
new file mode 100644
index 0000000..dc39a08
--- /dev/null
+++ b/elf.h
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements reading and caching of ELF files.
+ */
+#ifndef D_elf
+#define D_elf
+
+#include <sys/types.h>
+#if defined(WIN32)
+#else
+#  include <elf.h>
+#endif
+#include "mdep.h"
+
+typedef unsigned char U1_T;
+typedef signed char I1_T;
+typedef unsigned short U2_T;
+typedef signed short I2_T;
+typedef unsigned int U4_T;
+typedef signed int I4_T;
+typedef uns64 U8_T;
+typedef int64 I8_T;
+
+struct ELF_File;
+struct ELF_Section;
+typedef struct ELF_Section ELF_Section;
+typedef struct ELF_File ELF_File;
+
+struct ELF_File {
+    ELF_File * next;
+    U4_T ref_cnt;
+
+    char * name;
+    dev_t dev;
+    ino_t ino;
+    time_t mtime;
+    int fd;
+
+    int big_endian;
+    U4_T section_cnt;
+    ELF_Section ** sections;
+
+    void * libelf_cache;
+    void * dwarf_cache;
+    void * sym_cache;
+    void * line_numbers_cache;
+};
+
+struct ELF_Section {
+    ELF_File * file;
+    U4_T index;
+    char * name;
+    U4_T type;
+    U4_T flags;
+    U8_T offset;
+    U8_T size;
+    U8_T addr;
+    U4_T link;
+    U4_T info;     
+};
+
+/*
+ * Open ELF file for reading.
+ * Same file can be opened mutiple times, each call to elf_open() increases reference counter.
+ * File must be closed after usage by calling elf_close().
+ * Returns the file descriptior on success. If error, returns NULL and sets errno.
+ */
+extern ELF_File * elf_open(char * file_name);
+
+/*
+ * Read section data from ELF file.
+ * '*rd_len' is set to number of bytes transfered into the buffer.
+ * Returns zero on success. If error, returns -1 and sets errno.
+ */
+extern int elf_read(ELF_Section * section, U8_T offset, U1_T * buf, U4_T size, U4_T * rd_len);
+
+/*
+ * Load section data into memory.
+ * '*address' is set to section data address in memory.
+ * Data will stay in memory at least until file is closed.
+ * Returns zero on success. If error, returns -1 and sets errno.
+ */
+extern int elf_load(ELF_Section * section, U1_T ** address);
+
+/*
+ * Close ELF file.
+ * Each call of elf_close() decrements reference counter.
+ * The file be kept in cache for some time even after all references are closed.
+ */
+extern void elf_close(ELF_File * file);
+
+/*
+ * Register ELF file close callback.
+ * The callback is called each time an ELF file data is about to be disposed.
+ * Service implementation can use the callback to deallocate
+ * cached data related to the file.
+ */
+typedef void (*ELFCloseListener)(ELF_File *);
+extern void elf_add_close_listener(ELFCloseListener listener);
+
+#endif
+
diff --git a/errors.c b/errors.c
new file mode 100644
index 0000000..691f9be
--- /dev/null
+++ b/errors.c
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module defines agent error codes in addition to system codes defined in errno.h
+ */
+
+#include <string.h>
+#include "errors.h"
+
+char * errno_to_str(int err) {
+    switch (err) {
+    case ERR_ALREADY_STOPPED:
+        return "Already stopped";
+    case ERR_ALREADY_EXITED:
+        return "Already exited";
+    case ERR_ALREADY_RUNNING:
+        return "Already running";
+    case ERR_JSON_SYNTAX:
+        return "JSON syntax error";
+    case ERR_PROTOCOL:
+        return "Protocol format error";
+    case ERR_INV_CONTEXT:
+        return "Invalid context ID";
+    case ERR_INV_ADDRESS:
+        return "Invalid address";
+    case ERR_EOF:
+        return "End of file";
+    case ERR_BASE64:
+        return "Invalid BASE64 string";
+    case ERR_INV_EXPRESSION:
+        return "Invalid expression";
+    case ERR_SYM_NOT_FOUND:
+        return "Symbol not found";
+    case ERR_ALREADY_ATTACHED:
+        return "Already attached";
+    case ERR_BUFFER_OVERFLOW:
+        return "Buffer overflow";
+    case ERR_INV_FORMAT:
+        return "Format is not supported";
+    case ERR_INV_NUMBER:
+        return "Invalid number";
+    case ERR_IS_RUNNING:
+        return "Execution context is running";
+    case ERR_DWARF:
+        return "Error reading DWARF data";
+    default:
+        return strerror(err);
+    }
+}
diff --git a/errors.h b/errors.h
new file mode 100644
index 0000000..f7e8f67
--- /dev/null
+++ b/errors.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module defines agent error codes in addition to system codes defined in errno.h
+ */
+
+#ifndef D_errors
+#define D_errors
+
+#include <errno.h>
+
+#define ERR_ALREADY_STOPPED     0x1000
+#define ERR_ALREADY_EXITED      0x1001
+#define ERR_ALREADY_RUNNING     0x1002
+#define ERR_JSON_SYNTAX         0x1003
+#define ERR_PROTOCOL            0x1004
+#define ERR_INV_CONTEXT         0x1005
+#define ERR_INV_ADDRESS         0x1006
+#define ERR_EOF                 0x1007
+#define ERR_BASE64              0x1008
+#define ERR_INV_EXPRESSION      0x1009
+#define ERR_SYM_NOT_FOUND       0x100a
+#define ERR_ALREADY_ATTACHED    0x100b
+#define ERR_BUFFER_OVERFLOW     0x100c
+#define ERR_INV_FORMAT          0x100d
+#define ERR_INV_NUMBER          0x100e
+#define ERR_IS_RUNNING          0x100f
+#define ERR_DWARF               0x1010
+
+extern char * errno_to_str(int err);
+
+#endif
diff --git a/events.c b/events.c
new file mode 100644
index 0000000..d29f102
--- /dev/null
+++ b/events.c
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Event queue manager.
+ * Event is a data pointer plus a function pointer (a.k.a. event handler).
+ *
+ * Posting event means placing event into event queue.
+ * Dispatching event means removing event from the queue and then calling
+ * event function with event data as argument.
+ *
+ * All events are dispatched by single thread - dispatch thread. This makes it safe
+ * to access global data structures from event handlers without further synchronization,
+ * while allows for high level of concurrency.
+ */
+
+#include <time.h>
+#include <assert.h>
+#include "mdep.h"
+#include "myalloc.h"
+#include "trace.h"
+#include "events.h"
+
+typedef struct event_node event_node;
+
+struct event_node {
+    event_node *        next;
+    struct timespec     runtime;
+    void                (*handler)(void *);
+    void                *arg;
+};
+
+pthread_t event_thread = 0;
+
+static pthread_mutex_t event_lock;
+static pthread_cond_t event_cond;
+
+static event_node * event_queue = NULL;
+static event_node * event_last = NULL;
+static event_node * timer_queue = NULL;
+static event_node * free_queue = NULL;
+static int free_queue_size = 0;
+
+static int time_cmp(const struct timespec *tv1, const struct timespec *tv2) {
+    if (tv1->tv_sec < tv2->tv_sec) return -1;
+    if (tv1->tv_sec > tv2->tv_sec) return 1;
+    if (tv1->tv_nsec < tv2->tv_nsec) return -1;
+    if (tv1->tv_nsec > tv2->tv_nsec) return 1;
+    return 0;
+}
+
+/*
+ * Add microsecond value to timeval.
+ */
+static void time_add_usec(struct timespec *tv, unsigned long usec) {
+    tv->tv_sec += usec / 1000000;
+    tv->tv_nsec += (usec % 1000000) * 1000;
+    if (tv->tv_nsec >= 1000000000) {
+        tv->tv_sec++;
+        tv->tv_nsec -= 1000000000;
+    }
+}
+
+static event_node * alloc_node(void (*handler)(void *), void *arg) {
+    event_node * node;
+    if (free_queue != NULL) {
+        node = free_queue;
+        free_queue = node->next;
+        free_queue_size--;
+    }
+    else {
+        node = (event_node *)loc_alloc(sizeof(event_node));
+    }
+    memset(node, 0, sizeof(event_node));
+    node->handler = handler;
+    node->arg = arg;
+    return node;
+}
+
+static void free_node(event_node * node) {
+    if (free_queue_size < 500) {
+        node->next = free_queue;
+        free_queue = node;
+        free_queue_size++;
+    }
+    else {
+        loc_free(node);
+    }
+}
+
+void post_event_with_delay(void (*handler)(void *), void *arg, unsigned long delay) {
+    event_node * ev;
+    event_node * qp;
+    event_node ** qpp;
+
+    pthread_mutex_lock(&event_lock);
+    ev = alloc_node(handler, arg);
+    if (clock_gettime(CLOCK_REALTIME, &ev->runtime)) {
+        perror("clock_gettime");
+        exit(1);
+    }
+    time_add_usec(&ev->runtime, delay);
+
+    qpp = &timer_queue;
+    while ((qp = *qpp) != 0 && time_cmp(&ev->runtime, &qp->runtime) >= 0) {
+        qpp = &qp->next;
+    }
+    ev->next = qp;
+    *qpp = ev;
+    if (timer_queue == ev) {
+        pthread_cond_signal(&event_cond);
+    }
+    trace(LOG_EVENTCORE, "post_event: event %#x handler %#x arg %#x runtime %02d%02d.%03d",
+        ev, ev->handler, ev->arg, ev->runtime.tv_sec/60%60, ev->runtime.tv_sec%60, ev->runtime.tv_nsec/1000000);
+    pthread_mutex_unlock(&event_lock);
+}
+
+void post_event(void (*handler)(void *), void *arg) {
+    event_node * ev;
+
+    pthread_mutex_lock(&event_lock);
+    ev = alloc_node(handler, arg);
+
+    if (event_queue == NULL) {
+        assert(event_last == NULL);
+        event_last = event_queue = ev;
+        pthread_cond_signal(&event_cond);
+    }
+    else {
+        event_last->next = ev;
+        event_last = ev;
+    }
+    trace(LOG_EVENTCORE, "post_event: event %#x handler %#x arg %#x", ev, ev->handler, ev->arg);
+    pthread_mutex_unlock(&event_lock);
+}
+
+int is_dispatch_thread(void) {
+    return event_thread == pthread_self();
+}
+
+void ini_events_queue(void) {
+    /* Initial thread is event dispatcher. */
+    event_thread = pthread_self();
+    pthread_mutex_init(&event_lock, NULL);
+    pthread_cond_init(&event_cond, NULL);
+}
+
+void run_event_loop(void) {
+    assert(is_dispatch_thread());
+    pthread_mutex_lock(&event_lock);
+    for (;;) {
+        event_node * ev = NULL;
+        if (event_queue != NULL) {
+            ev = event_queue;
+            event_queue = ev->next;
+            if (event_queue == NULL) {
+                assert(event_last == ev);
+                event_last = NULL;
+            }
+        }
+        else if (timer_queue != NULL) {
+            struct timespec timenow;
+            if (clock_gettime(CLOCK_REALTIME, &timenow)) {
+                perror("clock_gettime");
+                exit(1);
+            }
+            ev = timer_queue;
+            if (time_cmp(&timer_queue->runtime, &timenow) > 0) {
+                pthread_cond_timedwait(&event_cond, &event_lock, &ev->runtime);
+                continue;
+            }
+            timer_queue = ev->next;
+        }
+        else {
+            pthread_cond_wait(&event_cond, &event_lock);
+            continue;
+        }
+
+        pthread_mutex_unlock(&event_lock);
+        trace(LOG_EVENTCORE, "run_event_loop: event %#x handler %#x arg %#x", ev, ev->handler, ev->arg);
+        ev->handler(ev->arg);
+        pthread_mutex_lock(&event_lock);
+        free_node(ev);
+    }
+}
+
diff --git a/events.h b/events.h
new file mode 100644
index 0000000..d54ba01
--- /dev/null
+++ b/events.h
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Event queue manager.
+ * Event is a data pointer plus a function pointer (a.k.a. event handler).
+ *
+ * Posting event means placing event into event queue.
+ * Dispatching event means removing event from the queue and then calling
+ * event function with event data as argument.
+ *
+ * All events are dispatched by single thread - dispatch thread. This makes it safe
+ * to access global data structures from event handlers without further synchronization,
+ * while allows for high level of concurrency.
+ */
+
+#ifndef D_events
+#define D_events
+
+extern void post_event(void (*handler)(void *), void *arg);
+extern void post_event_with_delay(void (*handler)(void *), void *arg, unsigned long us_delay);
+
+extern int is_dispatch_thread(void);
+
+extern void run_event_loop(void);
+
+extern void ini_events_queue(void);
+
+#endif
diff --git a/exceptions.c b/exceptions.c
new file mode 100644
index 0000000..f991007
--- /dev/null
+++ b/exceptions.c
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Exception handling. Functionality is similar to C++ try/catch.
+ * Usage example:
+    Trap trap;
+    if (set_trap(&trap)) {
+        // Some code that can throw an exception by calling exception()
+        ...
+
+        clear_trap(&trap);
+    }
+    else {
+        // Exception handling code
+        if (trap.error == ...
+        ...
+    }
+ * Only main thread is allowed to use exceptions.
+ */
+
+#if _WRS_KERNEL
+#  include <vxWorks.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "exceptions.h"
+#include "events.h"
+#include "trace.h"
+
+static Trap * chain = NULL;
+
+int set_trap_a(Trap * trap) {
+    assert(is_dispatch_thread());
+    memset(trap, 0, sizeof(Trap));
+    trap->next = chain;
+    chain = trap;
+    return 0;
+}
+
+int set_trap_b(Trap * trap) {
+    if (trap->error == 0) return 1;
+    assert(trap == chain);
+    chain = trap->next;
+    return 0;
+}
+
+void clear_trap(Trap * trap) {
+    assert(is_dispatch_thread());
+    assert(trap == chain);
+    chain = trap->next;
+}
+
+void exception(int error) {
+    assert(is_dispatch_thread());
+    assert(error != 0);
+    if (chain == NULL) {
+        trace(LOG_ALWAYS, "Unhandled exception %d: %s", error, errno_to_str(error));
+        exit(error);
+    }
+    longjmp(chain->env, error);
+}
+
+void str_exception(int error, char * msg) {
+    assert(is_dispatch_thread());
+    assert(error != 0);
+    if (chain == NULL) {
+        trace(LOG_ALWAYS, "Unhandled exception %d: %s", error, errno_to_str(error));
+        exit(error);
+    }
+    strncpy(chain->msg, msg, sizeof(chain->msg));
+    longjmp(chain->env, error);
+}
+
diff --git a/exceptions.h b/exceptions.h
new file mode 100644
index 0000000..8c2a54f
--- /dev/null
+++ b/exceptions.h
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Exception handling. Functionality is similar to C++ try/catch.
+ * Usage example:
+    Trap trap;
+    if (set_trap(&trap)) {
+        // Some code that can throw an exception by calling exception()
+        ...
+
+        clear_trap(&trap);
+    }
+    else {
+        // Exception handling code
+        if (trap.error == ...
+        ...
+    }
+ * Only main thread is allowed to use exceptions.
+ */
+
+#ifndef D_exceptions
+#define D_exceptions
+
+#include <setjmp.h>
+#include "errors.h"
+
+typedef struct Trap Trap;
+
+struct Trap {
+    int error;
+    char msg[256];
+    jmp_buf env;
+    Trap * next;
+};
+
+#define set_trap(trap) (set_trap_a(trap), (trap)->error = setjmp((trap)->env), set_trap_b(trap))
+
+extern int set_trap_a(Trap * trap);
+extern int set_trap_b(Trap * trap);
+
+extern void clear_trap(Trap * trap);
+extern void exception(int error);
+extern void str_exception(int error, char * msg);
+
+#endif
diff --git a/expressions.c b/expressions.c
new file mode 100644
index 0000000..fa94357
--- /dev/null
+++ b/expressions.c
@@ -0,0 +1,854 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Expression evaluation library.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "mdep.h"
+#include "myalloc.h"
+#include "exceptions.h"
+#include "expressions.h"
+
+#define STR_POOL_SIZE 1024
+
+struct StringValue {
+    struct StringValue * next;
+    char buf[1];
+};
+
+typedef struct StringValue StringValue;
+
+#define SY_LEQ   256
+#define SY_GEQ   257
+#define SY_EQU   258
+#define SY_NEQ   259
+#define SY_AND   260
+#define SY_OR    261
+#define SY_SHL   262
+#define SY_SHR   263
+#define SY_VAL   264
+#define SY_ID    265
+#define SY_REF   266
+#define SY_DEC   267
+#define SY_INC   268
+#define SY_A_SUB 269
+#define SY_A_ADD 270
+#define SY_A_SHL 271
+#define SY_A_SHR 272
+#define SY_A_OR  273
+#define SY_A_XOR 274
+#define SY_A_AND 275
+#define SY_A_MUL 276
+#define SY_A_DIV 277
+#define SY_A_MOD 278
+
+static ExpressionContext * expr_ctx = NULL;
+static char * text = NULL;
+static int text_pos = 0;
+static int text_ch = 0;
+static int text_sy = 0;
+static Value text_val;
+static char text_error[256];
+
+static char str_pool[STR_POOL_SIZE];
+static int str_pool_cnt = 0;
+static StringValue * str_alloc_list = NULL;
+
+static char * alloc_str(int len) {
+    if (str_pool_cnt + len < STR_POOL_SIZE) {
+        char * s = str_pool + str_pool_cnt;
+        str_pool_cnt += len + 1;
+        return s;
+    }
+    else {
+        StringValue * s = (StringValue *)loc_alloc(sizeof(StringValue) + len);
+        s->next = str_alloc_list;
+        str_alloc_list = s;
+        return s->buf;
+    }
+}
+
+void string_value(Value * v, char * str) {
+    memset(v, 0, sizeof(Value));
+    v->type = VALUE_STR;
+    if (str != NULL) {
+        int len = strlen(str);
+        v->str = alloc_str(len);
+        memcpy(v->str, str, len + 1);
+    }
+}
+
+static void error(int no, char * msg) {
+    snprintf(text_error, sizeof(text_error),
+        "Expression evaluation error: %s, text pos %d", msg, text_pos);
+    exception(no);
+}
+
+static void next_ch(void) {
+    text_ch = (unsigned char)text[text_pos];
+    if (text_ch != 0) text_pos++;
+}
+
+static int next_hex(void) {
+    int ch = text_ch;
+    next_ch();
+    if (ch >= '0' && ch <= '9') return ch - '0';
+    if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
+    if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
+    error(ERR_INV_EXPRESSION, "Invalid hexadecimal number");
+    return 0;
+}
+
+static int next_oct(void) {
+    int ch = text_ch;
+    next_ch();
+    if (ch >= '0' && ch <= '7') return ch - '0';
+    error(ERR_INV_EXPRESSION, "Invalid octal number");
+    return 0;
+}
+
+static int next_dec(void) {
+    int ch = text_ch;
+    next_ch();
+    if (ch >= '0' && ch <= '9') return ch - '0';
+    error(ERR_INV_EXPRESSION, "Invalid decimal number");
+    return 0;
+}
+
+static int next_char_val(void) {
+    int n = 0;
+    if (text_ch == '\\') {
+        next_ch();
+        switch (text_ch) {
+        case 'n' : n = '\n'; break;
+        case 't' : n = '\t'; break;
+        case 'v' : n = '\v'; break;
+        case 'b' : n = '\b'; break;
+        case 'r' : n = '\r'; break;
+        case 'f' : n = '\f'; break;
+        case 'a' : n = '\a'; break;
+        case '\\': n = '\\'; break;
+        case '\'': n = '\''; break;
+        case '"' : n = '"'; break;
+        case 'x' :
+            next_ch(); 
+            n = next_hex() << 8;
+            n |= next_hex() << 4;
+            n |= next_hex();
+            return n;
+        case '0' :
+        case '1' :
+        case '2' :
+        case '3' :
+            n = next_oct() << 6;
+            n |= next_oct() << 3;
+            n |= next_oct();
+            return n;
+        default  :
+            n = text_ch;
+            break;
+        }
+    }
+    else {
+        n = text_ch;
+    }
+    next_ch();
+    return n;
+}
+
+static int is_name_character(int ch) {
+    if (ch >= 'A' && ch <= 'Z') return 1;
+    if (ch >= 'a' && ch <= 'z') return 1;
+    if (ch >= '0' && ch <= '9') return 1;
+    if (ch == '_') return 1;
+    if (ch == '$') return 1;
+    if (ch == '@') return 1;
+    return 0;
+}
+
+static void next_sy(void) {
+    for (;;) {
+        int ch = text_ch;
+        next_ch();
+        switch (ch) {
+        case 0:
+            text_sy = 0;
+            return;
+        case ' ':
+        case '\r':
+        case '\n':
+        case '\t':
+            continue;
+        case '(':
+        case ')':
+        case '{':
+        case '}':
+        case '~':
+        case '[':
+        case ']':
+        case ';':
+        case ':':
+        case '?':
+        case ',':
+        case '.':
+            text_sy = ch;
+            return;
+        case '-':
+            if (text_ch == '>') {
+                next_ch();
+                text_sy = SY_REF;
+                return;
+            }
+            if (text_ch == '-') {
+                next_ch();
+                text_sy = SY_DEC;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_SUB;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '+':
+            if (text_ch == '+') {
+                next_ch();
+                text_sy = SY_INC;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_ADD;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '<':
+            if (text_ch == '<') {
+                next_ch();
+                if (text_ch == '=') {
+                    next_ch();
+                    text_sy = SY_A_SHL;
+                    return;
+                }
+                text_sy = SY_SHL;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_LEQ;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '>':
+            if (text_ch == '>') {
+                next_ch();
+                if (text_ch == '=') {
+                    next_ch();
+                    text_sy = SY_A_SHR;
+                    return;
+                }
+                text_sy = SY_SHR;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_GEQ;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '=':
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_EQU;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '!':
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_NEQ;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '&':
+            if (text_ch == '&') {
+                next_ch();
+                text_sy = SY_AND;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_AND;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '|':
+            if (text_ch == '|') {
+                next_ch();
+                text_sy = SY_OR;
+                return;
+            }
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_OR;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '*':
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_MUL;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '/':
+            if (text_ch == '|') {
+                next_ch();
+                text_sy = SY_A_DIV;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '%':
+            if (text_ch == '|') {
+                next_ch();
+                text_sy = SY_A_MOD;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '^':
+            if (text_ch == '=') {
+                next_ch();
+                text_sy = SY_A_XOR;
+                return;
+            }
+            text_sy = ch;
+            return;
+        case '\'':
+            text_val.type = VALUE_UNS;
+            text_val.str = NULL;
+            text_val.value = next_char_val();
+            if (text_ch != '\'') error(ERR_INV_EXPRESSION, "Missing 'single quote'");
+            next_ch();
+            text_sy = SY_VAL;
+            return;
+        case '"':
+            {
+                int len = 0;
+                int cnt = 0;
+                int pos = text_pos;
+                while (text_ch != '"') {
+                    next_char_val();
+                    len++;
+                }
+                text_val.type = VALUE_STR;
+                text_val.value = 0;
+                text_val.str = alloc_str(len);
+                text_pos = pos - 1;
+                next_ch();
+                while (text_ch != '"') {
+                    text_val.str[cnt++] = next_char_val();
+                }
+                assert(cnt == len);
+                text_val.str[cnt] = 0;
+                next_ch();
+                text_sy = SY_VAL;
+            }
+            return;
+        case '0':
+            if (text_ch == 'x') {
+                next_ch();
+                text_val.type = VALUE_UNS;
+                text_val.str = NULL;
+                text_val.value = 0;
+                while (text_ch >= '0' && text_ch <= '9' ||
+                        text_ch >= 'A' && text_ch <= 'F' ||
+                        text_ch >= 'a' && text_ch <= 'f') {
+                    text_val.value = (text_val.value << 4) | next_hex();
+                }
+            }
+            else {
+                text_val.type = VALUE_INT;
+                text_val.str = NULL;
+                text_val.value = 0;
+                while (text_ch >= '0' && text_ch <= '7') {
+                    text_val.value = (text_val.value << 3) | next_oct();
+                }
+            }
+            text_sy = SY_VAL;
+            return;
+        default:
+            if (ch >= '0' && ch <= '9') {
+                text_val.type = VALUE_INT;
+                text_val.str = NULL;
+                text_val.value = ch - '0';
+                while (text_ch >= '0' && text_ch <= '9') {
+                    text_val.value = (text_val.value * 10) + next_dec();
+                }
+                text_sy = SY_VAL;
+                return;
+            }
+            if (is_name_character(ch)) {
+                int len = 1;
+                int cnt = 0;
+                int pos = text_pos - 1;
+                while (is_name_character(text_ch)) {
+                    len++;
+                    next_ch();
+                }
+                text_val.type = VALUE_STR;
+                text_val.value = 0;
+                text_val.str = alloc_str(len);
+                text_pos = pos - 1;
+                next_ch();
+                while (is_name_character(text_ch)) {
+                    text_val.str[cnt++] = text_ch;
+                    next_ch();
+                }
+                assert(cnt == len);
+                text_val.str[cnt] = 0;
+                text_sy = SY_ID;
+                return;
+            }
+            error(ERR_INV_EXPRESSION, "Illegal character");
+            break;
+        }
+    }
+}
+
+static int to_boolean(Value * v) {
+    if (v == NULL) return 0;
+    switch (v->type) {
+    case VALUE_INT: return v->value != 0;
+    case VALUE_UNS: return v->value != 0;
+    case VALUE_STR: return v->str != NULL;
+    default: assert(0);
+    }
+    return 0;
+}
+
+static int to_int(Value * v) {
+    if (v == NULL) return 0;
+    switch (v->type) {
+    case VALUE_INT: return v->value;
+    case VALUE_UNS: return v->value;
+    case VALUE_STR: return v->str != NULL;
+    default: assert(0);
+    }
+    return 0;
+}
+
+static unsigned to_uns(Value * v) {
+    if (v == NULL) return 0;
+    switch (v->type) {
+    case VALUE_INT: return (unsigned)v->value;
+    case VALUE_UNS: return (unsigned)v->value;
+    case VALUE_STR: return v->str != NULL;
+    default: assert(0);
+    }
+    return 0;
+}
+
+static void expression(Value * v);
+
+static void primary_expression(Value * v) {
+    if (text_sy == '(') {
+        next_sy();
+        expression(v);
+        if (text_sy != ')') error(ERR_INV_EXPRESSION, "Missing ')'");
+        next_sy();
+    }
+    else if (text_sy == SY_VAL) {
+        if (v) *v = text_val;
+        next_sy();
+    }
+    else if (text_sy == SY_ID) {
+        errno = 0;
+        if (expr_ctx->identifier == NULL || expr_ctx->identifier(text_val.str, v)) {
+            char msg[256];
+            int err = ERR_INV_EXPRESSION;
+            if (errno != 0) {
+                err = errno;
+                snprintf(msg, sizeof(msg), "Can't evaluate '%s': %d %s",
+                    text_val.str, err, errno_to_str(err));
+            }
+            else {
+                snprintf(msg, sizeof(msg), "Undeclared identifier '%s'", text_val.str);
+            }
+            error(err, msg);
+        }
+        next_sy();
+    }
+    else {
+        error(ERR_INV_EXPRESSION, "Syntax error");
+    }
+}
+
+static void postfix_expression(Value * v) {
+    // TODO: postfix_expression()
+    primary_expression(v);
+}
+
+static void unary_expression(Value * v) {
+    // TODO: unary_expression()
+    postfix_expression(v);
+}
+
+static void cast_expression(Value * v) {
+    // TODO: cast_expression()
+    unary_expression(v);
+}
+
+static void multiplicative_expression(Value * v) {
+    cast_expression(v);
+    while (text_sy == '*' || text_sy == '/' || text_sy == '%') {
+        Value x;
+        int sy = text_sy;
+        next_sy();
+        cast_expression(v ? &x : NULL);
+        if (v) {
+            if (v->type == VALUE_STR || x.type == VALUE_STR) {
+                error(ERR_INV_EXPRESSION, "Operation is not applicable to string");
+            }
+            if (sy != '*' && x.value == 0) {
+                error(ERR_INV_EXPRESSION, "Dividing by zero");
+            }
+            if (v->type == VALUE_UNS || x.type == VALUE_UNS) {
+                switch (sy) {
+                case '*': v->value = to_uns(v) * to_uns(&x); break;
+                case '/': v->value = to_uns(v) / to_uns(&x); break;
+                case '%': v->value = to_uns(v) % to_uns(&x); break;
+                }
+                v->type = VALUE_UNS;
+            }
+            else {
+                switch (sy) {
+                case '*': v->value = to_int(v) * to_int(&x); break;
+                case '/': v->value = to_int(v) / to_int(&x); break;
+                case '%': v->value = to_int(v) % to_int(&x); break;
+                }
+                v->type = VALUE_INT;
+            }
+        }
+    }
+}
+
+static void additive_expression(Value * v) {
+    multiplicative_expression(v);
+    while (text_sy == '+' || text_sy == '-') {
+        Value x;
+        int sy = text_sy;
+        next_sy();
+        multiplicative_expression(v ? &x : NULL);
+        if (v) {
+            if (v->type == VALUE_STR && x.type == VALUE_STR) {
+                char * s;
+                if (sy != '+') error(ERR_INV_EXPRESSION, "Operation is not applicable to string");
+                if (v->str == NULL) {
+                    v->str = x.str;
+                }
+                else if (x.str != NULL) {
+                    s = alloc_str(strlen(v->str) + strlen(x.str));
+                    strcpy(s, v->str);
+                    strcat(s, x.str);
+                    v->str = s;
+                }
+            }
+            else if (v->type == VALUE_STR || x.type == VALUE_STR) {
+                error(ERR_INV_EXPRESSION, "Operation is not applicable to string");
+            }
+            else if (v->type == VALUE_UNS || x.type == VALUE_UNS) {
+                switch (sy) {
+                case '+': v->value = to_uns(v) + to_uns(&x); break;
+                case '-': v->value = to_uns(v) - to_uns(&x); break;
+                }
+                v->type = VALUE_UNS;
+            }
+            else {
+                switch (sy) {
+                case '+': v->value = to_int(v) + to_int(&x); break;
+                case '-': v->value = to_int(v) - to_int(&x); break;
+                }
+                v->type = VALUE_INT;
+            }
+        }
+    }
+}
+
+static void shift_expression(Value * v) {
+    additive_expression(v);
+    while (text_sy == SY_SHL || text_sy == SY_SHR) {
+        Value x;
+        int sy = text_sy;
+        next_sy();
+        additive_expression(v ? &x : NULL);
+        if (v) {
+            if (v->type == VALUE_STR || x.type == VALUE_STR) {
+                error(ERR_INV_EXPRESSION, "Integral types expected");
+            }
+            if (x.type == VALUE_INT && to_int(&x) < 0) {
+                if (v->type == VALUE_UNS) {
+                    switch (sy) {
+                    case SY_SHL: v->value = to_uns(v) >> -to_int(&x); break;
+                    case SY_SHR: v->value = to_uns(v) << -to_int(&x); break;
+                    }
+                }
+                else {
+                    switch (sy) {
+                    case SY_SHL: v->value = to_int(v) >> -to_int(&x); break;
+                    case SY_SHR: v->value = to_int(v) << -to_int(&x); break;
+                    }
+                }
+            }
+            else {
+                if (v->type == VALUE_UNS) {
+                    switch (sy) {
+                    case SY_SHL: v->value = to_uns(v) << to_uns(&x); break;
+                    case SY_SHR: v->value = to_uns(v) >> to_uns(&x); break;
+                    }
+                }
+                else {
+                    switch (sy) {
+                    case SY_SHL: v->value = to_int(v) << to_uns(&x); break;
+                    case SY_SHR: v->value = to_int(v) >> to_uns(&x); break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void relational_expression(Value * v) {
+    shift_expression(v);
+    while (text_sy == '<' || text_sy == '>' || text_sy == SY_LEQ || text_sy == SY_GEQ) {
+        Value x;
+        int sy = text_sy;
+        next_sy();
+        shift_expression(v ? &x : NULL);
+        if (v) {
+            if (v->type == VALUE_STR && x.type == VALUE_STR) {
+                int n = 0;
+                if (v->str == NULL && x.str == NULL) n = 0;
+                else if (v->str == NULL) n = -1;
+                else if (x.str == NULL) n = 1;
+                else n = strcmp(v->str, x.str);
+                switch (sy) {
+                case '<': v->value = n < 0; break;
+                case '>': v->value = n > 0; break;
+                case SY_LEQ: v->value = n <= 0; break;
+                case SY_GEQ: v->value = n >= 0; break;
+                }
+            }
+            else if (v->type == VALUE_UNS || x.type == VALUE_UNS) {
+                switch (sy) {
+                case '<': v->value = to_uns(v) < to_uns(&x); break;
+                case '>': v->value = to_uns(v) > to_uns(&x); break;
+                case SY_LEQ: v->value = to_uns(v) <= to_uns(&x); break;
+                case SY_GEQ: v->value = to_uns(v) >= to_uns(&x); break;
+                }
+            }
+            else {
+                switch (sy) {
+                case '<': v->value = to_int(v) < to_int(&x); break;
+                case '>': v->value = to_int(v) > to_int(&x); break;
+                case SY_LEQ: v->value = to_int(v) <= to_int(&x); break;
+                case SY_GEQ: v->value = to_int(v) >= to_int(&x); break;
+                }
+            }
+            v->str = NULL;
+            v->type = VALUE_INT;
+        }
+    }
+}
+
+static void equality_expression(Value * v) {
+    relational_expression(v);
+    while (text_sy == SY_EQU || text_sy == SY_NEQ) {
+        Value x;
+        int sy = text_sy;
+        next_sy();
+        relational_expression(v ? &x : NULL);
+        if (v) {
+            if (v->type == VALUE_STR && x.type == VALUE_STR) {
+                if (v->str == NULL && x.str == NULL) v->value = 1;
+                else if (v->str == NULL || x.str == NULL) v->value = 0;
+                else v->value = strcmp(v->str, x.str) == 0;
+            }
+            else {
+                v->value = to_int(v) == to_int(&x);
+            }
+            v->str = NULL;
+            v->type = VALUE_INT;
+            if (sy == SY_NEQ) v->value = !v->value;
+        }
+    }
+}
+
+static void and_expression(Value * v) {
+    equality_expression(v);
+    while (text_sy == '&') {
+        Value x;
+        next_sy();
+        equality_expression(v ? &x : NULL);
+        if (v) {
+            v->value = to_int(v) & to_int(&x);
+            v->str = NULL;
+            v->type = v->type == VALUE_UNS || x.type == VALUE_UNS ? VALUE_UNS : VALUE_INT;
+        }
+    }
+}
+
+static void exclusive_or_expression(Value * v) {
+    and_expression(v);
+    while (text_sy == '^') {
+        Value x;
+        next_sy();
+        and_expression(v ? &x : NULL);
+        if (v) {
+            v->value = to_int(v) ^ to_int(&x);
+            v->str = NULL;
+            v->type = v->type == VALUE_UNS || x.type == VALUE_UNS ? VALUE_UNS : VALUE_INT;
+        }
+    }
+}
+
+static void inclusive_or_expression(Value * v) {
+    exclusive_or_expression(v);
+    while (text_sy == '|') {
+        Value x;
+        next_sy();
+        exclusive_or_expression(v ? &x : NULL);
+        if (v) {
+            v->value = to_int(v) | to_int(&x);
+            v->str = NULL;
+            v->type = v->type == VALUE_UNS || x.type == VALUE_UNS ? VALUE_UNS : VALUE_INT;
+        }
+    }
+}
+
+static void logical_and_expression(Value * v) {
+    inclusive_or_expression(v);
+    while (text_sy == SY_AND) {
+        Value x;
+        int b = to_boolean(v);
+        next_sy();
+        inclusive_or_expression(v && b ? &x : NULL);
+        if (v && b) *v = x;
+    }
+}
+
+static void logical_or_expression(Value * v) {
+    logical_and_expression(v);
+    while (text_sy == SY_OR) {
+        Value x;
+        int b = to_boolean(v);
+        next_sy();
+        logical_and_expression(v && !b ? &x : NULL);
+        if (v && !b) *v = x;
+    }
+}
+
+static void conditional_expression(Value * v) {
+    logical_or_expression(v);
+    if (text_sy == '?') {
+        Value x;
+        Value y;
+        int b = to_boolean(v);
+        next_sy();
+        expression(v && b ? &x : NULL);
+        if (text_sy != ':') error(ERR_INV_EXPRESSION, "Missing ':'");
+        next_sy();
+        conditional_expression(v && !b ? &y : NULL);
+        if (v) *v = b ? x : y;
+    }
+}
+
+static void expression(Value * v) {
+    // TODO: assignments in expressions
+    conditional_expression(v);
+}
+
+int evaluate_expression(ExpressionContext * ctx, char * s, Value * v) {
+    int r = 0;
+    Trap trap;
+    if (set_trap(&trap)) {
+        expr_ctx = ctx;
+        text_error[0] = 0;
+        text_val.str = NULL;
+        str_pool_cnt = 0;
+        while (str_alloc_list != NULL) {
+            StringValue * str = str_alloc_list;
+            str_alloc_list = str->next;
+            loc_free(str);
+        }
+        text = s;
+        text_pos = 0;
+        next_ch();
+        next_sy();
+        expression(v);
+        if (text_sy != 0) error(ERR_INV_EXPRESSION, "Illegal characters at the end of expression");
+        clear_trap(&trap);
+    }
+    else {
+        errno = trap.error;
+        r = -1;
+    }
+    return r;
+}
+
+char * get_expression_error_msg(void) {
+    if (text_error[0] == 0) return NULL;
+    return text_error;
+}
+
+void ini_expression_library(void) {
+#ifndef  NDEBUG
+    Value v;
+    ExpressionContext ctx = { NULL, NULL };
+    assert(evaluate_expression(&ctx, "0", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 0 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "0.", &v) != 0);
+    assert(evaluate_expression(&ctx, "2 * 2", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 4 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "1 ? 2 : 3", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 2 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "0 ? 2 : 3", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 3 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "(1?2:3) == 2 && (0?2:3) == 3", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 1 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "(1?2:3) != 2 || (0?2:3) != 3", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 0 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "5>2 && 4<6", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 1 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "5<=2 || 4>=6", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 0 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "((5*2+7-1)/2)>>1==4 && 1<<3==8 && 5%2==1", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 1 && v.str == NULL);
+    assert(evaluate_expression(&ctx, "\042ABC\042 + \042DEF\042 == \042ABCDEF\042", &v) == 0);
+    assert(v.type == VALUE_INT && v.value == 1 && v.str == NULL);
+#endif
+}
+
diff --git a/expressions.h b/expressions.h
new file mode 100644
index 0000000..8fcb43c
--- /dev/null
+++ b/expressions.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Expression evaluation library.
+ */
+
+#ifndef D_expression
+#define D_expression
+
+#define VALUE_INT 1
+#define VALUE_UNS 2
+#define VALUE_STR 3
+
+struct Value {
+    int type;
+    int value;
+    char * str;
+};
+
+typedef struct Value Value;
+
+struct ExpressionContext {
+    int (*identifier)(char *, Value *);
+    int (*type_cast)(char *, Value *);
+};
+
+typedef struct ExpressionContext ExpressionContext;
+
+extern int evaluate_expression(ExpressionContext * ctx, char * s, Value * v);
+
+extern char * get_expression_error_msg(void);
+
+extern void string_value(Value * v, char * str);
+
+extern void ini_expression_library(void);
+
+#endif
+
diff --git a/filesystem.c b/filesystem.c
new file mode 100644
index 0000000..e8dbb28
--- /dev/null
+++ b/filesystem.c
@@ -0,0 +1,1103 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: file system access (TCF name FileSystem)
+ */
+
+#include "config.h"
+#if SERVICE_FileSystem
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#  include <sys/utime.h>
+#  include <direct.h>
+#else
+#  include <utime.h>
+#  include <dirent.h>
+#endif
+#include "mdep.h"
+#include "myalloc.h"
+#include "streams.h"
+#include "channel.h"
+#include "link.h"
+#include "trace.h"
+#include "json.h"
+#include "exceptions.h"
+#include "base64.h"
+#include "protocol.h"
+#include "filesystem.h"
+
+#define BUF_SIZE 0x1000
+
+static const char * FILE_SYSTEM = "FileSystem";
+
+static const int
+    TCF_O_READ              = 0x00000001,
+    TCF_O_WRITE             = 0x00000002,
+    TCF_O_APPEND            = 0x00000004, 
+    TCF_O_CREAT             = 0x00000008,
+    TCF_O_TRUNC             = 0x00000010,
+    TCF_O_EXCL              = 0x00000020;
+
+static const int
+    ATTR_SIZE               = 0x00000001,
+    ATTR_UIDGID             = 0x00000002,
+    ATTR_PERMISSIONS        = 0x00000004,
+    ATTR_ACMODTIME          = 0x00000008;
+
+static const int
+    STATUS_OK = 0,
+    STATUS_EOF = 1,
+    STATUS_NO_SUCH_FILE = 2,
+    STATUS_PERMISSION_DENIED = 3,
+    STATUS_FAILURE = 4,
+    STATUS_BAD_MESSAGE = 5,
+    STATUS_NO_CONNECTION = 6,
+    STATUS_CONNECTION_LOST = 7,
+    STATUS_OP_UNSUPPORTED = 8;
+
+typedef struct OpenFileInfo OpenFileInfo;
+
+struct OpenFileInfo {
+    unsigned long handle;
+    char path[FILE_PATH_SIZE];
+    int file;
+    DIR * dir;
+    InputStream * inp;
+    LINK link_ring;
+    LINK link_hash;
+};
+
+#define hash2file(A)    ((OpenFileInfo *)((char *)(A) - (int)&((OpenFileInfo *)0)->link_hash))
+#define ring2file(A)    ((OpenFileInfo *)((char *)(A) - (int)&((OpenFileInfo *)0)->link_ring))
+
+typedef struct FileAttrs FileAttrs;
+
+struct FileAttrs {
+    int flags;
+    int64 size;
+    int uid;
+    int gid;
+    int permissions;
+    int64 atime;
+    int64 mtime;
+};
+
+static unsigned long handle_cnt = 0;
+
+#define HANDLE_HASH_SIZE 0x1000
+static LINK handle_hash[HANDLE_HASH_SIZE];
+static LINK file_info_ring = { NULL, NULL };
+
+#if defined(_WRS_KERNEL)
+#  define FS_ROOT "host:c:/"    
+#endif
+
+static OpenFileInfo * create_open_file_info(InputStream * inp, char * path, int file, DIR * dir) {
+    int i = 0;
+    LINK * list_head = NULL;
+
+    OpenFileInfo * h = (OpenFileInfo *)loc_alloc_zero(sizeof(OpenFileInfo));
+    for (;;) {
+        LINK * list_next;
+        OpenFileInfo * p = NULL;
+        h->handle = handle_cnt++;
+        list_head = &handle_hash[h->handle % HANDLE_HASH_SIZE];
+        for (list_next = list_head->next; list_next != list_head; list_next = list_next->next) {
+            if (hash2file(list_next)->handle == h->handle) {
+                p = hash2file(list_next);
+                break;
+            }
+        }
+        if (p == NULL) break;
+    }
+    strcpy(h->path, path);
+    h->file = file;
+    h->dir = dir;
+    h->inp = inp;
+    list_add_first(&h->link_ring, &file_info_ring);
+    list_add_first(&h->link_hash, list_head);
+    return h;
+}
+
+static OpenFileInfo * find_open_file_info(char * id) {
+    unsigned long handle = 0;
+    LINK * list_head = NULL;
+    LINK * list_next = NULL;
+
+    if (id == NULL || id[0] != 'F' || id[1] != 'S' || id[2] == 0) return NULL;
+    handle = strtoul(id + 2, &id, 10);
+    if (id[0] != 0) return NULL;
+    list_head = &handle_hash[handle % HANDLE_HASH_SIZE];
+    for (list_next = list_head->next; list_next != list_head; list_next = list_next->next) {
+        if (hash2file(list_next)->handle == handle) return hash2file(list_next);
+    }
+    return NULL;
+}
+
+static void delete_open_file_info(OpenFileInfo * h) {
+    list_remove(&h->link_ring);
+    list_remove(&h->link_hash);
+    loc_free(h);
+}
+
+static void channel_close_listener(InputStream * inp, OutputStream * out) {
+    LINK list;
+    LINK * list_next = NULL;
+
+    list_init(&list);
+    for (list_next = file_info_ring.next; list_next != &file_info_ring; list_next = list_next->next) {
+        OpenFileInfo * h = ring2file(list_next);
+        if (h->inp == inp) {
+            trace(LOG_ALWAYS, "file handle left open by client: FS%d", h->handle);
+            list_remove(&h->link_hash);
+            if (h->dir != NULL) {
+                closedir(h->dir);
+                h->dir = NULL;
+            }
+            if (h->file >= 0) {
+                close(h->file);
+                h->file = -1;
+            }
+            list_add_last(&h->link_hash, &list);
+        }
+    }
+
+    while (!list_is_empty(&list)) delete_open_file_info(hash2file(list.next));
+}
+
+static void write_fs_errno(OutputStream * out, int err) {
+    char * msg = NULL;
+    int status = 0;
+    switch (err) {
+    case 0:
+        status = STATUS_OK;
+        break;
+    case ERR_EOF:
+        status = STATUS_EOF;
+        break;
+    case ENOENT:
+        status = STATUS_NO_SUCH_FILE;
+        break;
+    case EACCES:
+        status = STATUS_PERMISSION_DENIED;
+        break;
+    default:
+        status = STATUS_FAILURE;
+        break;
+    }
+    json_write_long(out, status);
+    out->write(out, 0);
+    if (err != 0) msg = errno_to_str(err);
+    json_write_string(out, msg);
+    out->write(out, 0);
+}
+
+static void write_file_handle(OutputStream * out, OpenFileInfo * h) {
+    if (h == NULL) {
+        write_string(out, "null");
+    }
+    else {
+        char s[32];
+        char * p = s + sizeof(s);
+        unsigned long n = h->handle;
+        *(--p) = 0;
+        do {
+            *(--p) = (char)(n % 10 + '0');
+            n = n / 10;
+        }
+        while (n != 0);
+        *(--p) = 'S';
+        *(--p) = 'F';
+        json_write_string(out, p);
+    }
+    out->write(out, 0);
+}
+
+static void fill_attrs(FileAttrs * attrs, struct_stat * buf) {
+    memset(attrs, 0, sizeof(FileAttrs));
+    attrs->flags |= ATTR_SIZE | ATTR_UIDGID | ATTR_PERMISSIONS | ATTR_ACMODTIME;
+    attrs->size = buf->st_size;
+    attrs->uid = buf->st_uid;
+    attrs->gid = buf->st_gid;
+    attrs->permissions = buf->st_mode;
+    attrs->atime = (int64)buf->st_atime * 1000;
+    attrs->mtime = (int64)buf->st_mtime * 1000;
+}
+
+static void read_file_attrs(InputStream * inp, char * nm, void * arg) {
+    FileAttrs * attrs = (FileAttrs *)arg;
+    if (strcmp(nm, "Size") == 0) {
+        attrs->size = json_read_int64(inp);
+        attrs->flags |= ATTR_SIZE;
+    }
+    else if (strcmp(nm, "UID") == 0) {
+        attrs->uid = (int)json_read_long(inp);
+        attrs->flags |= ATTR_UIDGID;
+    }
+    else if (strcmp(nm, "GID") == 0) {
+        attrs->gid = (int)json_read_long(inp);
+        attrs->flags |= ATTR_UIDGID;
+    }
+    else if (strcmp(nm, "Permissions") == 0) {
+        attrs->permissions = (int)json_read_long(inp);
+        attrs->flags |= ATTR_PERMISSIONS;
+    }
+    else if (strcmp(nm, "ATime") == 0) {
+        attrs->atime = json_read_int64(inp);
+        attrs->flags |= ATTR_ACMODTIME;
+    }
+    else if (strcmp(nm, "MTime") == 0) {
+        attrs->mtime = json_read_int64(inp);
+        attrs->flags |= ATTR_ACMODTIME;
+    }
+    else {
+        exception(ERR_JSON_SYNTAX);
+    }
+}
+
+static void write_file_attrs(OutputStream * out, FileAttrs * attrs) {
+    int cnt = 0;
+
+    if (attrs == NULL) {
+        write_stringz(out, "null");
+        return;
+    }
+
+    out->write(out, '{');
+    if (attrs->flags & ATTR_SIZE) {
+        json_write_string(out, "Size");
+        out->write(out, ':');
+        json_write_int64(out, attrs->size);
+        cnt++;
+    }
+    if (attrs->flags & ATTR_UIDGID) {
+        if (cnt) out->write(out, ',');
+        json_write_string(out, "UID");
+        out->write(out, ':');
+        json_write_long(out, attrs->uid);
+        out->write(out, ',');
+        json_write_string(out, "GID");
+        out->write(out, ':');
+        json_write_long(out, attrs->gid);
+        cnt++;
+    }
+    if (attrs->flags & ATTR_SIZE) {
+        if (cnt) out->write(out, ',');
+        json_write_string(out, "Permissions");
+        out->write(out, ':');
+        json_write_long(out, attrs->permissions);
+        cnt++;
+    }
+    if (attrs->flags & ATTR_ACMODTIME) {
+        if (cnt) out->write(out, ',');
+        json_write_string(out, "ATime");
+        out->write(out, ':');
+        json_write_int64(out, attrs->atime);
+        out->write(out, ',');
+        json_write_string(out, "MTime");
+        out->write(out, ':');
+        json_write_int64(out, attrs->mtime);
+        cnt++;
+    }
+    out->write(out, '}');
+}
+
+static int to_local_open_flags(int flags) {
+    int res = O_BINARY | O_LARGEFILE;
+    if (flags & TCF_O_READ) res |= O_RDONLY;
+    if (flags & TCF_O_WRITE) res |= O_WRONLY;
+    if (flags & TCF_O_APPEND) res |= O_APPEND;
+    if (flags & TCF_O_CREAT) res |= O_CREAT;
+    if (flags & TCF_O_TRUNC) res |= O_TRUNC;
+    if (flags & TCF_O_EXCL) res |= O_EXCL;
+    return res;
+}
+
+static void read_path(InputStream * inp, char * path, int size) {
+    int i = 0;
+    char buf[FILE_PATH_SIZE];
+    json_read_string(inp, path, size);
+    while (path[i] != 0) {
+        if (path[i] == '\\') path[i] = '/';
+        i++;
+    }
+#ifdef WIN32
+    if (path[0] != 0 && path[1] == ':' && path[2] == '/') return;
+#elif defined(_WRS_KERNEL)
+    if (strncmp(path, FS_ROOT, strlen(FS_ROOT)) == 0) return;
+#endif
+    if (path[0] == 0) {
+        strcpy(path, get_user_home());
+    }
+    else if (path[0] != '/') {
+        snprintf(buf, sizeof(buf), "%s/%s", get_user_home(), path);
+        strcpy(path, buf);
+    }
+}
+
+static void command_open(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    unsigned long flags = 0;
+    FileAttrs attrs;
+    int file = -1;
+    int err = 0;
+    OpenFileInfo * handle = NULL;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    flags = json_read_ulong(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    memset(&attrs, 0, sizeof(FileAttrs));
+    json_read_struct(inp, read_file_attrs, &attrs);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if ((attrs.flags & ATTR_PERMISSIONS) == 0) {
+        attrs.permissions = 0775;
+    }
+    file = open(path, to_local_open_flags(flags), attrs.permissions); 
+
+    if (file < 0){
+        err = errno;
+    }
+    else {
+        handle = create_open_file_info(inp, path, file, NULL);
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    write_file_handle(out, handle);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_close(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    OpenFileInfo * h = NULL;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    h = find_open_file_info(id);
+    if (h == NULL) {
+        err = EBADF;
+    }
+    else if (h->dir != NULL) {
+        if (closedir(h->dir) < 0) {
+            err = errno;
+        }
+        else {
+            delete_open_file_info(h);
+        }
+    }
+    else {
+        if (close(h->file) < 0) {
+            err = errno;
+        }
+        else {
+            delete_open_file_info(h);
+        }
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_read(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    OpenFileInfo * h = NULL;
+    int err = 0;
+    int eof = 0;
+    int64 offset;
+    unsigned long len;
+    unsigned long cnt = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    offset = json_read_int64(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    len = json_read_ulong(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    h = find_open_file_info(id);
+    if (h == NULL) {
+        err = EBADF;
+        write_stringz(out, "null");
+    }
+    else {
+        char buf[BUF_SIZE + 4];
+        int rem = 0;
+        unsigned long chk = 0;
+        out->write(out, '"');
+        while (cnt < len) {
+            if (lseek(h->file, offset + cnt, SEEK_SET) == -1) {
+                assert(errno != 0);
+                err = errno;
+                break;
+            }
+            else {
+                int i, j;
+                int rd = read(h->file, buf + rem, BUF_SIZE < len - cnt ? BUF_SIZE : len - cnt);
+                if (rd < 0) {
+                    assert(errno != 0);
+                    err = errno;
+                    break;
+                }
+                if (rd == 0) {
+                    assert(cnt < len);
+                    eof = 1;
+                    break;
+                }
+                j = rem + rd;
+                rem = j % 3;
+                chk += write_base64(out, buf, j - rem);
+                for (i = 0; i < rem; i++) buf[i] = buf[j - rem + i];
+                cnt += rd;
+            }
+        }
+        chk += write_base64(out, buf, rem);
+        out->write(out, '"');
+        out->write(out, 0);
+        assert(chk == (cnt + 2) / 3 * 4);
+    }
+
+    assert(err || eof || cnt == len);
+    write_fs_errno(out, err);
+    json_write_boolean(out, eof);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_write(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    OpenFileInfo * h = NULL;
+    int err = 0;
+    int64 offset;
+    unsigned long len = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    offset = json_read_int64(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX);
+
+    h = find_open_file_info(id);
+    if (h == NULL) err = EBADF;
+    for (;;) {
+        char buf[BUF_SIZE];
+        int rd = read_base64(inp, buf, sizeof(buf));
+        if (rd == 0) break;
+        if (err == 0 && lseek(h->file, offset + len, SEEK_SET) == -1) {
+            err = errno;
+        }
+        if (err == 0) {
+            int wr = write(h->file, buf, rd);
+            if (wr < 0) err = errno;
+            else if (wr < rd) err = ENOSPC;
+        }
+        len += rd;
+    }
+
+    if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void write_stat_result(char * token, OutputStream * out, int err, struct_stat * buf) {
+    FileAttrs attrs;
+
+    if (err == 0) fill_attrs(&attrs, buf);
+    else memset(&attrs, 0, sizeof(attrs));
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    write_file_attrs(out, &attrs);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_stat(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    struct_stat buf;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    memset(&buf, 0, sizeof(buf));
+    if (stat(path, &buf) < 0) err = errno;
+
+    write_stat_result(token, out, err, &buf);
+}
+
+static void command_lstat(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    struct_stat buf;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    memset(&buf, 0, sizeof(buf));
+    if (lstat(path, &buf) < 0) err = errno;
+
+    write_stat_result(token, out, err, &buf);
+}
+
+static void command_fstat(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    struct_stat buf;
+    OpenFileInfo * h = NULL;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    h = find_open_file_info(id);
+    memset(&buf, 0, sizeof(buf));
+    if (h == NULL) err = EBADF;
+    else if (fstat(h->file, &buf) < 0) err = errno;
+    write_stat_result(token, out, err, &buf);
+}
+
+static void command_setstat(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    FileAttrs attrs;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    memset(&attrs, 0, sizeof(FileAttrs));
+    json_read_struct(inp, read_file_attrs, &attrs);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (attrs.flags & ATTR_SIZE) {
+        if (truncate(path, attrs.size) < 0) err = errno;
+    }
+#if !defined(WIN32) && !defined(_WRS_KERNEL)
+    if (attrs.flags & ATTR_UIDGID) {
+        if (chown(path, attrs.uid, attrs.gid) < 0) err = errno;
+    }
+#endif
+    if (attrs.flags & ATTR_PERMISSIONS) {
+        if (chmod(path, attrs.permissions) < 0) err = errno;
+    }
+    if (attrs.flags & ATTR_ACMODTIME) {
+        struct utimbuf buf;
+        buf.actime = (long)(attrs.atime / 1000);
+        buf.modtime = (long)(attrs.mtime / 1000);
+        if (utime(path, &buf) < 0) err = errno;
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_fsetstat(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    FileAttrs attrs;
+    OpenFileInfo * h = NULL;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    memset(&attrs, 0, sizeof(FileAttrs));
+    json_read_struct(inp, read_file_attrs, &attrs);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    h = find_open_file_info(id);
+    if (h == NULL) {
+        err = EBADF;
+    }
+    else {
+        if (attrs.flags & ATTR_SIZE) {
+            if (ftruncate(h->file, attrs.size) < 0) err = errno;
+        }
+#if defined(WIN32) || defined(_WRS_KERNEL)
+        if (attrs.flags & ATTR_PERMISSIONS) {
+            if (chmod(h->path, attrs.permissions) < 0) err = errno;
+        }
+#else
+        if (attrs.flags & ATTR_UIDGID) {
+            if (fchown(h->file, attrs.uid, attrs.gid) < 0) err = errno;
+        }
+        if (attrs.flags & ATTR_PERMISSIONS) {
+            if (fchmod(h->file, attrs.permissions) < 0) err = errno;
+        }
+#endif
+        if (attrs.flags & ATTR_ACMODTIME) {
+            struct utimbuf buf;
+            buf.actime = (long)(attrs.atime / 1000);
+            buf.modtime = (long)(attrs.mtime / 1000);
+            if (utime(h->path, &buf) < 0) err = errno;
+        }
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_opendir(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    DIR * dir = NULL;
+    int err = 0;
+    OpenFileInfo * handle = NULL;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    dir = opendir(path); 
+    if (dir == NULL){
+        err = errno;
+    }
+    else {
+        handle = create_open_file_info(inp, path, -1, dir);
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    write_file_handle(out, handle);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_readdir(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    OpenFileInfo * h = NULL;
+    int err = 0;
+    int eof = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    h = find_open_file_info(id);
+    if (h == NULL || h->dir == NULL) {
+        write_stringz(out, "null");
+        err = EBADF;
+    }
+    else {
+        int cnt = 0;
+        out->write(out, '[');
+        while (cnt < 64) {
+            struct dirent * e;
+            char path[FILE_PATH_SIZE];
+            struct_stat st;
+            FileAttrs attrs;
+            errno = 0;
+            e = readdir(h->dir);
+            if (e == NULL) {
+                err = errno;
+                if (err == 0) eof = 1;
+                break;
+            }
+            if (strcmp(e->d_name, ".") == 0) continue;
+            if (strcmp(e->d_name, "..") == 0) continue;
+            if (cnt > 0) out->write(out, ',');
+            out->write(out, '{');
+            json_write_string(out, "FileName");
+            out->write(out, ':');
+            json_write_string(out, e->d_name);
+            memset(&st, 0, sizeof(st));
+            snprintf(path, sizeof(path), "%s/%s", h->path, e->d_name);
+            if (stat(path, &st) == 0) {
+                fill_attrs(&attrs, &st);
+                out->write(out, ',');
+                json_write_string(out, "Attrs");
+                out->write(out, ':');
+                write_file_attrs(out, &attrs);
+            }
+            out->write(out, '}');
+            cnt++;
+        }
+        out->write(out, ']');
+        out->write(out, 0);
+    }
+
+    write_fs_errno(out, err);
+    json_write_boolean(out, eof);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_remove(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    DIR * dir = NULL;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (remove(path) < 0) err = errno;
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_rmdir(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    DIR * dir = NULL;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (rmdir(path) < 0) err = errno;
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_mkdir(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    FileAttrs attrs;
+    int err = 0;
+    int mode = 0777;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    memset(&attrs, 0, sizeof(FileAttrs));
+    json_read_struct(inp, read_file_attrs, &attrs);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (attrs.flags & ATTR_PERMISSIONS) {
+        mode = attrs.permissions;
+    }
+#if defined(WIN32) || defined(_WRS_KERNEL)
+    if (mkdir(path) < 0) err = errno;
+#else
+    if (mkdir(path, mode) < 0) err = errno;
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_realpath(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    char * real = NULL;
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    real = canonicalize_file_name(path);
+    if (real == NULL) err = errno;
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    json_write_string(out, real);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+    free(real);
+}
+
+static void command_rename(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    char newp[FILE_PATH_SIZE];
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    read_path(inp, newp, sizeof(newp));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (rename(path, newp) < 0) err = errno;
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_readlink(char * token, InputStream * inp, OutputStream * out) {
+    char path[FILE_PATH_SIZE];
+    char link[FILE_PATH_SIZE];
+    int err = 0;
+
+    read_path(inp, path, sizeof(path));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    link[0] = 0;
+#if defined(WIN32) || defined(_WRS_KERNEL)
+    err = ENOSYS;
+#else
+    if (readlink(path, link, sizeof(link)) < 0) err = errno;
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    json_write_string(out, link);
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_symlink(char * token, InputStream * inp, OutputStream * out) {
+    char link[FILE_PATH_SIZE];
+    char target[FILE_PATH_SIZE];
+    int err = 0;
+
+    read_path(inp, link, sizeof(link));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    read_path(inp, target, sizeof(target));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+#if defined(WIN32) || defined(_WRS_KERNEL)
+    err = ENOSYS;
+#else
+    if (symlink(target, link) < 0) err = errno;
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_copy(char * token, InputStream * inp, OutputStream * out) {
+    char src[FILE_PATH_SIZE];
+    char dst[FILE_PATH_SIZE];
+    int copy_uidgid;
+    int copy_perms;
+    struct_stat st;
+    int fi = -1;
+    int fo = -1;
+    int err = 0;
+    int64 pos = 0;
+
+    read_path(inp, src, sizeof(src));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    read_path(inp, dst, sizeof(dst));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    copy_uidgid = json_read_boolean(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    copy_perms = json_read_boolean(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    if (stat(src, &st) < 0) err = errno;
+    if (err == 0 && (fi = open(src, O_RDONLY | O_BINARY, 0)) < 0) err = errno;
+    if (err == 0 && (fo = open(dst, O_WRONLY | O_BINARY | O_CREAT, 0775)) < 0) err = errno;
+
+    while (err == 0 && pos < st.st_size) {
+        char buf[BUF_SIZE];
+        int wr = 0;
+        int rd = read(fi, buf, sizeof(buf));
+        if (rd == 0) break;
+        if (rd < 0) {
+            err == errno;
+            break;
+        }
+        wr = write(fo, buf, rd);
+        if (wr < 0) {
+            err = errno;
+            break;
+        }
+        if (wr < rd) {
+            err = ENOSPC;
+            break;
+        }
+        pos += rd;
+    }
+
+    if (fo >= 0 && close(fo) < 0 && err == 0) err = errno;
+    if (fi >= 0 && close(fi) < 0 && err == 0) err = errno;
+
+    if (err == 0) {
+        struct utimbuf buf;
+        buf.actime = st.st_atime;
+        buf.modtime = st.st_mtime;
+        if (utime(dst, &buf) < 0) err = errno;
+    }
+    if (err == 0 && copy_perms && chmod(dst, st.st_mode) < 0) err = errno;
+#if !defined(WIN32) && !defined(_WRS_KERNEL)
+    if (err == 0 && copy_uidgid && chown(dst, st.st_uid, st.st_gid) < 0) err = errno;
+#endif
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_fs_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_user(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    json_write_long(out, getuid());
+    out->write(out, 0);
+    json_write_long(out, geteuid());
+    out->write(out, 0);
+    json_write_long(out, getgid());
+    out->write(out, 0);
+    json_write_long(out, getegid());
+    out->write(out, 0);
+    json_write_string(out, get_user_home());
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_roots(char * token, InputStream * inp, OutputStream * out) {
+    struct_stat st;
+    int err = 0;
+    int cnt = 0;
+    int disk = 0;
+
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    out->write(out, '[');
+
+#ifdef WIN32
+    for (disk = 'A'; disk <= 'Z'; disk++) {
+        char path[32];
+        snprintf(path, sizeof(path), "%c:/", disk);
+        memset(&st, 0, sizeof(st));
+        if (stat(path, &st) == 0) {
+            FileAttrs attrs;
+            if (cnt > 0) out->write(out, ',');
+            out->write(out, '{');
+            json_write_string(out, "FileName");
+            out->write(out, ':');
+            json_write_string(out, path);
+            fill_attrs(&attrs, &st);
+            out->write(out, ',');
+            json_write_string(out, "Attrs");
+            out->write(out, ':');
+            write_file_attrs(out, &attrs);
+            out->write(out, '}');
+            cnt++;
+        }
+    }
+#elif defined(_WRS_KERNEL)
+    out->write(out, '{');
+    json_write_string(out, "FileName");
+    out->write(out, ':');
+    json_write_string(out, FS_ROOT);
+    memset(&st, 0, sizeof(st));
+    if (stat("/", &st) == 0) {
+        FileAttrs attrs;
+        fill_attrs(&attrs, &st);
+        out->write(out, ',');
+        json_write_string(out, "Attrs");
+        out->write(out, ':');
+        write_file_attrs(out, &attrs);
+    }
+    out->write(out, '}');
+#else
+    out->write(out, '{');
+    json_write_string(out, "FileName");
+    out->write(out, ':');
+    json_write_string(out, "/");
+    memset(&st, 0, sizeof(st));
+    if (stat("/", &st) == 0) {
+        FileAttrs attrs;
+        fill_attrs(&attrs, &st);
+        out->write(out, ',');
+        json_write_string(out, "Attrs");
+        out->write(out, ':');
+        write_file_attrs(out, &attrs);
+    }
+    out->write(out, '}');
+#endif
+
+    out->write(out, ']');
+    out->write(out, 0);
+    write_fs_errno(out, err);
+
+    out->write(out, MARKER_EOM);
+}
+
+void ini_file_system_service(void) {
+    int i;
+
+    add_channel_close_listener(channel_close_listener);
+    list_init(&file_info_ring);
+    for (i = 0; i < HANDLE_HASH_SIZE; i++) {
+        list_init(&handle_hash[i]);
+    }
+
+    add_command_handler(FILE_SYSTEM, "open", command_open);
+    add_command_handler(FILE_SYSTEM, "close", command_close);
+    add_command_handler(FILE_SYSTEM, "read", command_read);
+    add_command_handler(FILE_SYSTEM, "write", command_write);
+    add_command_handler(FILE_SYSTEM, "stat", command_stat);
+    add_command_handler(FILE_SYSTEM, "lstat", command_lstat);
+    add_command_handler(FILE_SYSTEM, "fstat", command_fstat);
+    add_command_handler(FILE_SYSTEM, "setstat", command_setstat);
+    add_command_handler(FILE_SYSTEM, "fsetstat", command_fsetstat);
+    add_command_handler(FILE_SYSTEM, "opendir", command_opendir);
+    add_command_handler(FILE_SYSTEM, "readdir", command_readdir);
+    add_command_handler(FILE_SYSTEM, "remove", command_remove);
+    add_command_handler(FILE_SYSTEM, "rmdir", command_rmdir);
+    add_command_handler(FILE_SYSTEM, "mkdir", command_mkdir);
+    add_command_handler(FILE_SYSTEM, "realpath", command_realpath);
+    add_command_handler(FILE_SYSTEM, "rename", command_rename);
+    add_command_handler(FILE_SYSTEM, "readlink", command_readlink);
+    add_command_handler(FILE_SYSTEM, "symlink", command_symlink);
+    add_command_handler(FILE_SYSTEM, "copy", command_copy);
+    add_command_handler(FILE_SYSTEM, "user", command_user);
+    add_command_handler(FILE_SYSTEM, "roots", command_roots);
+}
+
+#endif
+
diff --git a/filesystem.h b/filesystem.h
new file mode 100644
index 0000000..5e8b508
--- /dev/null
+++ b/filesystem.h
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: file system access (TCF name FileSystem)
+ */
+
+#ifndef D_filesystem
+#define D_filesystem
+
+/*
+ * Initialize file system service.
+ */
+extern void ini_file_system_service(void);
+
+#endif
diff --git a/json.c b/json.c
new file mode 100644
index 0000000..6a85cec
--- /dev/null
+++ b/json.c
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module provides support for JSON - a computer data interchange format.
+ * It is a text-based, human-readable format for representing simple data structures and
+ * associative arrays (called objects). The JSON format is specified in RFC 4627 by Douglas Crockford. 
+ * JSON is TCF preffered marshaling format.
+ */
+
+#include "json.h"
+#include "assert.h"
+#include "myalloc.h"
+#include "exceptions.h"
+
+static char * buf = NULL;
+static unsigned buf_size = 0;
+
+void json_write_ulong(OutputStream * out, unsigned long n) {
+    if (n >= 10) {
+        json_write_ulong(out, n / 10);
+        n = n % 10;
+    }
+    out->write(out, n + '0');
+}
+
+void json_write_long(OutputStream * out, long n) {
+    if (n < 0) {
+        out->write(out, '-');
+        n = -n;
+    }
+    json_write_ulong(out, (unsigned long)n);
+}
+
+void json_write_int64(OutputStream * out, int64 n) {
+    if (n < 0) {
+        out->write(out, '-');
+        n = -n;
+        if (n < 0) exception(EINVAL);
+    }
+    if (n >= 10) {
+        json_write_int64(out, n / 10);
+        n = n % 10;
+    }
+    out->write(out, (int)n + '0');
+}
+
+void json_write_boolean(OutputStream * out, int b) {
+    if (b) write_string(out, "true");
+    else write_string(out, "false");
+}
+
+static char hex_digit(unsigned n) {
+    n &= 0xf;
+    if (n < 10) return '0' + n;
+    return 'A' + (n - 10);
+}
+
+void json_write_char(OutputStream * out, char ch) {
+    unsigned n = ch & 0xff;
+    if (n < ' ') {
+        out->write(out, '\\');
+        out->write(out, 'u');
+        out->write(out, '0');
+        out->write(out, '0');
+        out->write(out, hex_digit(n >> 4));
+        out->write(out, hex_digit(n));
+    }
+    else {
+        if (n == '"' || n == '\\') out->write(out, '\\');
+        out->write(out, n);
+    }
+}
+
+void json_write_string(OutputStream * out, const char * str) {
+    if (str == NULL) {
+        write_string(out, "null");
+    }
+    else {
+        out->write(out, '"');
+        while (*str) json_write_char(out, *str++);
+        out->write(out, '"');
+    }
+}
+
+void json_write_string_len(OutputStream * out, const char * str, size_t len) {
+    if (str == NULL) {
+        write_string(out, "null");
+    }
+    else {
+        out->write(out, '"');
+        while (len > 0) {
+            json_write_char(out, *str++);
+            len--;
+        }
+        out->write(out, '"');
+    }
+}
+
+static int readHex(InputStream * inp) {
+    int ch = inp->read(inp);
+    if (ch >= '0' && ch <= '9') return ch - '0';
+    if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
+    if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
+    exception(ERR_JSON_SYNTAX);
+    return 0;
+}
+
+static int readHexChar(InputStream * inp) {
+    int n = readHex(inp) << 12;
+    n |= readHex(inp) << 8;
+    n |= readHex(inp) << 4;
+    n |= readHex(inp);
+    return n;
+}
+
+static int read_esc_char(InputStream * inp) {
+    int ch = inp->read(inp);
+    switch (ch) {
+    case '"': break;
+    case '\\': break;
+    case '/': break;
+    case 'b': ch = '\b'; break;
+    case 'f': ch = '\f'; break;
+    case 'n': ch = '\n'; break;
+    case 'r': ch = '\r'; break;
+    case 't': ch = '\t'; break;
+    case 'u': ch = readHexChar(inp); break;
+    default: exception(ERR_JSON_SYNTAX);
+    }
+    return ch;
+}
+
+int json_read_string(InputStream * inp, char * str, size_t size) {
+    unsigned i = 0;
+    int ch = inp->read(inp);
+    if (ch == 'n') {
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        str[0] = 0;
+        return -1;
+    }
+    if (ch != '"') exception(ERR_JSON_SYNTAX);
+    for (;;) {
+        ch = inp->read(inp);
+        if (ch == '"') break;
+        if (ch == '\\') ch = read_esc_char(inp);
+        if (i < size - 1) str[i] = (char)ch;
+        i++;
+    }
+    if (i < size) str[i] = 0;
+    else str[size - 1] = 0;
+    return i;
+}
+
+char * json_read_alloc_string(InputStream * inp) {
+    char * str = NULL;
+    unsigned i = 0;
+    int ch = inp->read(inp);
+    if (ch == 'n') {
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        return NULL;
+    }
+    if (ch != '"') exception(ERR_JSON_SYNTAX);
+    for (;;) {
+        ch = inp->read(inp);
+        if (ch == '"') break;
+        if (ch == '\\') ch = read_esc_char(inp);
+        if (i >= buf_size) {
+            int new_size = buf_size == 0 ? 0x1000 : buf_size * 2;
+            char * tmp = (char *)loc_alloc(new_size);
+            if (i > 0) memcpy(tmp, buf, i);
+            if (buf != NULL) loc_free(buf);
+            buf = tmp;
+            buf_size = new_size;
+        }
+        buf[i++] = (char)ch;
+    }
+    str = (char *)loc_alloc(i + 1);
+    memcpy(str, buf, i);
+    str[i] = 0;
+    return str;
+}
+
+int json_read_boolean(InputStream * inp) {
+    int ch = inp->read(inp);
+    if (ch == 'f') {
+        if (inp->read(inp) != 'a') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 's') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'e') exception(ERR_JSON_SYNTAX);
+        return 0;
+    }
+    if (ch == 't') {
+        if (inp->read(inp) != 'r') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'e') exception(ERR_JSON_SYNTAX);
+        return 1;
+    }
+    exception(ERR_JSON_SYNTAX);
+    return 0;
+}
+
+long json_read_long(InputStream * inp) {
+    long res = 0;
+    int neg = 0;
+    int ch = inp->read(inp);
+    if (ch == '-') {
+        neg = 1;
+        ch = inp->read(inp);
+    }
+    if (ch < '0' || ch > '9') exception(ERR_JSON_SYNTAX);
+    res = ch - '0';
+    while (1) {
+        ch = inp->peek(inp);
+        if (ch < '0' || ch > '9') break;
+        inp->read(inp);
+        res = res * 10 + (ch - '0');
+    }
+    if (neg) return -res;
+    return res;
+}
+
+unsigned long json_read_ulong(InputStream * inp) {
+    unsigned long res = 0;
+    int neg = 0;
+    int ch = inp->read(inp);
+    if (ch == '-') {
+        neg = 1;
+        ch = inp->read(inp);
+    }
+    if (ch < '0' || ch > '9') exception(ERR_JSON_SYNTAX);
+    res = ch - '0';
+    while (1) {
+        ch = inp->peek(inp);
+        if (ch < '0' || ch > '9') break;
+        inp->read(inp);
+        res = res * 10 + (ch - '0');
+    }
+    if (neg) return ~res + 1;
+    return res;
+}
+
+int64 json_read_int64(InputStream * inp) {
+    int64 res = 0;
+    int neg = 0;
+    int ch = inp->read(inp);
+    if (ch == '-') {
+        neg = 1;
+        ch = inp->read(inp);
+    }
+    if (ch < '0' || ch > '9') exception(ERR_JSON_SYNTAX);
+    res = ch - '0';
+    while (1) {
+        ch = inp->peek(inp);
+        if (ch < '0' || ch > '9') break;
+        inp->read(inp);
+        res = res * 10 + (ch - '0');
+    }
+    if (neg) return -res;
+    return res;
+}
+
+int json_read_struct(InputStream * inp, struct_call_back call_back, void * arg) {
+    int ch = inp->read(inp);
+    if (ch == 'n') {
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        return 0;
+    }
+    if (ch == '{') {
+        ch = inp->read(inp);
+        if (ch != '}') {
+            for (;;) {
+                int nm_len = 0;
+                char nm[256];
+                if (ch != '"') exception(ERR_JSON_SYNTAX);
+                for (;;) {
+                    ch = inp->read(inp);
+                    if (ch == '"') break;
+                    if (ch == '\\') {
+                        ch = inp->read(inp);
+                        switch (ch) {
+                        case '"': break;
+                        case '\\': break;
+                        case '/': break;
+                        case 'b': ch = '\b'; break;
+                        case 'f': ch = '\f'; break;
+                        case 'n': ch = '\n'; break;
+                        case 'r': ch = '\r'; break;
+                        case 't': ch = '\t'; break;
+                        case 'u': ch = readHexChar(inp); break;
+                        default: exception(ERR_JSON_SYNTAX);
+                        }
+                    }
+                    if (nm_len < sizeof(nm) - 1) {
+                        nm[nm_len] = (char)ch;
+                        nm_len++;
+                    }
+                }
+                nm[nm_len] = 0;
+                ch = inp->read(inp);
+                if (ch != ':') exception(ERR_JSON_SYNTAX);
+                call_back(inp, nm, arg);
+                ch = inp->read(inp);
+                if (ch == '}') break;
+                if (ch != ',') exception(ERR_JSON_SYNTAX);
+                ch = inp->read(inp);
+            }
+        }
+        return 1;
+    }
+    exception(ERR_JSON_SYNTAX);
+    return 0;
+}
+
+char ** json_read_alloc_string_array(InputStream * inp, int * pos) {
+    int ch = inp->read(inp);
+    *pos = 0;
+    if (ch == 'n') {
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        return NULL;
+    }
+    else if (ch != '[') {
+        exception(ERR_PROTOCOL);
+        return NULL;
+    }
+    else {
+        static int * len_buf = NULL;
+        static int len_buf_size = 0;
+
+        int buf_pos = 0;
+        int len_pos = 0;
+
+        int i, j;
+        char * str = NULL;
+        char ** arr = NULL;
+
+        if (inp->peek(inp) == ']') {
+            inp->read(inp);
+        }
+        else {
+            while (1) {
+                int ch;
+                int len;
+                if (buf == NULL) {
+                    buf_size = 0x1000;
+                    buf = (char *)loc_alloc(buf_size);
+                }
+                else if (buf_size - buf_pos < 0x200) {
+                    char * tmp = (char *)loc_alloc(buf_size * 2);
+                    memcpy(tmp, buf, buf_pos);
+                    loc_free(buf);
+                    buf = tmp;
+                    buf_size *= 2;
+                }
+                if (len_pos >= len_buf_size) {
+                    len_buf_size = len_buf_size == 0 ? 0x100 : len_buf_size * 2;
+                    len_buf = (int *)loc_realloc(len_buf, len_buf_size * sizeof(int));
+                }
+                len = json_read_string(inp, buf + buf_pos, buf_size - buf_pos);
+                if (len >= (int)(buf_size - buf_pos)) exception(ERR_BUFFER_OVERFLOW);
+                len_buf[len_pos++] = len;
+                buf_pos += len + 1;
+                ch = inp->read(inp);
+                if (ch == ',') continue;
+                if (ch == ']') break;
+                exception(ERR_JSON_SYNTAX);
+            }
+        }
+        arr = (char **)loc_alloc((len_pos + 1) * sizeof(char *) + buf_pos);
+        str = (char *)(arr + len_pos + 1);
+        memcpy(str, buf, buf_pos);
+        j = 0;
+        for (i = 0; i < len_pos; i++) {
+            arr[i] = str + j;
+            j += len_buf[i] + 1;
+        }
+        arr[len_pos] = NULL;
+        *pos = len_pos;
+        return arr;
+    }
+}
+
+void json_skip_object(InputStream * inp) {
+    int ch = inp->read(inp);
+    if (ch == 'n') {
+        if (inp->read(inp) != 'u') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != 'l') exception(ERR_JSON_SYNTAX);
+        return;
+    }
+    if (ch == '"') {
+        for (;;) {
+            ch = inp->read(inp);
+            if (ch == '"') break;
+            if (ch == '\\') {
+                if (inp->read(inp) == 'u') readHexChar(inp);
+            }
+        }
+        return;
+    }
+    if (ch == '-' || ch >= '0' && ch <= '9') {
+        while (1) {
+            ch = inp->peek(inp);
+            if (ch < '0' || ch > '9') break;
+            inp->read(inp);
+        }
+        return;
+    }
+    if (ch == '[') {
+        if (inp->peek(inp) == ']') {
+            inp->read(inp);
+        }
+        else {
+            while (1) {
+                int ch;
+                json_skip_object(inp);
+                ch = inp->read(inp);
+                if (ch == ',') continue;
+                if (ch == ']') break;
+                exception(ERR_JSON_SYNTAX);
+            }
+        }
+        return;
+    }
+    if (ch == '{') {
+        if (inp->peek(inp) == '}') {
+            inp->read(inp);
+        }
+        else {
+            while (1) {
+                int ch;
+                json_skip_object(inp);
+                if (inp->read(inp) != ':') exception(ERR_JSON_SYNTAX);
+                json_skip_object(inp);
+                ch = inp->read(inp);
+                if (ch == ',') continue;
+                if (ch == '}') break;
+                exception(ERR_JSON_SYNTAX);
+            }
+        }
+    }
+    exception(ERR_JSON_SYNTAX);
+}
+
+void write_errno(OutputStream * out, int err) {
+    char * msg = NULL;
+    json_write_long(out, err);
+    out->write(out, 0);
+    if (err != 0) msg = errno_to_str(err);
+    json_write_string(out, msg);
+    out->write(out, 0);
+}
+
+void write_err_msg(OutputStream * out, int err, char * msg) {
+    json_write_long(out, err);
+    out->write(out, 0);
+    if (err == 0) {
+        write_string(out, "null");
+    }
+    else {
+        char * str = errno_to_str(err);
+        out->write(out, '"');
+        while (*str) json_write_char(out, *str++);
+        if (msg != NULL) {
+            out->write(out, ':');
+            out->write(out, ' ');
+            while (*msg) json_write_char(out, *msg++);
+        }
+        out->write(out, '"');
+    }
+    out->write(out, 0);
+}
+
diff --git a/json.h b/json.h
new file mode 100644
index 0000000..3c22789
--- /dev/null
+++ b/json.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module provides support for JSON - a computer data interchange format.
+ * It is a text-based, human-readable format for representing simple data structures and
+ * associative arrays (called objects). The JSON format is specified in RFC 4627 by Douglas Crockford. 
+ * JSON is TCF preffered marshaling format.
+ */
+
+#ifndef D_json
+#define D_json
+
+#include <stdlib.h>
+#include "mdep.h"
+#include "streams.h"
+
+extern int json_read_string(InputStream * inp, char * str, size_t size);
+extern int json_read_boolean(InputStream * inp);
+extern long json_read_long(InputStream * inp);
+extern unsigned long json_read_ulong(InputStream * inp);
+extern int64 json_read_int64(InputStream * inp);
+extern char * json_read_alloc_string(InputStream * inp);
+extern char ** json_read_alloc_string_array(InputStream * inp, int * len);
+
+typedef void (*struct_call_back)(InputStream *, char *, void *);
+extern int json_read_struct(InputStream * inp, struct_call_back call_back, void * arg);
+
+extern void json_skip_object(InputStream * inp);
+
+extern void json_write_ulong(OutputStream * out, unsigned long n);
+extern void json_write_long(OutputStream * out, long n);
+extern void json_write_int64(OutputStream * out, int64 n);
+extern void json_write_char(OutputStream * out, char ch);
+extern void json_write_string(OutputStream * out, const char * str);
+extern void json_write_string_len(OutputStream * out, const char * str, size_t len);
+extern void json_write_boolean(OutputStream * out, int b);
+
+extern void write_errno(OutputStream * out, int err);
+extern void write_err_msg(OutputStream * out, int err, char * msg);
+
+#endif
diff --git a/linenumbers.c b/linenumbers.c
new file mode 100644
index 0000000..19b5c0c
--- /dev/null
+++ b/linenumbers.c
@@ -0,0 +1,641 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF service line Numbers
+ * The service associates locations in the source files with the corresponding
+ * machine instruction addresses in the executable object.
+ */
+
+#include "config.h"
+#if SERVICE_LineNumbers
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include "linenumbers.h"
+#include "context.h"
+#include "myalloc.h"
+#include "exceptions.h"
+#include "json.h"
+#include "protocol.h"
+#include "elf.h"
+#include "dwarfio.h"
+#include "dwarf.h"
+
+static const char * LINENUMBERS = "LineNumbers";
+
+typedef unsigned long ADDR_T;
+
+struct FileInfo {
+    char * name;
+    char * dir;
+    U4_T mtime;
+    U4_T size;
+};
+
+typedef struct FileInfo FileInfo;
+
+struct LineNumbersState {
+    unsigned file;
+    unsigned line;
+    unsigned column;
+    ADDR_T address;
+    U1_T isa;
+    U1_T is_stmt;
+    U1_T basic_block;
+    U1_T prologue_end;
+    U1_T epilogue_begin;
+    U1_T end_sequence;
+};
+
+typedef struct LineNumbersState LineNumbersState;
+
+struct CompUnit {
+    ADDR_T low_pc;
+    ADDR_T high_pc;
+    U8_T debug_ranges_offs;
+    U8_T debug_info_offs;
+    U8_T line_info_offs;
+    char * name;
+    char * dir;
+
+    U4_T files_cnt;
+    U4_T files_max;
+    FileInfo * files;
+
+    U4_T dirs_cnt;
+    U4_T dirs_max;
+    char ** dirs;
+
+    U4_T states_cnt;
+    U4_T states_max;
+    LineNumbersState * states;
+};
+
+typedef struct CompUnit CompUnit;
+
+struct LineNumbersCache {
+    ELF_File * file;
+    CompUnit * units;
+    U4_T units_max;
+    U4_T units_cnt;
+    ELF_Section * debug_ranges;
+    ELF_Section * debug_line;
+};
+
+typedef struct LineNumbersCache LineNumbersCache;
+
+static LineNumbersCache * read_cache;
+
+static void read_tag_com_unit(U2_T attr, U2_T form) {
+    static CompUnit * unit;
+    switch (attr) {
+    case 0:
+        if (form) {
+            if (read_cache->units_cnt >= read_cache->units_max) {
+                read_cache->units_max = read_cache->units_max == 0 ? 16 : read_cache->units_max * 2;
+                read_cache->units = (CompUnit *)loc_realloc(read_cache->units, sizeof(CompUnit) * read_cache->units_max);
+            }
+            unit = read_cache->units + read_cache->units_cnt++;
+            memset(unit, 0, sizeof(CompUnit));
+            unit->debug_ranges_offs = ~(U8_T)0;
+        }
+        else {
+            /* Skip to next compilation unit */
+            assert(dio_gUnitSize > 0);
+            dio_Skip(dio_gUnitPos + dio_gUnitSize - dio_GetPos());
+        }
+        break;
+    case AT_low_pc:
+        dio_ChkAddr(form);
+        unit->low_pc = (ADDR_T)dio_gFormRef;
+        break;
+    case AT_high_pc:
+        dio_ChkAddr(form);
+        unit->high_pc = (ADDR_T)dio_gFormRef;
+        break;
+    case AT_ranges:
+        dio_ChkData(form);
+        unit->debug_ranges_offs = dio_gFormData;
+        break;
+    case AT_name:
+        dio_ChkString(form);
+        unit->name = (char *)loc_alloc(dio_gFormBlockSize);
+        strcpy(unit->name, (char *)dio_gFormBlockBuf);
+        break;
+    case AT_comp_dir:
+        dio_ChkString(form);
+        unit->dir = (char *)loc_alloc(dio_gFormBlockSize);
+        strcpy(unit->dir, (char *)dio_gFormBlockBuf);
+        break;
+    case AT_stmt_list:
+        dio_ChkData(form);
+        unit->line_info_offs = dio_gFormData;
+        break;
+    }
+}
+
+static void entry_callback(U2_T Tag, U2_T attr, U2_T form) {
+    switch (Tag) {
+    case TAG_compile_unit           :
+        read_tag_com_unit(attr, form);
+        break;
+    }
+}
+                
+static void free_unit_cache(CompUnit * unit) {
+    U4_T j;
+    
+    for (j = 0; j < unit->files_cnt; j++) {
+        loc_free(unit->files[j].name);
+    }
+    unit->files_cnt = 0;
+    unit->files_max = 0;
+    loc_free(unit->files);
+
+    for (j = 0; j < unit->dirs_cnt; j++) {
+        loc_free(unit->dirs[j]);
+    }
+    unit->dirs_cnt = 0;
+    unit->dirs_max = 0;
+    loc_free(unit->dirs);
+
+    unit->states_cnt = 0;
+    unit->states_max = 0;
+    loc_free(unit->states);
+}
+
+static void free_line_numbers_cache(ELF_File * file) {
+    LineNumbersCache * cache = (LineNumbersCache *)file->line_numbers_cache;
+    if (cache != NULL) {
+        U4_T i;
+        for (i = 0; i < cache->units_cnt; i++) {
+            CompUnit * unit = cache->units + i;
+            loc_free(unit->name);
+            loc_free(unit->dir);
+            free_unit_cache(unit);
+        }
+        loc_free(cache->units);
+        loc_free(cache);
+    }
+}
+
+static LineNumbersCache * get_line_numbers_cache(Context * ctx) {
+    ELF_File * file;
+    char fnm[FILE_PATH_SIZE];
+
+#if defined(WIN32)
+    exception(EINVAL);
+#elif defined(_WRS_KERNEL)
+    exception(EINVAL);
+#else
+    snprintf(fnm, sizeof(fnm), "/proc/%d/exe", ctx->mem);
+#endif
+
+    file = elf_open(fnm);
+    if (file == NULL) exception(errno);
+    if (file->line_numbers_cache == NULL) {
+        Trap trap;
+        if (set_trap(&trap)) {
+            unsigned idx;
+            LineNumbersCache * cache = NULL;
+            dio_LoadAbbrevTable(file);
+            cache = (LineNumbersCache *)(file->line_numbers_cache = loc_alloc_zero(sizeof(LineNumbersCache)));
+            cache->file = file;
+            read_cache = cache;
+            for (idx = 0; idx < file->section_cnt; idx++) {
+                ELF_Section * sec = file->sections[idx];
+                if (sec == NULL) continue;
+                if (sec->size == 0) continue;
+                if (sec->name == NULL) continue;
+                if (strcmp(sec->name, ".debug") == 0 || strcmp(sec->name, ".debug_info") == 0) {
+                    dio_EnterSection(sec, 0);
+                    dio_gVersion = strcmp(sec->name, ".debug") == 0 ? 1 : 2;
+                    while (dio_GetPos() < sec->size) dio_ReadUnit(entry_callback);
+                    dio_ExitSection();
+                }
+                else if (strcmp(sec->name, ".debug_ranges") == 0) {
+                    cache->debug_ranges = sec;
+                }
+                else if (strcmp(sec->name, ".debug_line") == 0) {
+                    cache->debug_line = sec;
+                }
+            }
+            read_cache = NULL;
+            clear_trap(&trap);
+        }
+        else {
+            free_line_numbers_cache(file);
+            str_exception(trap.error, trap.msg);
+        }
+    }
+    return (LineNumbersCache *)file->line_numbers_cache;
+}
+
+static void add_dir(CompUnit * unit, char * name) {
+    if (unit->dirs_cnt >= unit->dirs_max) {
+        unit->dirs_max = unit->dirs_max == 0 ? 16 : unit->dirs_max * 2;
+        unit->dirs = (char **)loc_realloc(unit->dirs, sizeof(char *) * unit->dirs_max);
+    }
+    unit->dirs[unit->dirs_cnt++] = name;
+}
+
+static void add_file(CompUnit * unit, FileInfo * file) {
+    if (unit->files_cnt >= unit->files_max) {
+        unit->files_max = unit->files_max == 0 ? 16 : unit->files_max * 2;
+        unit->files = (FileInfo *)loc_realloc(unit->files, sizeof(FileInfo) * unit->files_max);
+    }
+    if (file->dir == NULL) file->dir = unit->dir;
+    unit->files[unit->files_cnt++] = *file;
+}
+
+static void add_state(CompUnit * unit, LineNumbersState * state) {
+    if (unit->states_cnt >= unit->states_max) {
+        unit->states_max = unit->states_max == 0 ? 128 : unit->states_max * 2;
+        unit->states = (LineNumbersState *)loc_realloc(unit->states, sizeof(LineNumbersState) * unit->states_max);
+    }
+    unit->states[unit->states_cnt++] = *state;
+}
+
+static void load_line_numbers(LineNumbersCache * cache, CompUnit * unit) {
+    Trap trap;
+    if (unit->files != NULL && unit->dirs != NULL) return;
+    dio_gUnitPos = unit->line_info_offs;
+    dio_EnterSection(cache->debug_line, dio_gUnitPos);
+    if (set_trap(&trap)) {
+        U8_T header_pos = 0;
+        U1_T opcode_base = 0;
+        U1_T opcode_size[256];
+        U4_T header_size = 0;
+        U1_T min_instruction_length = 0;
+        U1_T is_stmt_default = 0;
+        I1_T line_base = 0;
+        U1_T line_range = 0;
+        U4_T unit_size = 0;
+        LineNumbersState state;
+        
+        // Read header
+        unit_size = dio_ReadU4();
+        if (unit_size == 0xffffffffu) {
+            str_exception(ERR_DWARF, "64-bit DWARF is not supported yet");
+        }
+        else {
+            unit_size += 4;
+        }
+        dio_ReadU2(); /* line info version */
+        header_size = dio_ReadU4();
+        header_pos = dio_GetPos();
+        min_instruction_length = dio_ReadU1();
+        is_stmt_default = dio_ReadU1() != 0;
+        line_base = (I1_T)dio_ReadU1();
+        line_range = dio_ReadU1();
+        opcode_base = dio_ReadU1();
+        memset(opcode_size, 0, sizeof(opcode_size));
+        dio_Read(opcode_size + 1, opcode_base - 1);
+
+        // Read directory names
+        for (;;) {
+            char * name = dio_ReadString();
+            if (name == NULL) break;
+            add_dir(unit, name);
+        }
+
+        // Read source files info
+        for (;;) {
+            U4_T dir = 0;
+            FileInfo file;
+            memset(&file, 0, sizeof(file));
+            file.name = dio_ReadString();
+            if (file.name == NULL) break;
+            dir = dio_ReadLEB128();
+            if (dir > 0 && dir <= unit->dirs_cnt) file.dir = unit->dirs[dir - 1];
+            file.mtime = dio_ReadLEB128();
+            file.size = dio_ReadLEB128();
+            add_file(unit, &file);
+        }
+
+        // Run the program
+        if (header_pos + header_size != dio_GetPos())
+            str_exception(ERR_DWARF, "Invalid line info header");
+        memset(&state, 0, sizeof(state));
+        state.file = 1;
+        state.line = 1;
+        state.is_stmt = is_stmt_default;
+        while (dio_GetPos() < dio_gUnitPos + unit_size) {
+            U1_T opcode = dio_ReadU1();
+            if (opcode >= opcode_base) {
+                state.line += (unsigned)((int)((opcode - opcode_base) % line_range) + line_base);
+                state.address += (opcode - opcode_base) / line_range * min_instruction_length;
+                add_state(unit, &state);
+                state.basic_block = 0;
+                state.prologue_end = 0;
+                state.epilogue_begin = 0;
+            }
+            else if (opcode == 0) {
+		U4_T op_size = dio_ReadLEB128();
+                U8_T op_pos = dio_GetPos();
+                switch (dio_ReadU1()) {
+                case DW_LNE_define_file: {
+                    U4_T dir = 0;
+                    FileInfo file;
+                    memset(&file, 0, sizeof(file));
+                    file.name = dio_ReadString();
+                    dir = dio_ReadLEB128();
+                    if (dir > 0 && dir <= unit->dirs_cnt) file.dir = unit->dirs[dir - 1];
+                    file.mtime = dio_ReadLEB128();
+                    file.size = dio_ReadLEB128();
+                    add_file(unit, &file);
+                    break;
+                }
+                case DW_LNE_end_sequence:
+                    state.end_sequence = 1;
+                    add_state(unit, &state);
+                    memset(&state, 0, sizeof(state));
+                    state.file = 1;
+                    state.line = 1;
+                    state.is_stmt = is_stmt_default;
+                    break;
+                case DW_LNE_set_address:
+                    state.address = (ADDR_T)dio_ReadAddress();
+                    break;
+                default:
+                    dio_Skip(op_size - 1);
+                    break;
+                }
+                assert(dio_GetPos() == op_pos + op_size);
+            }
+            else {
+                switch (opcode) {
+                case DW_LNS_copy:
+                    add_state(unit, &state);
+                    state.basic_block = 0;
+                    state.prologue_end = 0;
+                    state.epilogue_begin = 0;
+                    break;
+                case DW_LNS_advance_pc:
+                    state.address += (ADDR_T)(dio_ReadU8LEB128() * min_instruction_length);
+                    break;
+                case DW_LNS_advance_line:
+                    state.line += dio_ReadLEB128();
+                    break;
+                case DW_LNS_set_file:
+                    state.file = dio_ReadLEB128();
+                    break;
+                case DW_LNS_set_column:
+                    state.column = dio_ReadLEB128();
+                    break;
+                case DW_LNS_negate_stmt:
+                    state.is_stmt = !state.is_stmt;
+                    break;
+                case DW_LNS_set_basic_block:
+                    state.basic_block = 1;
+                    break;
+                case DW_LNS_const_add_pc:
+                    state.address += (255 - opcode_base) / line_range * min_instruction_length;
+                    break;
+                case DW_LNS_fixed_advance_pc:
+                    state.address += dio_ReadU2();
+                    break;
+                case DW_LNS_set_prologue_end:
+                    state.prologue_end = 1;
+                    break;
+                case DW_LNS_set_epilogue_begin:
+                    state.epilogue_begin = 1;
+                    break;
+                case DW_LNS_set_isa:
+                    state.isa = (U1_T)dio_ReadLEB128();
+                    break;
+                default:
+                    str_exception(ERR_DWARF, "Invalid line info op code");
+                    break;
+                }
+            }
+        }
+        dio_ExitSection();
+        clear_trap(&trap);
+    }
+    else {
+        dio_ExitSection();
+        free_unit_cache(unit);
+        str_exception(trap.error, trap.msg);
+    }
+}
+
+static CompUnit * find_unit(LineNumbersCache * cache, ADDR_T addr0, ADDR_T addr1, ADDR_T * addr_next) {
+    U4_T i;
+    CompUnit * unit = NULL;
+    ADDR_T low_pc = 0;
+    // TODO: faster unit search
+    for (i = 0; i < cache->units_cnt; i++) {
+        CompUnit * u = cache->units + i;
+        if (u->debug_ranges_offs != ~(U8_T)0) {
+            if (cache->debug_ranges != NULL) {
+                U8_T base = u->low_pc;
+                U8_T max = 0;
+                dio_gUnitPos = u->debug_ranges_offs;
+                dio_EnterSection(cache->debug_ranges, dio_gUnitPos);
+                while (1) {
+                    U8_T x = dio_ReadAddress();
+                    U8_T y = dio_ReadAddress();
+                    if (x == 0 && y == 0) break;
+                    if (x == ((U8_T)1 << dio_gAddressSize * 8) - 1) {
+                        base = y;
+                    }
+                    else {
+                        x = base + x;
+                        y = base + y;
+                        if (addr0 < y && addr1 > x) {
+                            if (unit == NULL || low_pc > x) {
+                                unit = u;
+                                low_pc = (ADDR_T)x;
+                                *addr_next = (ADDR_T)y;
+                            }
+                        }
+                    }
+                }
+                dio_ExitSection();
+            }
+        }
+        else if (u->low_pc != 0 && u->high_pc != 0) {
+            if (addr0 < u->high_pc && addr1 > u->low_pc) {
+                if (unit == NULL || low_pc > u->low_pc) {
+                    unit = u;
+                    low_pc = u->low_pc;
+                    *addr_next = u->high_pc;
+                }
+            }
+        }
+    }
+    return unit;
+}
+
+static void load_line_numbers_in_range(LineNumbersCache * cache, ADDR_T addr0, ADDR_T addr1) {
+    while (addr0 < addr1) {
+        ADDR_T next = 0;
+        CompUnit * unit = find_unit(cache, addr0, addr1, &next);
+        if (unit == NULL) break;
+        load_line_numbers(cache, unit);
+        addr0 = next;
+    }
+}
+
+static void command_map_to_source(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char * err_msg = NULL;
+    char id[256];
+    ADDR_T addr0;
+    ADDR_T addr1;
+    Context * ctx = NULL;
+    LineNumbersCache * cache = NULL;
+    Trap trap;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    addr0 = json_read_ulong(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    addr1 = json_read_ulong(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    ctx = id2ctx(id);
+    if (ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+
+    if (err == 0) {
+        if (set_trap(&trap)) {
+            cache = get_line_numbers_cache(ctx);
+            load_line_numbers_in_range(cache, addr0, addr1);
+            clear_trap(&trap);
+        }
+        else {
+            err = trap.error;
+            err_msg = trap.msg;
+        }
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_err_msg(out, err, err_msg);
+    if (err != 0) {
+        write_stringz(out, "null");
+    }
+    else {
+        int cnt = 0;
+        FileInfo * file = NULL;
+        out->write(out, '[');
+        while (addr0 < addr1) {
+            U4_T i;
+            ADDR_T next = 0;
+            FileInfo * state_file = NULL;
+            CompUnit * unit = find_unit(cache, addr0, addr1, &next);
+            if (unit == NULL) break;
+
+            for (i = 0; i < unit->states_cnt - 1; i++) {
+                LineNumbersState * state = unit->states + i;
+                LineNumbersState * next = unit->states + i + 1;
+                if (state->end_sequence) continue;
+                if (next->address > addr0 && state->address < addr1) {
+                    if (cnt > 0) out->write(out, ',');
+                    out->write(out, '{');
+                    json_write_string(out, "SLine");
+                    out->write(out, ':');
+                    json_write_ulong(out, state->line - 1);
+                    if (state->column > 0) {
+                        out->write(out, ',');
+                        json_write_string(out, "SCol");
+                        out->write(out, ':');
+                        json_write_ulong(out, state->column - 1);
+                    }
+                    out->write(out, ',');
+                    json_write_string(out, "ELine");
+                    out->write(out, ':');
+                    json_write_ulong(out, next->line - 1);
+                    if (next->column > 0) {
+                        out->write(out, ',');
+                        json_write_string(out, "ECol");
+                        out->write(out, ':');
+                        json_write_ulong(out, next->column - 1);
+                    }
+                    state_file = NULL;
+                    if (state->file >= 1 && state->file <= unit->files_cnt) {
+                        state_file = unit->files + (state->file - 1);
+                    }
+                    if (file != state_file) {
+                        file = state_file;
+                        out->write(out, ',');
+                        json_write_string(out, "File");
+                        out->write(out, ':');
+                        json_write_string(out, file == NULL ? NULL : file->name);
+                        out->write(out, ',');
+                        json_write_string(out, "Dir");
+                        out->write(out, ':');
+                        json_write_string(out, file == NULL ? NULL : file->dir);
+                    }
+                    out->write(out, ',');
+                    json_write_string(out, "SAddr");
+                    out->write(out, ':');
+                    json_write_ulong(out, state->address);
+                    out->write(out, ',');
+                    json_write_string(out, "EAddr");
+                    out->write(out, ':');
+                    json_write_ulong(out, next->address);
+                    if (state->isa != 0) {
+                        out->write(out, ',');
+                        json_write_string(out, "ISA");
+                        out->write(out, ':');
+                        json_write_ulong(out, state->isa);
+                    }
+                    if (state->is_stmt) {
+                        out->write(out, ',');
+                        json_write_string(out, "IsStmt");
+                        out->write(out, ':');
+                        json_write_boolean(out, state->is_stmt);
+                    }
+                    if (state->basic_block) {
+                        out->write(out, ',');
+                        json_write_string(out, "BasicBlock");
+                        out->write(out, ':');
+                        json_write_boolean(out, state->basic_block);
+                    }
+                    if (state->prologue_end) {
+                        out->write(out, ',');
+                        json_write_string(out, "PrologueEnd");
+                        out->write(out, ':');
+                        json_write_boolean(out, state->prologue_end);
+                    }
+                    if (state->epilogue_begin) {
+                        out->write(out, ',');
+                        json_write_string(out, "EpilogueBegin");
+                        out->write(out, ':');
+                        json_write_boolean(out, state->epilogue_begin);
+                    }
+                    out->write(out, '}');
+                    cnt++;
+                }
+            }
+
+            addr0 = next;
+        }
+        out->write(out, ']');
+        out->write(out, 0);
+    }
+    out->write(out, MARKER_EOM);
+    if (cache != NULL) elf_close(cache->file);
+}
+
+void ini_line_numbers_service(void) {
+    elf_add_close_listener(free_line_numbers_cache);
+    add_command_handler(LINENUMBERS, "mapToSource", command_map_to_source);
+}
+
+#endif
+
diff --git a/linenumbers.h b/linenumbers.h
new file mode 100644
index 0000000..fad5ef2
--- /dev/null
+++ b/linenumbers.h
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF service Line Numbers
+ * The service associates locations in the source files with the corresponding
+ * machine instruction addresses in the executable object.
+ */
+
+#ifndef D_linenumbers
+#define D_linenumbers
+
+/*
+ * Initialize Line Numbers service.
+ */
+extern void ini_line_numbers_service(void);
+
+
+#endif
diff --git a/link.h b/link.h
new file mode 100644
index 0000000..f994418
--- /dev/null
+++ b/link.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Double linked list support.
+ */
+
+#ifndef D_link
+#define D_link
+
+typedef struct LINK LINK;
+
+struct LINK {
+    LINK * next;
+    LINK * prev;
+};
+
+#define list_init(list) (list)->next = (list)->prev = (list)
+
+#define list_is_empty(list) ((list)->next == (list) && (list)->prev == (list))
+
+#define list_remove(item) (item)->prev->next = (item)->next; \
+        (item)->next->prev = (item)->prev
+
+#define list_add_first(item,list) (item)->next = (list)->next; (item)->prev = (list); \
+        (list)->next->prev = (item); (list)->next = (item)
+
+#define list_add_last(item,list)  (item)->next = (list); (item)->prev = (list)->prev; \
+        (list)->prev->next = (item); (list)->prev = (item)
+
+#define list_concat(item,list) if(!list_is_empty(list)) { \
+            (item)->prev->next = (list)->next; \
+            (list)->next->prev = (item)->prev; \
+            (item)->prev = (list)->prev; \
+            (list)->prev->next = (item); \
+        }
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..9d56f28
--- /dev/null
+++ b/main.c
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Agent main module.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include "mdep.h"
+#include "events.h"
+#include "trace.h"
+#include "expressions.h"
+#include "cmdline.h"
+#include "context.h"
+#include "channel.h"
+#include "protocol.h"
+#include "runctrl.h"
+#include "registers.h"
+#include "stacktrace.h"
+#include "memory.h"
+#include "breakpoints.h"
+#include "diagnostics.h"
+#include "filesystem.h"
+#include "processes.h"
+#include "symbols.h"
+#include "linenumbers.h"
+#include "proxy.h"
+#include "sysmon.h"
+
+static char * progname;
+
+#if defined(_WRS_KERNEL)
+int tcf(void) {
+#else	
+int main(int argc, char **argv) {
+#endif
+    int c;
+    int ind;
+    int interactive = 0;
+    char *s;
+    char *log_name = 0;
+    int port = 1534;
+
+    ini_mdep();
+    ini_trace();
+    ini_events_queue();
+    ini_expression_library();
+
+#if defined(_WRS_KERNEL)
+    
+    progname = "tcf";
+    log_file = stdout;
+    log_mode = 0;
+    
+#else
+    
+    progname = argv[0];
+
+    /* Parse arguments */
+    for (ind = 1; ind < argc; ind++) {
+        s = argv[ind];
+        if (*s != '-') {
+            break;
+        }
+        s++;
+        while ((c = *s++) != '\0') {
+            switch (c) {
+            case 'i':
+                interactive = 1;
+                break;
+
+            case 'l':
+            case 'L':
+                if (*s == '\0') {
+                    if (++ind >= argc) {
+                        fprintf(stderr, "%s: error: no argument given to option '%c'\n", progname, c);
+                        exit(1);
+                    }
+                    s = argv[ind];
+                }
+                switch (c) {
+                case 'l':
+                    log_mode = strtol(s, 0, 0);
+                    break;
+
+                case 'L':
+                    log_name = s;
+                    break;
+
+                default:
+                    fprintf(stderr, "%s: error: illegal option '%c'\n", progname, c);
+                    exit(1);
+                }
+                s = "";
+                break;
+
+            default:
+                fprintf(stderr, "%s: error: illegal option '%c'\n", progname, c);
+                exit(1);
+            }
+        }
+    }
+    
+    /* Create log file */
+    if (log_name == 0) {
+        log_file = NULL;
+    }
+    else if (strcmp(log_name, "-") == 0) {
+        log_file = stderr;
+    }
+    else if ((log_file = fopen(log_name, "a")) == NULL) {
+        fprintf(stderr, "%s: error: cannot create log file %s\n", progname, log_name);
+        exit(1);
+    }
+    
+#endif
+
+    if (interactive) ini_cmdline_handler();
+
+    ini_protocol();
+#if SERVICE_RunControl
+    ini_run_ctrl_service();
+#endif
+#if SERVICE_Breakpoints
+    ini_breakpoints_service();
+#endif
+#if SERVICE_Memory
+    ini_memory_service();
+#endif
+#if SERVICE_Registers
+    ini_registers_service();
+#endif
+#if SERVICE_StackTrace
+    ini_stack_trace_service();
+#endif
+#if SERVICE_Symbols
+    ini_symbols_service();
+#endif
+#if SERVICE_LineNumbers
+    ini_line_numbers_service();
+#endif
+#if SERVICE_Processes
+    ini_processes_service();
+#endif
+#if SERVICE_FileSystem
+    ini_file_system_service();
+#endif
+#if SERVICE_SysMonitor
+    ini_sys_mon_service();
+#endif
+    ini_diagnostics_service();
+    ini_proxy_service();
+    ini_contexts();
+    ini_channel_manager(port);
+
+    /* Process events - must run on the initial thread since ptrace()
+     * returns ECHILD otherwise, thinking we are not the owner. */
+    run_event_loop();
+    return 0;
+}
diff --git a/mdep.c b/mdep.c
new file mode 100644
index 0000000..d4e7d12
--- /dev/null
+++ b/mdep.c
@@ -0,0 +1,621 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Machine and OS dependend definitions.
+ * This module implements host OS abstraction layer that helps make
+ * agent code portable between Linux, Windows, VxWorks and potentially other OSes.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include "mdep.h"
+
+pthread_attr_t pthread_create_attr;
+
+#ifdef WIN32
+
+#include <fcntl.h>
+#include <shlobj.h>
+
+#define ERR_SOCKET (-1)
+#define ERR_WIN32  (-2)
+
+/*********************************************************************
+    Support of pthreads on Windows is implemented according to
+    reccomendations from the paper:
+    
+    Strategies for Implementing POSIX Condition Variables on Win32
+    C++ Report, SIGS, Vol. 10, No. 5, June, 1998
+
+    Douglas C. Schmidt and Irfan Pyarali
+    Department of Computer Science
+    Washington University, St. Louis, Missouri
+**********************************************************************/
+
+void pthread_mutex_init(pthread_mutex_t * mutex, void * attr) {
+    assert(attr == NULL);
+    *mutex = CreateMutex(NULL, FALSE, NULL);
+    if (*mutex == NULL) {
+        fprintf(stderr, "Can't create mutex: error %d\n", GetLastError());
+        exit(1);
+    }
+}
+
+void pthread_mutex_lock(pthread_mutex_t * mutex) {
+    assert(mutex != NULL);
+    assert(*mutex != NULL);
+    WaitForSingleObject(*mutex, INFINITE);
+}
+
+void pthread_mutex_unlock(pthread_mutex_t * mutex) {
+    assert(mutex != NULL);
+    assert(*mutex != NULL);
+    ReleaseMutex(*mutex);
+}
+
+void pthread_cond_init(pthread_cond_t * cond, void * attr) {
+    assert(attr == NULL);
+    cond->waiters_count = 0;
+    cond->was_broadcast = 0;
+    cond->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
+    InitializeCriticalSection(&cond->waiters_count_lock);
+    cond->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) {
+    DWORD res = 0;
+    int last_waiter = 0;
+
+    EnterCriticalSection(&cond->waiters_count_lock);
+    cond->waiters_count++;
+    LeaveCriticalSection(&cond->waiters_count_lock);
+
+    // This call atomically releases the mutex and waits on the
+    // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
+    // are called by another thread.
+    res = SignalObjectAndWait(*mutex, cond->sema, INFINITE, FALSE);
+
+    // Reacquire lock to avoid race conditions.
+    EnterCriticalSection(&cond->waiters_count_lock);
+
+    // We're no longer waiting...
+    cond->waiters_count--;
+
+    // Check to see if we're the last waiter after <pthread_cond_broadcast>.
+    last_waiter = cond->was_broadcast && cond->waiters_count == 0;
+
+    LeaveCriticalSection(&cond->waiters_count_lock);
+
+    // If we're the last waiter thread during this particular broadcast
+    // then let all the other threads proceed.
+    if (last_waiter) {
+        // This call atomically signals the <waiters_done_> event and waits until
+        // it can acquire the <mutex>.  This is required to ensure fairness. 
+        SignalObjectAndWait(cond->waiters_done, *mutex, INFINITE, FALSE);
+    }
+    else {
+        // Always regain the external mutex since that's the guarantee we
+        // give to our callers. 
+        WaitForSingleObject(*mutex, INFINITE);
+    }
+    assert(res == WAIT_OBJECT_0);
+    return 0;
+}
+
+int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, struct timespec * timeout) {
+    DWORD res = 0;
+    int last_waiter = 0;
+
+    EnterCriticalSection(&cond->waiters_count_lock);
+    cond->waiters_count++;
+    LeaveCriticalSection(&cond->waiters_count_lock);
+
+    // This call atomically releases the mutex and waits on the
+    // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
+    // are called by another thread.
+    res = SignalObjectAndWait(*mutex, cond->sema, timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000, FALSE);
+
+    // Reacquire lock to avoid race conditions.
+    EnterCriticalSection(&cond->waiters_count_lock);
+
+    // We're no longer waiting...
+    cond->waiters_count--;
+
+    // Check to see if we're the last waiter after <pthread_cond_broadcast>.
+    last_waiter = cond->was_broadcast && cond->waiters_count == 0;
+
+    LeaveCriticalSection(&cond->waiters_count_lock);
+
+    // If we're the last waiter thread during this particular broadcast
+    // then let all the other threads proceed.
+    if (last_waiter) {
+        // This call atomically signals the <waiters_done> event and waits until
+        // it can acquire the <mutex>.  This is required to ensure fairness. 
+        SignalObjectAndWait(cond->waiters_done, *mutex, INFINITE, FALSE);
+    }
+    else {
+        // Always regain the external mutex since that's the guarantee we
+        // give to our callers. 
+        WaitForSingleObject(*mutex, INFINITE);
+    }
+
+    if (res == WAIT_TIMEOUT) return errno = ETIMEDOUT;
+    assert(res == WAIT_OBJECT_0);
+    return 0;
+}
+
+void pthread_cond_signal(pthread_cond_t *cond) {
+    int have_waiters = 0;
+    
+    EnterCriticalSection(&cond->waiters_count_lock);
+    have_waiters = cond->waiters_count > 0;
+    LeaveCriticalSection(&cond->waiters_count_lock);
+
+    // If there aren't any waiters, then this is a no-op.  
+    if (have_waiters) ReleaseSemaphore(cond->sema, 1, 0);
+}
+
+void pthread_cond_broadcast(pthread_cond_t *cond) {
+    int have_waiters = 0;
+
+    // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
+    // consistent relative to each other.
+    EnterCriticalSection(&cond->waiters_count_lock);
+
+    if (cond->waiters_count > 0) {
+        // We are broadcasting, even if there is just one waiter...
+        // Record that we are broadcasting, which helps optimize
+        // <pthread_cond_wait> for the non-broadcast case.
+        cond->was_broadcast = 1;
+        have_waiters = 1;
+    }
+
+    if (have_waiters) {
+        // Wake up all the waiters atomically.
+        ReleaseSemaphore(cond->sema, cond->waiters_count, 0);
+
+        LeaveCriticalSection(&cond->waiters_count_lock);
+
+        // Wait for all the awakened threads to acquire the counting
+        // semaphore. 
+        WaitForSingleObject(cond->waiters_done, INFINITE);
+        // This assignment is okay, even without the <waiters_count_lock_> held 
+        // because no other waiter threads can wake up to access it.
+        cond->was_broadcast = 0;
+    }
+    else {
+        LeaveCriticalSection(&cond->waiters_count_lock);
+    }
+}
+
+typedef struct ThreadArgs ThreadArgs;
+
+struct ThreadArgs {
+    void * (*start)(void *);
+    void * args;
+};
+
+static void start_thread(void * x) {
+    ThreadArgs a = *(ThreadArgs *)x;
+
+    free(x);
+    ExitThread((DWORD)a.start(a.args));
+}
+
+int pthread_create(pthread_t * thread, pthread_attr_t * attr,
+                   void * (*start)(void *), void * args) {
+    unsigned long r;
+    ThreadArgs * a;
+
+    a = (ThreadArgs *)malloc(sizeof(ThreadArgs));
+    a->start = start;
+    a->args = args;
+    r = _beginthread(start_thread, 0, a);
+    if (r == (unsigned long)-1) {
+        int error = errno;
+        free(a);
+        errno = error;
+        return error;
+    }
+    *thread = (HANDLE)r;
+    return 0;
+}
+
+int pthread_join(pthread_t thread, void **value_ptr) {
+    if (WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) {
+        return EINVAL;
+    }
+    if (!GetExitCodeThread(thread, (LPDWORD)value_ptr)) {
+        return EINVAL;
+    }
+    CloseHandle(thread);
+    return 0;
+}
+
+pthread_t pthread_self(void) {
+    return GetCurrentThread();
+}
+
+static __int64 file_time_to_unix_time (const FILETIME * ft) {
+    __int64 res = (__int64)ft->dwHighDateTime << 32;
+
+    res |= ft->dwLowDateTime;
+    res /= 10;                  /* from 100 nano-sec periods to usec */
+    res -= 11644473600000000u;  /* from Win epoch to Unix epoch */
+    return res;
+}
+
+int clock_gettime(clockid_t clock_id, struct timespec * tp) {
+    FILETIME ft;
+    __int64 tim;
+
+    assert(clock_id == CLOCK_REALTIME);
+    if (!tp) {
+        errno = EINVAL;
+        return -1;
+    }
+    GetSystemTimeAsFileTime(&ft);
+    tim = file_time_to_unix_time(&ft);
+    tp->tv_sec  = (long)(tim / 1000000L);
+    tp->tv_nsec = (long)(tim % 1000000L) * 1000;
+    return 0;
+}
+
+void usleep(useconds_t useconds) {
+    Sleep(useconds / 1000);
+}
+
+void perror(const char * msg) {
+    int error = errno;
+    if (error == ERR_SOCKET) {
+        fprintf(stderr, "%s: socket error 0x%08x\n", msg, WSAGetLastError());
+    }
+    else if (error == ERR_WIN32) {
+        fprintf(stderr, "%s: Win32 error 0x%08x\n", msg, GetLastError());
+    }
+    else {
+        fprintf(stderr, "%s: %s\n", msg, strerror(error));
+    }
+}
+
+#undef bind
+int wsa_bind(int socket, const struct sockaddr * addr, int addr_size) {
+    int res = 0;
+    SetLastError(0);
+    WSASetLastError(0);
+    res = bind(socket, addr, addr_size);
+    if (res != 0) {
+        errno = ERR_SOCKET;
+        return -1;
+    }
+    return 0;
+}
+
+#undef socket
+int wsa_socket(int af, int type, int protocol) {
+    int res = 0;
+    SetLastError(0);
+    WSASetLastError(0);
+    res = socket(af, type, protocol);
+    if (res < 0) {
+        errno = ERR_SOCKET;
+        return -1;
+    }
+    return res;
+}
+
+int truncate(const char * path, int64 size) {
+    int res = 0;
+    int f = _open(path, _O_RDWR | _O_BINARY);
+    if (f < 0) return -1;
+    res = ftruncate(f, size);
+    _close(f);
+    return res;
+}
+
+int ftruncate(int fd, int64 size) {
+    int64 cur, pos;
+    BOOL ret = FALSE;
+    HANDLE handle = (HANDLE)_get_osfhandle(fd);
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        errno = EBADF;
+        return -1;
+    }
+    /* save the current file pointer */
+    cur = _lseeki64(fd, 0, SEEK_CUR);
+    if (cur >= 0) {
+        pos = _lseeki64(fd, size, SEEK_SET);
+        if (pos >= 0) {
+            ret = SetEndOfFile(handle);
+            if (!ret) errno = EBADF;
+        }
+        /* restore the file pointer */
+        _lseeki64(fd, cur, SEEK_SET);
+    }
+    return ret ? 0 : -1;
+}
+
+DIR * opendir(const char *path) {
+    DIR * d = (DIR *)malloc(sizeof(DIR));
+    if (!d) { errno = ENOMEM; return 0; }
+    strcpy(d->path, path);
+    strcat(d->path, "/*.*");
+    d->hdl = -1;
+    return d;
+}
+
+struct dirent * readdir(DIR *d) {
+    static struct dirent de;
+    if (d->hdl < 0) {
+        d->hdl = _findfirsti64(d->path, &d->blk);
+        if (d->hdl < 0) {
+            if (errno == ENOENT) errno = 0;
+            return 0;
+        }
+    }
+    else {
+        int r = _findnexti64(d->hdl, &d->blk);
+        if (r < 0) {
+            if (errno == ENOENT) errno = 0;
+            return 0;
+        }
+    }
+    strcpy(de.d_name, d->blk.name);
+    de.d_size = d->blk.size;
+    de.d_atime = d->blk.time_access;
+    de.d_ctime = d->blk.time_create;
+    de.d_wtime = d->blk.time_write;
+    return &de;
+}
+
+int closedir(DIR * d) {
+    int r = 0;
+    if (!d) {
+        errno = EBADF;
+        return -1;
+    }
+    if (d->hdl >= 0) r = _findclose(d->hdl);
+    free(d);
+    return r;
+}
+
+char * canonicalize_file_name(const char * path) {
+    char buf[MAX_PATH];
+    char * basename;
+    int i = 0;
+    DWORD len = GetFullPathName(path, sizeof(buf), buf, &basename);
+    if (len == 0) {
+        errno = ENOENT;
+        return NULL;
+    }
+    if (len > MAX_PATH - 1) {
+        errno = ENAMETOOLONG;
+        return NULL;
+    }
+    while (buf[i] != 0) {
+        if (buf[i] == '\\') buf[i] = '/';
+        i++;
+    }
+    return strdup(buf);
+}
+
+int getuid(void) {
+    /* Windows user is always a superuser :) */
+    return 0;
+}
+
+int geteuid(void) {
+    return 0;
+}
+
+int getgid(void) {
+    return 0;
+}
+
+int getegid(void) {
+    return 0;
+}
+
+char * get_os_name(void) {
+    static char str[256];
+    OSVERSIONINFOEX info;
+    memset(&info, 0, sizeof(info));
+    info.dwOSVersionInfoSize = sizeof(info);
+    GetVersionEx((OSVERSIONINFO *)&info);
+    switch (info.dwMajorVersion) {
+    case 4:
+        return "Windows NT";
+    case 5:
+        switch (info.dwMinorVersion) {
+        case 0: return "Windows 2000";
+        case 1: return "Windows XP";
+        case 2: return "Windows Server 2003";
+        }
+        break;
+    case 6:
+        return "Windows Vista";
+    }
+    snprintf(str, sizeof(str), "Windows %d.%d", info.dwMajorVersion, info.dwMajorVersion);
+    return str;
+}
+
+char * get_user_home(void) {
+    static char buf[MAX_PATH];
+    if (buf[0] != 0) return buf;
+    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, buf))) return buf;
+    return NULL;
+}
+
+void ini_mdep(void) {
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int err;
+    wVersionRequested = MAKEWORD( 1, 1 );
+    err = WSAStartup( wVersionRequested, &wsaData );
+    if ( err != 0 ) {
+        fprintf(stderr, "Couldn't access winsock.dll.\n");
+        exit(1);
+    }
+    /* Confirm that the Windows Sockets DLL supports 1.1.*/
+    /* Note that if the DLL supports versions greater */
+    /* than 1.1 in addition to 1.1, it will still return */
+    /* 1.1 in wVersion since that is the version we */
+    /* requested.     */
+    if (LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1) {
+        fprintf(stderr, "Unacceptable version of winsock.dll.\n");
+        WSACleanup();
+        exit(1);
+    }
+}
+
+#elif defined(_WRS_KERNEL)
+
+void usleep(useconds_t useconds) {
+    struct timespec tv;
+    tv.tv_sec = useconds / 1000000;
+    tv.tv_nsec = (useconds % 1000000) * 1000;
+    nanosleep(&tv, NULL);
+}
+
+int truncate(char * path, int64 size) {
+    int f = open(path, O_RDWR, 0);
+    if (f < 0) return -1;
+    if (ftruncate(f, size) < 0) {
+	int err = errno;
+	close(f);
+	errno = err;
+	return -1;
+    }
+    return close(f);
+}
+
+char * canonicalize_file_name(const char * path) {
+    char buf[PATH_MAX];
+    int i = 0, j = 0;
+    if (path[0] == '.' && (path[1] == '/' || path[1] == '\\' || path[1] == 0)) {
+    	getcwd(buf, sizeof(buf));
+    	j = strlen(buf);
+    	if (j == 1 && buf[0] == '/') j = 0;
+    	i = 1;
+    }
+    else if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\' || path[2] == 0)) {
+    	getcwd(buf, sizeof(buf));
+    	j = strlen(buf);
+	while (j > 0 && buf[j - 1] != '/') j--;
+	if (j > 0 && buf[j - 1] == '/') j--;
+    	i = 2;
+    }
+    while (path[i] && j < PATH_MAX - 1) {
+    	char ch = path[i];
+    	if (ch == '\\') ch = '/';
+    	if (ch == '/') {
+    	    if (path[i + 1] == '/' || path[i + 1] == '\\') {
+        	i++;
+        	continue;
+    	    }
+    	    if (path[i + 1] == '.') {
+    		if (path[i + 2] == 0) {
+    		    break;
+    		}
+    		if (path[i + 2] == '/' || path[i + 2] == '\\') {
+    		    i += 2;
+    		    continue;
+    		}
+    		if ((j == 0 || buf[0] == '/') && path[i + 2] == '.') {
+    		    if (path[i + 3] == '/' || path[i + 3] == '\\' || path[i + 3] == 0) {
+    			while (j > 0 && buf[j - 1] != '/') j--;
+    			if (j > 0 && buf[j - 1] == '/') j--;
+    			i += 3;
+    			continue;
+    		    }
+    		}
+    	    }
+    	}
+    	buf[j++] = ch;
+    	i++;
+    }
+    if (j == 0 && path[0] != 0) buf[j++] = '/';
+    buf[j] = 0;
+    return strdup(buf);
+}
+
+int getuid(void) {
+    return 0;
+}
+
+int geteuid(void) {
+    return 0;
+}
+
+int getgid(void) {
+    return 0;
+}
+
+int getegid(void) {
+    return 0;
+}
+
+char * get_os_name(void) {
+    static char str[256];
+    snprintf(str, sizeof(str), "VxWorks %s", kernelVersion());
+    return str;
+}
+
+char * get_user_home(void) {
+    return "/";
+}
+
+void ini_mdep(void) {
+    pthread_attr_init(&pthread_create_attr);
+    pthread_attr_setstacksize(&pthread_create_attr, 0x4000);
+    pthread_attr_setname(&pthread_create_attr, "tTcf");
+}
+
+#else
+
+#include <pwd.h>
+#include <sys/utsname.h>
+#include <asm/unistd.h>
+
+char * get_os_name(void) {
+    static char str[256];
+    struct utsname info;
+    memset(&info, 0, sizeof(info));
+    uname(&info);
+    assert(strlen(info.sysname) + strlen(info.release) < sizeof(str));
+    snprintf(str, sizeof(str), "%s %s", info.sysname, info.release);
+    return str;
+}
+
+char * get_user_home(void) {
+    static char buf[PATH_MAX];
+    if (buf[0] == 0) {
+        struct passwd * pwd = getpwuid(getuid());
+        if (pwd == NULL) return NULL;
+        strcpy(buf, pwd->pw_dir);
+    }
+    return buf;
+}
+
+int tkill(pid_t pid, int signal) {
+    return syscall(__NR_tkill, pid, signal);
+}
+
+void ini_mdep(void) {
+    pthread_attr_init(&pthread_create_attr);
+    pthread_attr_setstacksize(&pthread_create_attr, 0x8000);
+}
+
+#endif
+
diff --git a/mdep.h b/mdep.h
new file mode 100644
index 0000000..454ecf6
--- /dev/null
+++ b/mdep.h
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Machine and OS dependend definitions.
+ * This module implements host OS abstraction layer that helps make
+ * agent code portable between Linux, Windows, VxWorks and potentially other OSes.
+ */
+
+#ifndef D_mdep
+#define D_mdep
+
+#ifdef WIN32
+/* MS Windows NT/XP */
+
+#define _WIN32_WINNT 0x0400
+#pragma warning(disable:4615)
+
+#include <windows.h>
+#include <winsock.h>
+#include <memory.h>
+#include <process.h>
+#include <IPHlpApi.h>
+#include <time.h>
+#include <io.h>
+
+#define FILE_PATH_SIZE MAX_PATH
+
+typedef int socklen_t;
+#ifdef __GNUC__
+#define _WIN32_IE 0x0500
+#else
+#define __i386__
+typedef unsigned long pid_t;
+#endif
+typedef unsigned long useconds_t;
+
+typedef struct {
+    unsigned long ebx, ecx, edx, esi, edi, ebp, eax;
+    unsigned short ds, __ds, es, __es;
+    unsigned short fs, __fs, gs, __gs;
+    unsigned long orig_eax, eip;
+    unsigned short cs, __cs;
+    long eflags, esp;
+    unsigned short ss, __ss;
+} REG_SET;
+
+#define get_regs_PC(x) x.eip
+#define set_regs_PC(x,y) x.eip = (unsigned long)(y)
+
+struct timespec {
+    time_t  tv_sec;         /* seconds */
+    long    tv_nsec;        /* nanoseconds */
+};
+
+#define SIGTRAP 5
+#define SIGKILL 9
+#define SIGSTOP 19
+
+#define ETIMEDOUT 100
+
+#define vsnprintf _vsnprintf
+
+#define CLOCK_REALTIME 1
+typedef int clockid_t;
+extern int clock_gettime(clockid_t clock_id, struct timespec * tp); 
+
+extern void usleep(useconds_t useconds);
+
+/*
+ * PThreads emulation.
+ */
+typedef HANDLE pthread_t;
+typedef HANDLE pthread_mutex_t;
+typedef int pthread_attr_t;
+typedef struct {
+    int waiters_count;
+    CRITICAL_SECTION waiters_count_lock;
+    HANDLE sema;
+    HANDLE waiters_done;
+    size_t was_broadcast;
+} pthread_cond_t;
+
+extern void pthread_mutex_init(pthread_mutex_t * mutex, void * attr);
+extern void pthread_cond_init(pthread_cond_t * cond, void * attr);
+
+extern void pthread_cond_signal(pthread_cond_t * cond);
+extern void pthread_cond_broadcast(pthread_cond_t *cond);
+extern int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);
+extern int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+                                  struct timespec * timeout);
+extern void pthread_mutex_lock(pthread_mutex_t * mutex);
+extern void pthread_mutex_unlock(pthread_mutex_t * mutex);
+extern pthread_t pthread_self(void);
+extern int pthread_create(pthread_t * thread, pthread_attr_t * attr,
+                          void * (*start_routine)(void *), void * arg);
+extern int pthread_join(pthread_t thread, void **value_ptr);
+
+/*
+ * Windows socket functions don't set errno as expected.
+ * Wrappers are provided to workaround the problem.
+ * TODO: more socket function wrappers are needed for better error reports on Windows
+ */
+#define socket(af, type, protocol) wsa_socket(af, type, protocol)
+#define bind(socket, addr, addr_size) wsa_bind(socket, addr, addr_size)
+extern int wsa_bind(int socket, const struct sockaddr * addr, int addr_size);
+extern int wsa_socket(int af, int type, int protocol);
+
+typedef __int64 int64;
+typedef unsigned __int64 uns64;
+#define lseek _lseeki64
+typedef struct _stati64 struct_stat;
+#define stat _stati64
+#define lstat _stati64
+#define fstat _fstati64
+extern int truncate(const char * path, int64 size);
+extern int ftruncate(int f, int64 size);
+#define utimbuf _utimbuf
+#define utime _utime
+#define futime _futime
+#define snprintf _snprintf
+
+struct DIR {
+  long hdl;
+  struct _finddatai64_t blk;
+  char path[FILE_PATH_SIZE];
+};
+
+struct dirent {
+  char d_name[FILE_PATH_SIZE];
+  int64 d_size;
+  time_t d_atime;
+  time_t d_ctime;
+  time_t d_wtime;
+};
+
+typedef struct DIR DIR;
+
+extern DIR * opendir(const char * path);
+extern int closedir(DIR * dir);
+extern struct dirent * readdir(DIR * dir);
+
+extern char * canonicalize_file_name(const char * path);
+
+#define O_LARGEFILE 0
+
+extern int getuid(void);
+extern int geteuid(void);
+extern int getgid(void);
+extern int getegid(void);
+
+#elif defined(_WRS_KERNEL)
+/* VxWork kernel module */
+
+#define INET
+
+#include <vxWorks.h>
+#include <regs.h>
+#include <pthread.h>
+#include <sys/ioctl.h> 
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <wrn/coreip/sockLib.h>
+#include <wrn/coreip/hostLib.h>
+
+#define environ taskIdCurrent->ppEnviron
+
+#define get_regs_PC(x) (*(int *)((int)&(x) + PC_OFFSET))
+#define set_regs_PC(x,y) *(int *)((int)&(x) + PC_OFFSET) = (int)(y)
+
+#define closesocket close
+
+typedef long long int64;
+typedef unsigned long long uns64;
+typedef unsigned long useconds_t;
+
+#define FILE_PATH_SIZE PATH_MAX
+#define O_BINARY 0
+#define O_LARGEFILE 0
+#define lstat stat
+typedef struct stat struct_stat;
+#define ifr_netmask ifr_addr
+#define SA_LEN(addr) ((addr)->sa_len)  
+
+extern int truncate(char * path, int64 size);
+extern char * canonicalize_file_name(const char * path);
+
+extern void usleep(useconds_t useconds);
+
+extern int getuid(void);
+extern int geteuid(void);
+extern int getgid(void);
+extern int getegid(void);
+
+#else
+/* Linux or UNIX */
+
+#ifndef _LARGEFILE_SOURCE
+#error "Need CC command line option: -D_LARGEFILE_SOURCE"
+#endif
+
+#ifndef _GNU_SOURCE
+#error "Need CC command line option: -D_GNU_SOURCE"
+#endif
+
+#include <unistd.h>
+#include <memory.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/ioctl.h> 
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <net/if.h> 
+
+#define FILE_PATH_SIZE PATH_MAX
+
+#define closesocket close
+
+typedef __int64_t int64;
+typedef __uint64_t uns64;
+typedef struct user_regs_struct REG_SET; 
+typedef struct stat struct_stat;
+#define O_BINARY 0
+
+#define get_regs_PC(x) x.eip
+#define set_regs_PC(x,y) x.eip = (unsigned long)(y)
+
+#ifndef SA_LEN  
+# ifdef HAVE_SOCKADDR_SA_LEN  
+#  define SA_LEN(addr) ((addr)->sa_len)  
+# else /* HAVE_SOCKADDR_SA_LEN */  
+#  ifdef HAVE_STRUCT_SOCKADDR_STORAGE  
+static size_t get_sa_len(const struct sockaddr *addr) {  
+    switch (addr->sa_family) {  
+#   ifdef AF_UNIX  
+        case AF_UNIX: return sizeof(struct sockaddr_un);
+#   endif
+#   ifdef AF_INET  
+        case AF_INET: return (sizeof (struct sockaddr_in));  
+#   endif  
+#   ifdef AF_INET6  
+        case AF_INET6: return (sizeof (struct sockaddr_in6));  
+#   endif  
+        default: return (sizeof (struct sockaddr));  
+    }  
+}  
+#   define SA_LEN(addr)   (get_sa_len(addr))  
+#  else /* HAVE_SOCKADDR_STORAGE */  
+#   define SA_LEN(addr)   (sizeof (struct sockaddr))  
+#  endif /* HAVE_SOCKADDR_STORAGE */  
+# endif /* HAVE_SOCKADDR_SA_LEN */  
+#endif /* SA_LEN */  
+
+extern int tkill(pid_t pid, int signal);
+
+#endif
+
+extern pthread_attr_t pthread_create_attr;
+
+extern char * get_os_name(void);
+extern char * get_user_home(void);
+
+extern void ini_mdep(void);
+
+#endif
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..44d8a43
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,579 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Memory - memory access service.
+ */
+
+#include "config.h"
+#if SERVICE_Memory
+
+#include <assert.h>
+#include "mdep.h"
+#include "protocol.h"
+#include "context.h"
+#include "json.h"
+#include "exceptions.h"
+#include "runctrl.h"
+#include "myalloc.h"
+#include "channel.h"
+#include "base64.h"
+
+static const char * MEMORY = "Memory";
+
+#define BYTE_VALID        0x00
+#define BYTE_UNKNOWN      0x01
+#define BYTE_INVALID      0x02
+#define BYTE_CANNOT_READ  0x04
+#define BYTE_CANNOT_WRITE 0x08
+
+#define CMD_GET     1
+#define CMD_SET     2
+#define CMD_FILL    3
+
+#define BUF_SIZE    0x1000
+
+struct MemoryCommandArgs {
+    InputStream * inp;
+    OutputStream * out;
+    char token[256];
+    unsigned long addr;
+    unsigned long size;
+    int word_size;
+    int mode;
+    Context * ctx;
+};
+
+static void write_context(OutputStream * out, Context * ctx) {
+    assert(!ctx->exited);
+
+    out->write(out, '{');
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, container_id(ctx));
+
+#if !defined(_WRS_KERNEL)
+    out->write(out, ',');
+    json_write_string(out, "ProcessID");
+    out->write(out, ':');
+    json_write_string(out, pid2id(ctx->mem, 0));
+#endif
+
+    /* Check endianness */
+    {
+        short n = 0x0201;
+        char * p = (char *)&n;
+        out->write(out, ',');
+        json_write_string(out, "BigEndian");
+        out->write(out, ':');
+        json_write_boolean(out, *p == 0x02);
+    }
+
+    out->write(out, ',');
+    json_write_string(out, "AddressSize");
+    out->write(out, ':');
+    json_write_ulong(out, sizeof(char *));
+    
+    out->write(out, '}');
+}
+
+static void write_ranges(OutputStream * out, unsigned long addr, int size, int offs, int status, char * msg) {
+    out->write(out, '[');
+    if (offs > 0) {
+        out->write(out, '{');
+
+        json_write_string(out, "addr");
+        out->write(out, ':');
+        json_write_ulong(out, addr);
+        out->write(out, ',');
+
+        json_write_string(out, "size");
+        out->write(out, ':');
+        json_write_ulong(out, offs);
+        out->write(out, ',');
+
+        json_write_string(out, "stat");
+        out->write(out, ':');
+        json_write_ulong(out, 0);
+
+        out->write(out, '}');
+        out->write(out, ',');
+    }
+    if (offs < size) {
+        out->write(out, '{');
+
+        json_write_string(out, "addr");
+        out->write(out, ':');
+        json_write_ulong(out, addr + offs);
+        out->write(out, ',');
+
+        json_write_string(out, "size");
+        out->write(out, ':');
+        json_write_ulong(out, size - offs);
+        out->write(out, ',');
+
+        json_write_string(out, "stat");
+        out->write(out, ':');
+        json_write_ulong(out, status);
+        out->write(out, ',');
+
+        json_write_string(out, "msg");
+        out->write(out, ':');
+        json_write_string(out, msg);
+
+        out->write(out, '}');
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    Context * ctx = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    ctx = id2ctx(id);
+    
+    if (ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    if (err == 0) {
+        write_context(out, ctx);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    write_errno(out, 0);
+
+    out->write(out, '[');
+    if (id[0] == 0) {
+        LINK * qp;
+        int cnt = 0;
+        for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+            Context * ctx = ctxl2ctxp(qp);
+            if (ctx->exited) continue;
+            if (ctx->parent != NULL) continue;
+            if (cnt > 0) out->write(out, ',');
+            json_write_string(out, container_id(ctx));
+            cnt++;
+        }
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static struct MemoryCommandArgs * read_command_args(char * token, InputStream * inp, OutputStream * out, int cmd) {
+    int err = 0;
+    char id[256];
+    struct MemoryCommandArgs buf;
+    memset(&buf, 0, sizeof(buf));
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    buf.addr = json_read_ulong(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    buf.word_size = (int)json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    buf.size = (int)json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    buf.mode = (int)json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (cmd == CMD_GET && inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    buf.ctx = id2ctx(id);
+    if (buf.ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (buf.ctx->exited) err = ERR_ALREADY_EXITED;
+
+    if (err != 0) {
+        if (cmd == CMD_SET || cmd == CMD_FILL) {
+            if (inp->read(inp) != '[') exception(ERR_JSON_SYNTAX);
+            if (inp->peek(inp) == ']') {
+                inp->read(inp);
+            }
+            else {
+                while (1) {
+                    char ch;
+                    json_read_ulong(inp);
+                    ch = inp->read(inp);
+                    if (ch == ',') continue;
+                    if (ch == ']') break;
+                    exception(ERR_JSON_SYNTAX);
+                }
+            }
+            if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        }
+        if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+        write_stringz(out, "R");
+        write_stringz(out, token);
+        write_stringz(out, "null");
+        write_errno(out, err);
+        write_stringz(out, "null");
+        out->write(out, MARKER_EOM);
+        return NULL;
+    }
+    else {
+        struct MemoryCommandArgs * args = (struct MemoryCommandArgs *)
+            loc_alloc(sizeof(struct MemoryCommandArgs));
+        *args = buf;
+        args->inp = inp;
+        args->out = out;
+        strncpy(args->token, token, sizeof(args->token));
+        stream_lock(out);
+        context_lock(buf.ctx);
+        return args;
+    }
+}
+
+static void send_event_memory_changed(OutputStream * out, Context * ctx, unsigned long addr, unsigned long size) {
+    write_stringz(out, "E");
+    write_stringz(out, MEMORY);
+    write_stringz(out, "memoryChanged");
+
+    json_write_string(out, container_id(ctx));
+    out->write(out, 0);
+
+    /* <array of addres ranges> */
+    out->write(out, '[');
+    out->write(out, '{');
+
+    json_write_string(out, "addr");
+    out->write(out, ':');
+    json_write_ulong(out, addr);
+    
+    out->write(out, ',');
+
+    json_write_string(out, "size");
+    out->write(out, ':');
+    json_write_ulong(out, size);
+    
+    out->write(out, '}');
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void safe_memory_set(void * parm) {
+    struct MemoryCommandArgs * args = (struct MemoryCommandArgs *)parm;
+    InputStream * inp = args->inp;
+    OutputStream * out = args->out;
+    char * token = args->token;
+    unsigned long addr0 = args->addr;
+    unsigned long addr = args->addr;
+    unsigned long size = 0;
+    int word_size = args->word_size;
+    int mode = args->mode;
+    Context * ctx = args->ctx;
+    char buf[BUF_SIZE];
+    int err = 0;
+
+    if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+    if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX);
+
+    for (;;) {
+        int rd = read_base64(inp, buf, sizeof(buf));
+        if (rd == 0) break;
+        if (err == 0) {
+            // TODO: word size, mode
+            if (context_write_mem(ctx, addr, buf, rd) < 0) {
+                err = errno;
+            }
+            else {
+                addr += rd;
+            }
+        }
+        size += rd;
+    }
+
+    if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    send_event_memory_changed(&broadcast_stream, ctx, addr0, size);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    if (err == 0) {
+        write_stringz(out, "null");
+    }
+    else {
+        char msg[0x400];
+        strncpy(msg, errno_to_str(err), sizeof(msg));
+        write_ranges(out, addr0, size, addr - addr0, BYTE_INVALID | BYTE_CANNOT_WRITE, msg);
+    }
+    out->write(out, MARKER_EOM);
+    out->flush(out);
+    stream_unlock(out);
+    context_unlock(ctx);
+    loc_free(args);
+}
+
+static void command_set(char * token, InputStream * inp, OutputStream * out) {
+    struct MemoryCommandArgs * args = read_command_args(token, inp, out, CMD_SET);
+    if (args != NULL) post_safe_event(safe_memory_set, args);
+}
+
+static void safe_memory_get(void * parm) {
+    struct MemoryCommandArgs * args = (struct MemoryCommandArgs *)parm;
+    OutputStream * out = args->out;
+    char * token = args->token;
+    unsigned long addr0 = args->addr;
+    unsigned long addr = args->addr;
+    unsigned long size = args->size;
+    int word_size = args->word_size;
+    int mode = args->mode;
+    Context * ctx = args->ctx;
+    char buf[BUF_SIZE + 4];
+    int buf_pos = 0;
+    int err = 0;
+    int rem = 0;
+    unsigned long chk = 0;
+
+    if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    out->write(out, '"');
+    while (err == 0 && addr < addr0 + size) {
+        int rd = addr0 + size - addr;
+        if (rd > BUF_SIZE) rd = BUF_SIZE;
+        // TODO: word size, mode
+        if (context_read_mem(ctx, addr, buf + rem, rd) < 0) {
+            err = errno;
+        }
+        else {
+            int i = 0, j = rem + rd;
+            rem = j % 3;
+            chk += write_base64(out, buf, j - rem);
+            for (i = 0; i < rem; i++) buf[i] = buf[j - rem + i];
+            addr += rd;
+        }
+    }
+    chk += write_base64(out, buf, rem);
+    out->write(out, '"');
+    out->write(out, 0);
+    assert(chk == ((addr - addr0) + 2) / 3 * 4);
+
+    write_errno(out, err);
+    if (err == 0) {
+        write_stringz(out, "null");
+    }
+    else {
+        char msg[0x400];
+        strncpy(msg, errno_to_str(err), sizeof(msg));
+        write_ranges(out, addr0, size, addr - addr0, BYTE_INVALID | BYTE_CANNOT_READ, msg);
+    }
+    out->write(out, MARKER_EOM);
+    out->flush(out);
+    stream_unlock(out);
+    context_unlock(ctx);
+    loc_free(args);
+}
+
+static void command_get(char * token, InputStream * inp, OutputStream * out) {
+    struct MemoryCommandArgs * args = read_command_args(token, inp, out, CMD_GET);
+    if (args != NULL) post_safe_event(safe_memory_get, args);
+}
+
+static void safe_memory_fill(void * parm) {
+    struct MemoryCommandArgs * args = (struct MemoryCommandArgs *)parm;
+    InputStream * inp = args->inp;
+    OutputStream * out = args->out;
+    char * token = args->token;
+    unsigned long addr0 = args->addr;
+    unsigned long addr = args->addr;
+    unsigned long size = args->size;
+    int word_size = args->word_size;
+    int mode = args->mode;
+    Context * ctx = args->ctx;
+    char buf[0x1000];
+    int buf_pos = 0;
+    int err = 0;
+
+    if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;
+
+    if (inp->read(inp) != '[') exception(ERR_JSON_SYNTAX);
+    if (inp->peek(inp) == ']') {
+        inp->read(inp);
+    }
+    else {
+        while (1) {
+            char ch;
+            if (err == 0) {
+                if (buf_pos >= sizeof(buf)) err = ERR_BUFFER_OVERFLOW;
+                else buf[buf_pos++] = (char)json_read_ulong(inp);
+            }
+            else {
+                json_read_ulong(inp);
+            }
+            ch = inp->read(inp);
+            if (ch == ',') continue;
+            if (ch == ']') break;
+            exception(ERR_JSON_SYNTAX);
+        }
+    }
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    while (err == 0 && buf_pos < (int)size && buf_pos <= sizeof(buf) / 2) {
+        if (buf_pos == 0) {
+            buf[buf_pos++] = 0;
+        }
+        else {
+            memcpy(buf + buf_pos, buf, buf_pos);
+            buf_pos *= 2;
+        }
+    }
+
+    while (err == 0 && addr < addr0 + size) {
+        int wr = addr0 + size - addr;
+        if (wr > buf_pos) wr = buf_pos;
+        // TODO: word size, mode
+        if (context_write_mem(ctx, addr, buf, wr) < 0) {
+            err = errno;
+        }
+        else {
+            addr += wr;
+        }
+    }
+
+    send_event_memory_changed(&broadcast_stream, ctx, addr0, size);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    if (err == 0) {
+        write_stringz(out, "null");
+    }
+    else {
+        char msg[0x400];
+        strncpy(msg, errno_to_str(err), sizeof(msg));
+        write_ranges(out, addr0, size, addr - addr0, BYTE_INVALID | BYTE_CANNOT_WRITE, msg);
+    }
+    out->write(out, MARKER_EOM);
+    out->flush(out);
+    stream_unlock(out);
+    context_unlock(ctx);
+    loc_free(args);
+}
+
+static void command_fill(char * token, InputStream * inp, OutputStream * out) {
+    struct MemoryCommandArgs * args = read_command_args(token, inp, out, CMD_FILL);
+    if (args != NULL) post_safe_event(safe_memory_fill, args);
+}
+
+static void send_event_context_added(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, MEMORY);
+    write_stringz(out, "contextAdded");
+
+    /* <array of context data> */
+    out->write(out, '[');
+    write_context(out, ctx);
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_changed(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, MEMORY);
+    write_stringz(out, "contextChanged");
+
+    /* <array of context data> */
+    out->write(out, '[');
+    write_context(out, ctx);
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_removed(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, MEMORY);
+    write_stringz(out, "contextRemoved");
+
+    /* <array of context IDs> */
+    out->write(out, '[');
+    json_write_string(out, container_id(ctx));
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void event_context_created(Context * ctx) {
+    if (ctx->parent != NULL) return;
+    send_event_context_added(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+static void event_context_changed(Context * ctx) {
+    if (ctx->parent != NULL) return;
+    send_event_context_changed(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+static void event_context_exited(Context * ctx) {
+    if (ctx->parent != NULL) return;
+    send_event_context_removed(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+void ini_memory_service(void) {
+    static ContextEventListener listener = {
+        event_context_created,
+        event_context_exited,
+        NULL,
+        NULL,
+        event_context_changed,
+        NULL
+    };
+    add_context_event_listener(&listener);
+    add_command_handler(MEMORY, "getContext", command_get_context);
+    add_command_handler(MEMORY, "getChildren", command_get_children);
+    add_command_handler(MEMORY, "set", command_set);
+    add_command_handler(MEMORY, "get", command_get);
+    add_command_handler(MEMORY, "fill", command_fill);
+}
+
+#endif
+
diff --git a/memory.h b/memory.h
new file mode 100644
index 0000000..3087c4e
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Memory - memory access service.
+ */
+
+#ifndef D_memory
+#define D_memory
+
+/*
+ * Initialize memory service.
+ */
+extern void ini_memory_service(void);
+
+
+#endif
diff --git a/myalloc.c b/myalloc.c
new file mode 100644
index 0000000..6abcac9
--- /dev/null
+++ b/myalloc.c
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Local memory heap manager.
+ */
+
+#include <string.h>
+#include "trace.h"
+#include "myalloc.h"
+
+void * loc_alloc(size_t size) {
+    void * p;
+
+    if (size == 0) {
+        size = 1;
+    }
+    if ((p = malloc(size)) == NULL) {
+        perror("malloc");
+        exit(1);
+    }
+    trace(LOG_ALLOC, "loc_alloc(%d) = %#x", size, p);
+    return p;
+}
+
+void * loc_alloc_zero(size_t size) {
+    void * p;
+
+    if (size == 0) {
+        size = 1;
+    }
+    if ((p = malloc(size)) == NULL) {
+        perror("malloc");
+        exit(1);
+    }
+    memset(p, 0, size);
+    trace(LOG_ALLOC, "loc_alloc_zero(%d) = %#x", size, p);
+    return p;
+}
+
+void * loc_realloc(void * ptr, size_t size) {
+    void * p;
+
+    if (size == 0) {
+        size = 1;
+    }
+    if ((p = realloc(ptr, size)) == NULL) {
+        perror("realloc");
+        exit(1);
+    }
+    trace(LOG_ALLOC, "loc_realloc(%#x, %d) = %#x", ptr, size, p);
+    return p;
+}
+
+void loc_free(void *p) {
+    trace(LOG_ALLOC, "loc_free %#x", p);
+    free(p);
+}
+
diff --git a/myalloc.h b/myalloc.h
new file mode 100644
index 0000000..1f3cc59
--- /dev/null
+++ b/myalloc.h
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Local memory heap manager.
+ */
+
+#ifndef D_myalloc
+#define D_myalloc
+
+#include <stdlib.h>
+
+void * loc_alloc(size_t size);
+void * loc_alloc_zero(size_t size);
+void * loc_realloc(void *ptr, size_t size);
+void loc_free(void *p);
+
+#endif
diff --git a/processes.c b/processes.c
new file mode 100644
index 0000000..a66d41f
--- /dev/null
+++ b/processes.c
@@ -0,0 +1,419 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Processes - process control service.
+ * Processes service provides access to the target OS's process information,
+ * allows to start and terminate a process, and allows to attach and
+ * detach a process for debugging. Debug services, like Memory and Run Control,
+ * require a process to be attached before they can access it.
+ */
+
+#include "config.h"
+#if SERVICE_Processes
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+#include "mdep.h"
+#include "myalloc.h"
+#include "protocol.h"
+#include "context.h"
+#include "json.h"
+#include "exceptions.h"
+
+static const char * PROCESSES = "Processes";
+
+#if defined(WIN32)
+#  include <direct.h>
+#elif defined(_WRS_KERNEL)
+#  include <symLib.h>
+#  include <sysSymTbl.h>
+#else
+#  include <sys/stat.h>
+#  include <fcntl.h>
+#  include <unistd.h>
+#  include <dirent.h>
+#endif
+
+static void write_context(OutputStream * out, char * id, char * dir) {
+    Context * ctx = NULL;
+
+    out->write(out, '{');
+
+#if defined(WIN32)
+#elif defined(_WRS_KERNEL)
+#else
+    if (chdir(dir) >= 0) {
+        int sz;
+        char fnm[FILE_PATH_SIZE + 1];
+
+        json_write_string(out, "CanTerminate");
+        out->write(out, ':');
+        json_write_boolean(out, 1);
+        out->write(out, ',');
+
+        if ((sz = readlink("exe", fnm, FILE_PATH_SIZE)) > 0) {
+            fnm[sz] = 0;
+            json_write_string(out, "Name");
+            out->write(out, ':');
+            json_write_string(out, fnm);
+            out->write(out, ',');
+        }
+    }
+#endif
+    
+    ctx = id2ctx(id);
+    if (ctx != NULL) {
+        json_write_string(out, "Attached");
+        out->write(out, ':');
+        json_write_boolean(out, 1);
+        out->write(out, ',');
+    }
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, id);
+
+    out->write(out, '}');
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    pid_t pid, parent;
+    char dir[FILE_PATH_SIZE];
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    pid = id2pid(id, &parent);
+    snprintf(dir, sizeof(dir), "/proc/%d", pid);
+    if (pid != 0 && parent == 0) {
+#if defined(WIN32)
+#elif defined(_WRS_KERNEL)
+        if (TASK_ID_VERIFY(pid) == ERROR) err = ERR_INV_CONTEXT;
+#else
+        struct_stat st;
+        if (lstat(dir, &st) < 0) err = errno;
+        else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+#endif
+    }
+
+    write_errno(out, err);
+    
+    if (err == 0 && pid != 0 && parent == 0) {
+        write_context(out, id, dir);
+        out->write(out, 0);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    pid_t parent = 0;
+    int attached_only;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    attached_only = json_read_boolean(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    if (id[0] != 0) {
+        write_errno(out, 0);
+        write_stringz(out, "null");
+    }
+    else {
+#if defined(WIN32)
+#elif defined(_WRS_KERNEL)
+        int i = 0;
+        int cnt = 0;
+        int ids_cnt = 0;
+        int ids_max = 500;
+        int * ids = (int *)loc_alloc(ids_max * sizeof(int));
+        while (1) {
+            ids_cnt = taskIdListGet(ids, ids_max);
+            if (ids_cnt < ids_max) break;
+            loc_free(ids);
+            ids_max *= 2;
+            ids = (int *)loc_alloc(ids_max * sizeof(int));
+        }
+        out->write(out, '[');
+        for (i = 0; i < ids_cnt; i++) {
+            if (!attached_only || context_find_from_pid(ids[i]) != NULL) {
+                if (cnt > 0) out->write(out, ',');
+                json_write_string(out, pid2id(ids[i], 0));
+                cnt++;
+            }
+        }
+        out->write(out, ']');
+        out->write(out, 0);
+#else
+        DIR * proc = opendir("/proc");
+        if (proc == NULL) {
+            write_errno(out, errno);
+            write_stringz(out, "null");
+        }
+        else {
+            int cnt = 0;
+            write_errno(out, 0);
+            out->write(out, '[');
+            for (;;) {
+                struct dirent * ent = readdir(proc);
+                if (ent == NULL) break;
+                if (ent->d_name[0] >= '1' && ent->d_name[0] <= '9') {
+                    pid_t pid = atol(ent->d_name);
+                    if (!attached_only || context_find_from_pid(pid) != NULL) {
+                        if (cnt > 0) out->write(out, ',');
+                        json_write_string(out, pid2id(pid, 0));
+                        cnt++;
+                    }
+                }
+            }
+            out->write(out, ']');
+            out->write(out, 0);
+            closedir(proc);
+        }
+#endif
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_attach(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    pid_t pid, parent;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    if (parent != 0) {
+        err = ERR_INV_CONTEXT;
+    }
+    else if (context_find_from_pid(pid) != NULL) {
+        err = ERR_ALREADY_ATTACHED;
+    }
+    else {
+        if (context_attach(pid, NULL) < 0) err = errno;
+    }
+
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_detach(char * token, InputStream * inp, OutputStream * out) {
+    // TODO: implement command_detach()
+    exception(ERR_PROTOCOL);
+}
+
+static void command_terminate(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    pid_t pid, parent;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    if (parent != 0) {
+        err = ERR_INV_CONTEXT;
+    }
+    else {
+#if defined(WIN32)
+        err = ENOSYS;
+#elif defined(_WRS_KERNEL)
+        if (kill(pid, SIGTERM) < 0) err = errno;
+#else
+        if (kill(pid, SIGTERM) < 0) err = errno;
+#endif
+    }
+
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_signal(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    int signal = 0;
+    pid_t pid, parent;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    signal = (int)json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    if (parent != 0) {
+        err = ERR_INV_CONTEXT;
+    }
+    else {
+#if defined(WIN32)
+        err = ENOSYS;
+#elif defined(_WRS_KERNEL)
+        if (kill(pid, signal) < 0) err = errno;
+#else
+        if (kill(pid, signal) < 0) err = errno;
+#endif
+    }
+
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_environment(char * token, InputStream * inp, OutputStream * out) {
+    char ** p = environ;
+
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, '[');
+    if (p != NULL) {
+        while (*p != NULL) {
+            if (p != environ) out->write(out, ',');
+            json_write_string(out, *p++);
+        }
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_start(char * token, InputStream * inp, OutputStream * out) {
+    Context * ctx = NULL;
+    int pid = 0;
+    int err = 0;
+    char dir[FILE_PATH_SIZE];
+    char exe[FILE_PATH_SIZE];
+    char ** args = NULL;
+    char ** envp = NULL;
+    int args_len = 0;
+    int envp_len = 0;
+    int attach = 0;
+    Trap trap;
+
+    if (set_trap(&trap)) {
+        json_read_string(inp, dir, sizeof(dir));
+        if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        json_read_string(inp, exe, sizeof(exe));
+        if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        args = json_read_alloc_string_array(inp, &args_len);
+        if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        envp = json_read_alloc_string_array(inp, &envp_len);
+        if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        attach = json_read_boolean(inp);
+        if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+        if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+        if (dir[0] != 0 && chdir(dir) < 0) err = errno;
+        if (err == 0) {
+#if defined(WIN32)
+#elif defined(_WRS_KERNEL)
+            char * ptr;
+            SYM_TYPE type;
+            if (symFindByName(sysSymTbl, exe, &ptr, &type) != OK) {
+                err = errno;
+                if (err == S_symLib_SYMBOL_NOT_FOUND) err = ERR_SYM_NOT_FOUND;
+                assert(err != 0);
+            }
+            else {
+                // TODO: arguments, environment
+                pid = taskCreate("tTcf", 100, 0, 0x4000, (FUNCPTR)ptr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                if (attach) {
+                    taskStop(pid);
+                    taskActivate(pid);
+                    assert(taskIsStopped(pid));
+                }
+                else {
+                    taskActivate(pid);
+                }
+            }
+#else
+            pid = fork();
+            if (pid < 0) err = errno;
+            if (pid == 0) {
+                if (attach) tkill(getpid(), SIGSTOP);
+                exit(execve(exe, args, envp));
+            }
+#endif            
+        }
+        if (attach) {
+            if (err == 0 && context_attach(pid, &ctx) < 0) err = errno;
+            if (ctx != NULL && !ctx->stopped) ctx->pending_intercept = 1;
+        }
+
+        write_stringz(out, "R");
+        write_stringz(out, token);
+        write_errno(out, err);
+        if (err || pid == 0) {
+            write_stringz(out, "null");
+        }
+        else {
+            char bf[256];
+            snprintf(dir, sizeof(dir), "/proc/%d", pid);
+            write_context(out, strcpy(bf, pid2id(pid, 0)), dir);
+            out->write(out, 0);
+        }
+        out->write(out, MARKER_EOM);
+        clear_trap(&trap);
+    }
+
+    loc_free(args);
+    loc_free(envp);
+
+    if (trap.error) exception(trap.error);
+}
+
+void ini_processes_service(void) {
+    add_command_handler(PROCESSES, "getContext", command_get_context);
+    add_command_handler(PROCESSES, "getChildren", command_get_children);
+    add_command_handler(PROCESSES, "attach", command_attach);
+    add_command_handler(PROCESSES, "detach", command_detach);
+    add_command_handler(PROCESSES, "terminate", command_terminate);
+    add_command_handler(PROCESSES, "signal", command_signal);
+    add_command_handler(PROCESSES, "getEnvironment", command_get_environment);
+    add_command_handler(PROCESSES, "start", command_start);
+}
+
+#endif
+
diff --git a/processes.h b/processes.h
new file mode 100644
index 0000000..96e2e92
--- /dev/null
+++ b/processes.h
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Processes - process control service.
+ * Processes service provides access to the target OS's process information,
+ * allows to start and terminate a process, and allows to attach and
+ * detach a process for debugging. Debug services, like Memory and Run Control,
+ * require a process to be attached before they can access it.
+ */
+
+#ifndef D_processes
+#define D_processes
+
+/*
+ * Initialize process control service.
+ */
+extern void ini_processes_service(void);
+
+
+#endif
diff --git a/protocol.c b/protocol.c
new file mode 100644
index 0000000..e9895fb
--- /dev/null
+++ b/protocol.c
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF communication protocol.
+ * This module handles registration of command and event handlers.
+ * It is called when new messages are received and will dispatch
+ * messages to the appropriate handler. It has no knowledge of what transport
+ * protocol is used and what services do.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "protocol.h"
+#include "trace.h"
+#include "exceptions.h"
+#include "json.h"
+#include "myalloc.h"
+
+static const char * LOCATOR = "Locator";
+
+struct ServiceInfo {
+    const char * name;
+    struct ServiceInfo * next;
+};
+
+typedef struct ServiceInfo ServiceInfo;
+
+struct MessageHandlerInfo {
+    char type;
+    ServiceInfo * service;
+    const char * name;
+    MessageHandler handler;
+    struct MessageHandlerInfo * next;
+};
+
+typedef struct MessageHandlerInfo MessageHandlerInfo;
+
+#define MESSAGE_HASH_SIZE 127
+static MessageHandlerInfo * message_handlers[MESSAGE_HASH_SIZE];
+static ServiceInfo * services = NULL;
+
+int congestion_level = 0;
+
+static void read_stringz(InputStream * inp, char * str, size_t size) {
+    unsigned len = 0;
+    for (;;) {
+        int ch = inp->read(inp);
+        if (ch <= 0) break;
+        if (len < size - 1) str[len] = ch;
+        len++;
+    }
+    str[len] = 0;
+}
+
+static int message_hash(const char * service, const char * name) {
+    int i;
+    int h = 0;
+    for (i = 0; service[i]; i++) h += service[i];
+    for (i = 0; name[i]; i++) h += name[i];
+    h = h + h / MESSAGE_HASH_SIZE;
+    return h % MESSAGE_HASH_SIZE;
+}
+
+static MessageHandlerInfo * find_message_handler(char type, char * service, char * name) {
+    MessageHandlerInfo * c = message_handlers[message_hash(service, name)];
+    while (c != NULL) {
+        if (c->type == type && !strcmp(c->service->name, service) && !strcmp(c->name, name)) return c;
+        c = c->next;
+    }
+    trace(LOG_ALWAYS, "Unsupported TCF message: %c %s %s ...", type, service, name);
+    exception(ERR_PROTOCOL);
+    return NULL;
+}
+
+void handle_protocol_message(InputStream * inp, OutputStream * out) {
+    char type[8];
+    char token[256];
+    char service[256];
+    char name[256];
+    read_stringz(inp, type, sizeof(type));
+    if (strlen(type) != 1) {
+        trace(LOG_ALWAYS, "Invalid TCF message: %s ...", type);
+        exception(ERR_PROTOCOL);
+    }
+    else if (type[0] == 'C') {
+        Trap trap;
+        MessageHandlerInfo * c;
+        read_stringz(inp, token, sizeof(token));
+        read_stringz(inp, service, sizeof(service));
+        read_stringz(inp, name, sizeof(name));
+        trace(LOG_PROTOCOL, "Command: C %s %s %s ...", token, service, name);
+        c = find_message_handler('C', service, name);
+        if (set_trap(&trap)) {
+            c->handler(token, inp, out);
+            clear_trap(&trap);
+        }
+        else {
+            trace(LOG_ALWAYS, "Exception handling command %s.%s: %d %s",
+                service, name, trap.error, errno_to_str(trap.error));
+            exception(trap.error);
+        }
+    }
+    else if (type[0] == 'E') {
+        Trap trap;
+        MessageHandlerInfo * c;
+        read_stringz(inp, service, sizeof(service));
+        read_stringz(inp, name, sizeof(name));
+        trace(LOG_PROTOCOL, "Event: E %s %s ...", service, name);
+        c = find_message_handler('E', service, name);
+        if (set_trap(&trap)) {
+            c->handler(NULL, inp, out);
+            clear_trap(&trap);
+        }
+        else {
+            trace(LOG_ALWAYS, "Exception handling event %s.%s: %d %s",
+                service, name, trap.error, errno_to_str(trap.error));
+            exception(trap.error);
+        }
+    }
+    else if (type[0] == 'F') {
+        int n = 0;
+        int s = 0;
+        int ch = inp->read(inp);
+        if (ch == '-') {
+            s = 1;
+            ch = inp->read(inp);
+        }
+        while (ch >= '0' && ch <= '9') {
+            n = n * 10 + (ch - '0');
+            ch = inp->read(inp);
+        }
+        if (ch != MARKER_EOM) exception(ERR_PROTOCOL);
+        congestion_level = n;
+    }
+    else {
+        trace(LOG_ALWAYS, "Invalid TCF message: %s ...", type);
+        exception(ERR_PROTOCOL);
+    }
+}
+
+static void add_message_handler(const char type, const char * service, const char * name, MessageHandler handler) {
+    int h = message_hash(service, name);
+    ServiceInfo * s = services;
+    MessageHandlerInfo * c = (MessageHandlerInfo *)loc_alloc(sizeof(MessageHandlerInfo));
+    while (s != NULL && strcmp(s->name, service) != 0) s = s->next;
+    if (s == NULL) {
+        s = (ServiceInfo *)loc_alloc(sizeof(ServiceInfo));
+        s->name = service;
+        s->next = services;
+        services = s;
+    }
+    c->type = type;
+    c->service = s;
+    c->name = name;
+    c->handler = handler;
+    c->next = message_handlers[h];
+    message_handlers[h] = c;
+}
+
+void add_command_handler(const char * service, const char * name, MessageHandler handler) {
+    add_message_handler('C', service, name, handler);
+}
+
+void add_event_handler(const char * service, const char * name, MessageHandler handler) {
+    add_message_handler('E', service, name, handler);
+}
+
+void send_hello_message(OutputStream * out) {
+    ServiceInfo * s = services;
+    write_stringz(out, "E");
+    write_stringz(out, LOCATOR);
+    write_stringz(out, "Hello");
+    out->write(out, '[');
+    while (s) {
+        if (s != services) out->write(out, ',');
+        json_write_string(out, s->name);
+        s = s->next;
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+static void command_sync(char * token, InputStream * inp, OutputStream * out) {
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, 0);
+    out->write(out, MARKER_EOM);
+}
+
+void ini_protocol(void) {
+    add_command_handler(LOCATOR, "sync", command_sync);
+}
+
+
diff --git a/protocol.h b/protocol.h
new file mode 100644
index 0000000..13a4ee4
--- /dev/null
+++ b/protocol.h
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF communication protocol.
+ * This module handles registration of command and event handlers.
+ * It is called when new messages are received and will dispatch
+ * messages to the appropriate handler. It has no knowledge of what transport
+ * protocol is used and what services do.
+ */
+
+#ifndef D_protocol
+#define D_protocol
+
+#include "streams.h"
+
+typedef void (*MessageHandler)(char * /* Token or NULL */, InputStream *, OutputStream *);
+
+/*
+ * Current communication channels congestion level.
+ * Can be used by message handlers to manage congestion.
+ */
+extern int congestion_level;
+
+/*
+ * Read and dispatch one protocol message.
+ * This function is by channel manager when a message is available for handling.
+ */
+extern void handle_protocol_message(InputStream * inp, OutputStream * out);
+
+/*
+ * Send "Hello" message to host.
+ * This function is called by channel manager when new channel is opened.
+ */
+extern void send_hello_message(OutputStream * out);
+
+/*
+ * Register command message handler.
+ * The handler will be called for each incoming command message,
+ * that belongs to 'service' and has name 'name'.
+ */
+extern void add_command_handler(const char * service, const char * name, MessageHandler handler);
+
+/*
+ * Register event message handler.
+ * The handler will be called for each incoming event message,
+ * that belongs to 'service' and has name 'name'.
+ */
+extern void add_event_handler(const char * service, const char * name, MessageHandler handler);
+
+extern void ini_protocol(void);
+
+#endif
diff --git a/proxy.c b/proxy.c
new file mode 100644
index 0000000..ad24477
--- /dev/null
+++ b/proxy.c
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements tunneling of TCF messages to another target on behalf of a client
+ * This service intended to be used when a client has no direct access to a target.
+ */
+
+// TODO: Proxy service is not implemented yet
+
+#include "proxy.h"
+
+void ini_proxy_service(void) {
+}
diff --git a/proxy.h b/proxy.h
new file mode 100644
index 0000000..208b5fd
--- /dev/null
+++ b/proxy.h
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements tunneling of TCF messages to another target on behalf of a client.
+ * This service intended to be used when a client has no direct access to a target.
+ */
+
+#ifndef D_proxy
+#define D_proxy
+
+extern void ini_proxy_service(void);
+
+#endif
+
diff --git a/registers.c b/registers.c
new file mode 100644
index 0000000..c524de4
--- /dev/null
+++ b/registers.c
@@ -0,0 +1,376 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Registers - CPU registers access service.
+ */
+
+#include "config.h"
+#if SERVICE_Registers
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "mdep.h"
+#include "protocol.h"
+#include "context.h"
+#include "json.h"
+#include "exceptions.h"
+#include "registers.h"
+
+static const char * REGISTERS = "Registers";
+
+#if defined(_WRS_KERNEL)
+
+#  define regs_index taskRegName
+#  if defined(_WRS_REG_INDEX_REGWIDTH) || (CPU_FAMILY==COLDFIRE)
+#    define REG_WIDTH(x) (x).regWidth
+#  else
+#    define REG_WIDTH(x) 4
+#  endif
+
+#else
+
+typedef struct {
+    char	*regName;	/* pointer to register name */
+    int		regOff;		/* offset to entry in REG_SET */
+    int		regWidth;	/* register width in bytes */
+} REG_INDEX;
+
+#define REG_WIDTH(x) (x).regWidth
+
+#define REG_OFFSET(name) offsetof(REG_SET, name)
+
+#if defined(__i386__)
+static REG_INDEX regs_index[] = {
+    { "edi",    REG_OFFSET(edi),    4},
+    { "esi",    REG_OFFSET(esi),    4},
+    { "ebp",    REG_OFFSET(ebp),    4},
+    { "esp",    REG_OFFSET(esp),    4},
+    { "ebx",    REG_OFFSET(ebx),    4},
+    { "edx",    REG_OFFSET(edx),    4},
+    { "ecx",    REG_OFFSET(ecx),    4},
+    { "eax",    REG_OFFSET(eax),    4},
+    { "eflags", REG_OFFSET(eflags), 4},
+    { "eip",    REG_OFFSET(eip),    4},
+    { NULL,     0,                  0},
+};
+
+#else
+
+/* TODO: Linux: support for CPU types other then I86 */
+#error "Unknown CPU"
+
+#endif
+
+#endif /* _WRS_KERNEL */
+
+static short endianess_test = 0x0201;
+#define BIG_ENDIAN_DATA (*(char *)&endianess_test == 0x02)
+
+static void write_context(OutputStream * out, char * id, Context * ctx, REG_INDEX * idx) {
+    assert(!ctx->exited);
+
+    out->write(out, '{');
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, id);
+
+    out->write(out, ',');
+    json_write_string(out, "ParentID");
+    out->write(out, ':');
+    json_write_string(out, thread_id(ctx));
+
+    out->write(out, ',');
+    json_write_string(out, "Name");
+    out->write(out, ':');
+    json_write_string(out, idx->regName);
+
+    out->write(out, ',');
+    json_write_string(out, "Readable");
+    out->write(out, ':');
+    json_write_boolean(out, 1);
+
+    out->write(out, ',');
+    json_write_string(out, "Writeable");
+    out->write(out, ':');
+    json_write_boolean(out, 1);
+
+    out->write(out, ',');
+    json_write_string(out, "Formats");
+    out->write(out, ':');
+    out->write(out, '[');
+    json_write_string(out, "Hex");
+    out->write(out, ',');
+    json_write_string(out, "Decimal");
+    out->write(out, ']');
+
+#if !defined(_WRS_KERNEL)
+    out->write(out, ',');
+    json_write_string(out, "ProcessID");
+    out->write(out, ':');
+    json_write_string(out, pid2id(ctx->mem, 0));
+#endif
+
+    out->write(out, ',');
+    json_write_string(out, "BigEndian");
+    out->write(out, ':');
+    json_write_boolean(out, BIG_ENDIAN_DATA);
+
+    out->write(out, '}');
+    out->write(out, 0);
+}
+
+static int id2register(char * id, Context ** ctx, REG_INDEX ** idx) {
+    int i;
+    char name[64];
+    *ctx = NULL;
+    *idx = NULL;
+    if (*id++ != 'R') {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    i = 0;
+    while (*id != '.') {
+        if (*id == 0) {
+            errno = ERR_INV_CONTEXT;
+            return -1;
+        }
+        name[i++] = *id++;
+    }
+    name[i++] = 0;
+    id++;
+    for (i = 0; regs_index[i].regName != NULL; i++) {
+        if (strcmp(regs_index[i].regName, name) == 0) break;
+    }
+    if (regs_index[i].regName == NULL) {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    *ctx = id2ctx(id);
+    *idx = regs_index + i;
+    return 0;
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    Context * ctx = NULL;
+    REG_INDEX * idx = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    id2register(id, &ctx, &idx);
+    
+    if (ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    if (err == 0) {
+        write_context(out, id, ctx, idx);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    pid_t pid, parent;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    write_errno(out, 0);
+
+    out->write(out, '[');
+    if (pid != 0 && parent != 0) {
+        Context * ctx = context_find_from_pid(pid);
+        if (ctx != NULL) {
+            char t_id[128];
+            REG_INDEX * idx = regs_index;
+            strcpy(t_id, thread_id(ctx));
+            while (idx->regName != NULL) {
+                char r_id[128];
+                if (idx != regs_index) out->write(out, ',');
+                snprintf(r_id, sizeof(r_id), "R%s.%s", idx->regName, t_id);
+                json_write_string(out, r_id);
+                idx ++;
+            }
+        }
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    char fmt[256];
+    int hex = 0;
+    Context * ctx = NULL;
+    REG_INDEX * idx = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    json_read_string(inp, fmt, sizeof(fmt));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    id2register(id, &ctx, &idx);
+    
+    if (ctx == NULL || idx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    else if (!ctx->intercepted) err = ERR_IS_RUNNING;
+    else if (strcmp(fmt, "Hex") == 0) hex = 1;
+    else if (strcmp(fmt, "Decimal") != 0) err = ERR_INV_FORMAT;
+    
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    if (err == 0) {
+        int64 n = 0;
+        char val[64];
+        int val_len = 0;
+        assert(REG_WIDTH(*idx) <= sizeof(n));
+        memcpy( (char *)&n + (BIG_ENDIAN_DATA ? sizeof(n) - REG_WIDTH(*idx) : 0),
+                (char *)&ctx->regs + idx->regOff,
+                REG_WIDTH(*idx));
+        if (hex) {
+            while (val_len < REG_WIDTH(*idx) * 2) {
+                int i = (int)(n & 0xf);
+                val[val_len++] = i < 10 ? '0' + i : 'A' + i - 10;
+                n = n >> 4;
+            }
+        }
+        else {
+            int neg = n < 0;
+            uns64 m = neg ? -n : n;
+            do {
+                int i = (int)(m % 10);
+                val[val_len++] = '0' + i;
+                m = m / 10;
+            }
+            while (m != 0);
+            if (neg) val[val_len++] = '-';
+        }
+        out->write(out, '"');
+        while (val_len > 0) out->write(out, val[--val_len]);
+        out->write(out, '"');
+        out->write(out, 0);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_register_changed(OutputStream * out, char * id) {
+    write_stringz(out, "E");
+    write_stringz(out, REGISTERS);
+    write_stringz(out, "registerChanged");
+
+    json_write_string(out, id);
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_set(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    char fmt[256];
+    char val[256];
+    int hex = 0;
+    char * ptr = NULL;
+    Context * ctx = NULL;
+    REG_INDEX * idx = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    json_read_string(inp, fmt, sizeof(fmt));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    json_read_string(inp, val, sizeof(val));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    id2register(id, &ctx, &idx);
+    
+    if (ctx == NULL || idx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    else if (!ctx->intercepted) err = ERR_IS_RUNNING;
+    else if (strcmp(fmt, "Hex") == 0) hex = 1;
+    else if (strcmp(fmt, "Decimal") != 0) err = ERR_INV_FORMAT;
+    
+    if (err == 0) {
+        int64 n = 0;
+        ptr = val;
+        if (hex) {
+            while (1) {
+                if (*ptr >= '0' && *ptr <= '9') n = (n << 4) | (int64)(*ptr++ - '0');
+                else if (*ptr >= 'A' && *ptr <= 'F') n = (n << 4) | (int64)(*ptr++ - 'A' + 10);
+                else if (*ptr >= 'a' && *ptr <= 'f') n = (n << 4) | (int64)(*ptr++ - 'a' + 10);
+                else break;
+            }
+        }
+        else {
+            uns64 m = 0;
+            int neg = *ptr == '-';
+            if (neg) ptr++;
+            while (1) {
+                if (*ptr >= '0' && *ptr <= '9') m = (m * 10) + (uns64)(*ptr++ - '0');
+                else break;
+            }
+            n = neg ? (~m + 1) : m;
+        }
+        if (*ptr != 0) {
+            err = ERR_INV_NUMBER;
+        }
+        else {
+            assert(REG_WIDTH(*idx) <= sizeof(n));
+            memcpy( (char *)&ctx->regs + idx->regOff,
+                    (char *)&n + (BIG_ENDIAN_DATA ? sizeof(n) - REG_WIDTH(*idx) : 0),
+                    REG_WIDTH(*idx));
+            ctx->regs_dirty = 1;
+            send_event_register_changed(out, id);
+        }
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+void ini_registers_service(void) {
+    add_command_handler(REGISTERS, "getContext", command_get_context);
+    add_command_handler(REGISTERS, "getChildren", command_get_children);
+    add_command_handler(REGISTERS, "get", command_get);
+    add_command_handler(REGISTERS, "set", command_set);
+}
+
+#endif
+
diff --git a/registers.h b/registers.h
new file mode 100644
index 0000000..3c7570a
--- /dev/null
+++ b/registers.h
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF Registers - CPU registers access service.
+ */
+
+#ifndef D_registers
+#define D_registers
+
+/*
+ * Initialize registers service.
+ */
+extern void ini_registers_service(void);
+
+
+#endif
diff --git a/runctrl.c b/runctrl.c
new file mode 100644
index 0000000..e88fce9
--- /dev/null
+++ b/runctrl.c
@@ -0,0 +1,773 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: run control (TCF name RunControl)
+ */
+
+#include "config.h"
+#if SERVICE_RunControl
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <assert.h>
+#include "runctrl.h"
+#include "protocol.h"
+#include "channel.h"
+#include "json.h"
+#include "context.h"
+#include "myalloc.h"
+#include "trace.h"
+#include "events.h"
+#include "exceptions.h"
+#include "breakpoints.h"
+
+#define RM_RESUME           0
+#define RM_STEP_OVER        1
+#define RM_STEP_INTO        2
+#define RM_STEP_OVER_LINE   3
+#define RM_STEP_INTO_LINE   4
+#define RM_STEP_OUT         5
+
+#define STOP_ALL_TIMEOUT 1000000
+#define STOP_ALL_MAX_CNT 20
+
+static const char RUN_CONTROL[] = "RunControl";
+
+typedef struct SafeEvent SafeEvent;
+
+struct SafeEvent {
+    void (*done)(void *);
+    void * arg;
+    SafeEvent * next;
+};
+
+typedef struct GetContextArgs GetContextArgs;
+
+struct GetContextArgs {
+    OutputStream * out;
+    char token[256];
+    Context * ctx;
+    pid_t parent;
+};
+
+static SafeEvent * safe_event_list = NULL;
+static int safe_event_pid_count = 0;
+static int safe_event_generation = 0;
+
+#if !defined(WIN32) && !defined(_WRS_KERNEL)
+static char *get_executable(pid_t pid) {
+    static char s[FILE_PATH_SIZE + 1];
+    char tmpbuf[100];
+    int sz;
+
+    snprintf(tmpbuf, sizeof(tmpbuf), "/proc/%d/exe", pid);
+    if ((sz = readlink(tmpbuf, s, FILE_PATH_SIZE)) < 0) {
+        trace(LOG_ALWAYS, "error: readlink() failed; pid %d, error %d %s",
+            pid, errno, errno_to_str(errno));
+        return NULL;
+    }
+    s[sz] = 0;
+    return s;
+}
+#endif
+
+static void write_context(OutputStream * out, Context * ctx, int is_thread) {
+    assert(!ctx->exited);
+
+    out->write(out, '{');
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, is_thread ? thread_id(ctx) : container_id(ctx));
+
+    if (is_thread) {
+        out->write(out, ',');
+        json_write_string(out, "ParentID");
+        out->write(out, ':');
+        json_write_string(out, container_id(ctx));
+    }
+
+#if !defined(_WRS_KERNEL)
+    out->write(out, ',');
+    json_write_string(out, "ProcessID");
+    out->write(out, ':');
+    json_write_string(out, pid2id(ctx->mem, 0));
+#endif
+    
+#if !defined(WIN32) && !defined(_WRS_KERNEL)
+    if (!ctx->exiting && !is_thread) {
+        out->write(out, ',');
+        json_write_string(out, "File");
+        out->write(out, ':');
+        json_write_string(out, get_executable(ctx->pid));
+    }
+#endif
+
+    if (is_thread) {
+        out->write(out, ',');
+        json_write_string(out, "CanSuspend");
+        out->write(out, ':');
+        json_write_boolean(out, 1);
+
+        out->write(out, ',');
+        json_write_string(out, "CanResume");
+        out->write(out, ':');
+        json_write_long(out, (1 << RM_RESUME) | (1 << RM_STEP_INTO));
+
+        out->write(out, ',');
+        json_write_string(out, "HasState");
+        out->write(out, ':');
+        json_write_boolean(out, 1);
+    }
+
+    out->write(out, '}');
+}
+
+static void write_context_state(OutputStream * out, Context * ctx) {
+    char reason[128];
+
+    assert(!ctx->exited);
+
+    if (!ctx->intercepted) {
+        write_stringz(out, "0");
+        write_stringz(out, "null");
+        write_stringz(out, "null");
+        return;
+    }
+
+    /* Number: PC */
+    json_write_ulong(out, get_regs_PC(ctx->regs));
+    out->write(out, 0);
+
+    /* String: Reason */
+    if (ctx->event != 0) {
+        assert(ctx->signal == SIGTRAP);
+        snprintf(reason, sizeof(reason), "Event: %s", event_name(ctx->event));
+    }
+    else if (is_stopped_by_breakpoint(ctx)) {
+        strcpy(reason, "Breakpoint");
+    }
+    else if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) {
+        strcpy(reason, "Suspended");
+    }
+    else if (signal_name(ctx->signal)) {
+        snprintf(reason, sizeof(reason), "Signal %d %s", ctx->signal, signal_name(ctx->signal));
+    }
+    else {
+        snprintf(reason, sizeof(reason), "Signal %d", ctx->signal);
+    }
+    json_write_string(out, reason);
+    out->write(out, 0);
+
+    /* Object: Aditional info */
+    out->write(out, '{');
+    json_write_string(out, "Event");
+    out->write(out, ':');
+    json_write_long(out, ctx->event);
+    out->write(out, ',');
+    json_write_string(out, "Signal");
+    out->write(out, ':');
+    json_write_long(out, ctx->signal);
+    if (signal_name(ctx->signal)) {
+        out->write(out, ',');
+        json_write_string(out, "SignalName");
+        out->write(out, ':');
+        json_write_string(out, signal_name(ctx->signal));
+    }
+    out->write(out, '}');
+    out->write(out, 0);
+}
+
+static void event_get_context(void * arg) {
+    GetContextArgs * s = (GetContextArgs *)arg;
+    OutputStream * out = s->out;
+    Context * ctx = s->ctx;
+
+    if (!is_stream_closed(out)) {
+        int err = 0;
+
+        write_stringz(out, "R");
+        write_stringz(out, s->token);
+
+        if (ctx->exited) err = ERR_ALREADY_EXITED;
+        write_errno(out, err);
+    
+        if (err == 0) {
+            write_context(out, ctx, s->parent != 0);
+            out->write(out, 0);
+        }
+        else {
+            write_stringz(out, "null");
+        }
+
+        out->write(out, MARKER_EOM);
+        out->flush(out);
+    }
+    stream_unlock(out);
+    context_unlock(ctx);
+    loc_free(s);
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char id[256];
+    Context * ctx = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    ctx = id2ctx(id);
+    
+    if (ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    
+    if (err) {
+        write_stringz(out, "R");
+        write_stringz(out, token);
+        write_errno(out, err);
+        write_stringz(out, "null");
+        out->write(out, MARKER_EOM);
+    }
+    else {
+        /* Need to stop everything to access context properties.
+         * In particular, proc FS access can fail when process is running.
+         */
+        GetContextArgs * s = loc_alloc_zero(sizeof(GetContextArgs));
+        s->out = out;
+        stream_lock(out);
+        strcpy(s->token, token);
+        s->ctx = ctx;
+        context_lock(ctx);
+        id2pid(id, &s->parent);
+        post_safe_event(event_get_context, s);
+    }
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    write_errno(out, 0);
+
+    out->write(out, '[');
+    if (id[0] == 0) {
+        LINK * qp;
+        int cnt = 0;
+        for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+            Context * ctx = ctxl2ctxp(qp);
+            if (ctx->exited) continue;
+            if (ctx->parent != NULL) continue;
+            if (cnt > 0) out->write(out, ',');
+            json_write_string(out, container_id(ctx));
+            cnt++;
+        }
+    }
+    else if (id[0] == 'P') {
+        LINK * qp;
+        int cnt = 0;
+        pid_t ppd = 0;
+        pid_t pid = id2pid(id, &ppd);
+        Context * parent = id2ctx(id);
+        if (parent != NULL && parent->parent == NULL && ppd == 0) {
+            if (!parent->exited) {
+                if (cnt > 0) out->write(out, ',');
+                json_write_string(out, thread_id(parent));
+                cnt++;
+            }
+            for (qp = parent->children.next; qp != &parent->children; qp = qp->next) {
+                Context * ctx = cldl2ctxp(qp);
+                if (ctx->exited) continue;
+                assert(ctx->parent == parent);
+                if (cnt > 0) out->write(out, ',');
+                json_write_string(out,thread_id(ctx));
+                cnt++;
+            }
+        }
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_state(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    Context * ctx;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    ctx = id2ctx(id);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    if (ctx == NULL) err = ERR_INV_CONTEXT;
+    else if (ctx->exited) err = ERR_ALREADY_EXITED;
+    write_errno(out, err);
+
+    json_write_boolean(out, ctx != NULL && ctx->intercepted);
+    out->write(out, 0);
+
+    if (err) {
+        write_stringz(out, "0");
+        write_stringz(out, "null");
+        write_stringz(out, "null");
+    }
+    else {
+        write_context_state(out, ctx);
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_simple_result(OutputStream * out, char * token, int err) {
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_resumed(OutputStream * out, Context * ctx);
+
+static void done_skip_breakpoint(SkipBreakpointInfo * s) {
+    OutputStream * out = s->out;
+    if (!is_stream_closed(out)) {
+        send_simple_result(out, s->token, s->error);
+        out->flush(out);
+    }
+}
+
+static void command_resume(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    long mode;
+    long count;
+    Context * ctx;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    mode = json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    count = json_read_long(inp);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    ctx = id2ctx(id);
+    assert(safe_event_list == NULL);
+
+    if (ctx == NULL) {
+        err = ERR_INV_CONTEXT;
+    }
+    else if (ctx->exited) {
+        err = ERR_ALREADY_EXITED;
+    }
+    else if (!ctx->intercepted) {
+        err = ERR_ALREADY_RUNNING;
+    }
+    else if (ctx->regs_error) {
+        err = ctx->regs_error;
+    }
+    else if (count != 1) {
+        err = EINVAL;
+    }
+    else if (mode == RM_RESUME || mode == RM_STEP_INTO) {
+        SkipBreakpointInfo * sb = skip_breakpoint(ctx);
+        send_event_context_resumed(&broadcast_stream, ctx);
+        if (sb != NULL) {
+            if (mode == RM_STEP_INTO) sb->pending_intercept = 1;
+            sb->done = done_skip_breakpoint;
+            sb->out = out;
+            stream_lock(out);
+            strcpy(sb->token, token);
+            return;
+        }
+        if (mode == RM_STEP_INTO) {
+            if (context_single_step(ctx) < 0) {
+                err = errno;
+            }
+            else {
+                ctx->pending_intercept = 1;
+            }
+        }
+        else {
+            if (context_continue(ctx) < 0) err = errno;
+        }
+    }
+    else {
+        err = EINVAL;
+    }
+
+    send_simple_result(out, token, err);
+}
+
+static void send_event_context_suspended(OutputStream * out, Context * ctx);
+
+static void command_suspend(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    Context * ctx;
+    int err = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+    ctx = id2ctx(id);
+
+    if (ctx == NULL) {
+        err = ERR_INV_CONTEXT;
+    }
+    else if (ctx->exited) {
+        err = ERR_ALREADY_EXITED;
+    }
+    else if (ctx->intercepted) {
+        err = ERR_ALREADY_STOPPED;
+    }
+    else if (ctx->stopped) {
+        send_event_context_suspended(&broadcast_stream, ctx);
+    }
+    else {
+        ctx->pending_intercept = 1;
+        if (context_stop(ctx) < 0) err = errno;
+    }
+
+    send_simple_result(out, token, err);
+}
+
+static void command_not_supported(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    send_simple_result(out, token, ENOSYS);
+}
+
+static void send_event_context_added(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextAdded");
+
+    /* <array of context data> */
+    out->write(out, '[');
+    if (ctx->parent == NULL) {
+        write_context(out, ctx, 0);
+        out->write(out, ',');
+    }
+    write_context(out, ctx, 1);
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_changed(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextChanged");
+
+    /* <array of context data> */
+    out->write(out, '[');
+    if (ctx->parent == NULL) {
+        write_context(out, ctx, 0);
+        out->write(out, ',');
+    }
+    write_context(out, ctx, 1);
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_removed(OutputStream * out, Context * ctx) {
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextRemoved");
+
+    /* <array of context IDs> */
+    out->write(out, '[');
+    json_write_string(out, thread_id(ctx));
+    if (ctx->parent == NULL && list_is_empty(&ctx->children)) {
+        out->write(out, ',');
+        json_write_string(out, container_id(ctx));
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_suspended(OutputStream * out, Context * ctx) {
+    assert(!ctx->exited);
+    assert(!ctx->intercepted);
+    ctx->intercepted = 1;
+    ctx->pending_intercept = 0;
+
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextSuspended");
+
+    /* String: Context ID */
+    json_write_string(out, thread_id(ctx));
+    out->write(out, 0);
+
+    write_context_state(out, ctx);
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_resumed(OutputStream * out, Context * ctx) {
+    assert(ctx->intercepted);
+    assert(!ctx->pending_intercept);
+    ctx->intercepted = 0;
+
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextResumed");
+
+    /* String: Context ID */
+    json_write_string(out, thread_id(ctx));
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+static void send_event_context_exception(OutputStream * out, Context * ctx) {
+    char buf[128];
+
+    write_stringz(out, "E");
+    write_stringz(out, RUN_CONTROL);
+    write_stringz(out, "contextException");
+
+    /* String: Context ID */
+    json_write_string(out, thread_id(ctx));
+    out->write(out, 0);
+
+    /* String: Human readable description of the exception */
+    snprintf(buf, sizeof(buf), "Signal %d", ctx->signal);
+    json_write_string(out, buf);
+    out->write(out, 0);
+
+    out->write(out, MARKER_EOM);
+}
+
+int is_all_stopped(void) {
+    LINK * qp;
+    for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+        Context * ctx = ctxl2ctxp(qp);
+        if (ctx->exited || ctx->exiting) continue;
+        if (!ctx->stopped) return 0;
+    }
+    return are_channels_suspended();
+}
+
+static void continue_temporary_stopped(void * arg) {
+    LINK * qp;
+
+    if ((int)arg != safe_event_generation) return;
+    assert(safe_event_list == NULL);
+
+    if (channels_get_message_count() > 0) {
+        post_event(continue_temporary_stopped, (void *)safe_event_generation);
+        return;
+    }
+
+    for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+        Context * ctx = ctxl2ctxp(qp);
+        if (ctx->exited) continue;
+        if (!ctx->stopped) continue;
+        if (ctx->intercepted) continue;
+        if (ctx->pending_step) continue;
+        context_continue(ctx);
+    }
+}
+
+static void run_safe_events(void * arg) {
+    LINK * qp;
+
+    if ((int)arg != safe_event_generation) return;
+    assert(safe_event_list != NULL);
+    assert(are_channels_suspended());
+
+    for (qp = context_root.next; qp != &context_root; qp = qp->next) {
+        Context * ctx = ctxl2ctxp(qp);
+        if (ctx->exited || ctx->exiting) continue;
+        if (!ctx->pending_step) {
+            int error = 0;
+            if (ctx->stopped) continue;
+            if (context_stop(ctx) < 0) {
+                error = errno;
+#ifdef _WRS_KERNEL
+                if (error == S_vxdbgLib_INVALID_CTX) {
+                    /* Most often this means that context has exited,
+                     * but exit event is not delivered yet.
+                     * Not an error. */
+                    error = 0;
+                }
+#endif                
+            }
+            if (error) {
+                trace(LOG_ALWAYS, "error: can't temporary stop pid %d; error %d: %s",
+                    ctx->pid, error, errno_to_str(error));
+            }
+        }
+        if (!ctx->pending_safe_event) {
+            ctx->pending_safe_event = 1;
+            safe_event_pid_count++;
+        }
+        else if (ctx->pending_safe_event == STOP_ALL_MAX_CNT) {
+            trace(LOG_ALWAYS, "error: can't temporary stop pid %d; error: timeout", ctx->pid);
+            ctx->exiting = 1;
+            ctx->pending_safe_event = 0;
+            safe_event_pid_count--;
+        }
+        else {
+            ctx->pending_safe_event++;
+        }
+    }
+
+    if ((int)arg != safe_event_generation) return;
+
+    while (safe_event_list) {
+        SafeEvent * i = safe_event_list;
+        if (safe_event_pid_count > 0) {
+            post_event_with_delay(run_safe_events, (void *)++safe_event_generation, STOP_ALL_TIMEOUT);
+            return;
+        }
+        assert(is_all_stopped());
+        safe_event_list = i->next;
+        i->done(i->arg);
+        loc_free(i);
+        if ((int)arg != safe_event_generation) return;
+    }
+
+    channels_resume();
+    /* Lazily continue execution of temporary stopped contexts */
+    post_event(continue_temporary_stopped, (void *)safe_event_generation);
+}
+
+static void check_safe_events(Context * ctx) {
+    assert(ctx->stopped || ctx->exited);
+    assert(ctx->pending_safe_event);
+    assert(safe_event_list != NULL);
+    assert(safe_event_pid_count > 0);
+    ctx->pending_safe_event = 0;
+    safe_event_pid_count--;
+    if (safe_event_pid_count == 0) {
+        post_event(run_safe_events, (void *)++safe_event_generation);
+    }
+}
+
+void post_safe_event(void (*done)(void *), void * arg) {
+    SafeEvent * i = (SafeEvent *)loc_alloc(sizeof(SafeEvent));
+    i->done = done;
+    i->arg = arg;
+    if (safe_event_list == NULL) {
+        assert(safe_event_pid_count == 0);
+        channels_suspend();
+        post_event(run_safe_events, (void *)++safe_event_generation);
+    }
+    assert(are_channels_suspended());
+    i->next = safe_event_list;
+    safe_event_list = i;
+}
+
+static void event_context_created(Context * ctx) {
+    assert(!ctx->exited);
+    assert(!ctx->intercepted);
+    assert(!ctx->stopped);
+    send_event_context_added(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+static void event_context_changed(Context * ctx) {
+    send_event_context_changed(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+static void event_context_stopped(Context * ctx) {
+    assert(ctx->stopped);
+    assert(!ctx->intercepted);
+    assert(!ctx->exited);
+    if (ctx->pending_safe_event) check_safe_events(ctx);
+    if (is_stopped_by_breakpoint(ctx)) {
+        if (evaluate_breakpoint_condition(ctx)) {
+            ctx->pending_intercept = 1;
+        }
+        else {
+            skip_breakpoint(ctx);
+        }
+    }
+    else if (ctx->signal != SIGSTOP && ctx->signal != SIGTRAP) {
+        send_event_context_exception(&broadcast_stream, ctx);
+        ctx->pending_intercept = 1;
+    }
+    if (ctx->pending_intercept) {
+        send_event_context_suspended(&broadcast_stream, ctx);
+        broadcast_stream.flush(&broadcast_stream);
+    }
+    if (!ctx->intercepted && safe_event_list == NULL) {
+        context_continue(ctx);
+    }
+}
+
+static void event_context_started(Context * ctx) {
+    assert(!ctx->stopped);
+    assert(!ctx->intercepted);
+    ctx->stopped_by_bp = 0;
+    if (safe_event_list) {
+        if (!ctx->pending_step) {
+            context_stop(ctx);
+        }
+        if (!ctx->pending_safe_event) {
+            ctx->pending_safe_event = 1;
+            safe_event_pid_count++;
+        }
+    }
+}
+
+static void event_context_exited(Context * ctx) {
+    assert(!ctx->stopped);
+    assert(!ctx->intercepted);
+    if (ctx->pending_safe_event) check_safe_events(ctx);
+    send_event_context_removed(&broadcast_stream, ctx);
+    broadcast_stream.flush(&broadcast_stream);
+}
+
+void ini_run_ctrl_service(void) {
+    static ContextEventListener listener = {
+        event_context_created,
+        event_context_exited,
+        event_context_stopped,
+        event_context_started,
+        event_context_changed,
+        NULL
+    };
+    add_context_event_listener(&listener);
+    add_command_handler(RUN_CONTROL, "getContext", command_get_context);
+    add_command_handler(RUN_CONTROL, "getChildren", command_get_children);
+    add_command_handler(RUN_CONTROL, "getState", command_get_state);
+    add_command_handler(RUN_CONTROL, "resume", command_resume);
+    add_command_handler(RUN_CONTROL, "suspend", command_suspend);
+    add_command_handler(RUN_CONTROL, "terminate", command_not_supported);
+}
+
+#endif
diff --git a/runctrl.h b/runctrl.h
new file mode 100644
index 0000000..46d0d47
--- /dev/null
+++ b/runctrl.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: run control (TCF name RunControl)
+ */
+
+#ifndef D_runctrl
+#define D_runctrl
+
+#include "mdep.h"
+#include "context.h"
+
+/*
+ * Add "safe" event.
+ * Temporary suspends handling of incoming messages and stops all debuggee threads.
+ * Callback function 'done' will be called when everything is stopped and
+ * it is safe to access debuggee memory, plant breakpoints, etc.
+ */
+extern void post_safe_event(void (*done)(void *), void * arg);
+
+/*
+ * Return 1 if all threads in debuggee are stopped and handling of incoming messages
+ * is suspended and it is safe to access debuggee memory, plant breakpoints, etc.
+ */
+extern int is_all_stopped(void);
+
+/*
+ * Initialize run control service.
+ */
+extern void ini_run_ctrl_service(void);
+
+#endif
diff --git a/stacktrace.c b/stacktrace.c
new file mode 100644
index 0000000..d0c6483
--- /dev/null
+++ b/stacktrace.c
@@ -0,0 +1,425 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: stack trace (TCF name StackTrace)
+ */
+
+#include "config.h"
+#if SERVICE_StackTrace
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "mdep.h"
+#include "myalloc.h"
+#include "protocol.h"
+#include "context.h"
+#include "json.h"
+#include "exceptions.h"
+#include "stacktrace.h"
+
+static const char * STACKTRACE = "StackTrace";
+
+struct StackFrame {
+    unsigned long fp;   /* frame address */
+    unsigned long pc;   /* return address */
+    unsigned long fn;   /* address of function */
+    int arg_cnt;        /* number of function arguments */
+    unsigned long args; /* address of function arguments */
+};
+
+struct StackTrace {
+    int error;
+    int frame_cnt;
+    int top_first;
+    struct StackFrame frames[1];
+};
+
+typedef struct StackFrame StackFrame;
+typedef struct StackTrace StackTrace;
+
+typedef void (*STACK_TRACE_CALLBAK)(
+    void  *,	/* address from which function was called */
+    int	   ,	/* address of function called */
+    int    ,	/* number of arguments in function call */
+    int *  ,	/* pointer to function args */
+    int	   ,	/* thread ID */
+    int  	/* TRUE if Kernel addresses */
+);
+
+static int stack_trace_max = 0;
+static StackTrace * stack_trace = NULL;
+
+static void stack_trace_callback(
+    void *	callAdrs,	/* address from which function was called */
+    int		funcAdrs,	/* address of function called */
+    int		nargs,		/* number of arguments in function call */
+    int *	args,		/* pointer to function args */
+    int		taskId,		/* task's ID */
+    int 	isKernelAdrs	/* TRUE if Kernel addresses */
+)
+{
+    StackFrame * f;
+    if (stack_trace == NULL) {
+        stack_trace_max = 64;
+        stack_trace = (StackTrace *)loc_alloc(sizeof(StackTrace) + (stack_trace_max - 1) * sizeof(StackFrame));
+        memset(stack_trace, 0, sizeof(StackTrace));
+    }
+    else if (stack_trace->frame_cnt >= stack_trace_max) {
+        stack_trace_max *= 2;
+        stack_trace = (StackTrace *)loc_realloc(stack_trace, sizeof(StackTrace) + (stack_trace_max - 1) * sizeof(StackFrame));
+    }
+    f = stack_trace->frames + stack_trace->frame_cnt++;
+    memset(f, 0, sizeof(StackFrame));
+    f->pc = (unsigned long)callAdrs;
+    f->fn = (unsigned long)funcAdrs;
+    f->arg_cnt = nargs;
+    f->args = (unsigned long)args;
+}
+
+#if defined(_WRS_KERNEL)
+
+#include <trcLib.h>
+
+static void trace_stack(Context * ctx, STACK_TRACE_CALLBAK callback) {
+    trcStack(&ctx->regs, (FUNCPTR)stack_trace_callback, ctx->pid);
+}
+
+#else
+
+#define MAX_FRAMES  1000
+
+#define JMPD08      0xeb
+#define JMPD32      0xe9
+#define PUSH_EBP    0x55
+#define MOV_ESP0    0x89
+#define MOV_ESP1    0xe5
+#define ENTER       0xc8
+#define RET         0xc3
+#define RETADD      0xc2
+
+/*
+ * trace_jump - resolve any JMP instructions to final destination
+ *
+ * This routine returns a pointer to the next non-JMP instruction to be
+ * executed if the pc were at the specified <adrs>.  That is, if the instruction
+ * at <adrs> is not a JMP, then <adrs> is returned.  Otherwise, if the
+ * instruction at <adrs> is a JMP, then the destination of the JMP is
+ * computed, which then becomes the new <adrs> which is tested as before.
+ * Thus we will eventually return the address of the first non-JMP instruction
+ * to be executed.
+ *
+ * The need for this arises because compilers may put JMPs to instructions
+ * that we are interested in, instead of the instruction itself.  For example,
+ * optimizers may replace a stack pop with a JMP to a stack pop.  Or in very
+ * UNoptimized code, the first instruction of a subroutine may be a JMP to
+ * a PUSH %EBP MOV %ESP %EBP, instead of a PUSH %EBP MOV %ESP %EBP (compiler
+ * may omit routine "post-amble" at end of parsing the routine!).  We call
+ * this routine anytime we are looking for a specific kind of instruction,
+ * to help handle such cases.
+ *
+ * RETURNS: The address that a chain of branches points to.
+ */
+static unsigned long trace_jump(Context * ctx, unsigned long addr) {
+    int cnt = 0;
+    /* while instruction is a JMP, get destination adrs */
+    while (cnt < 100) {
+        unsigned char instr;		/* instruction opcode at <addr> */
+        unsigned long dest;	/* Jump destination address */
+        if (context_read_mem(ctx, addr, &instr, 1) < 0) return addr;
+
+	/* If instruction is a JMP, get destination adrs */
+        if (instr == JMPD08) {
+            signed char disp08;
+            if (context_read_mem(ctx, addr + 1, &disp08, 1) < 0) return addr;
+            dest = addr + 2 + disp08;
+        }
+        else if (instr == JMPD32) {
+            int	disp32;
+            assert(sizeof(disp32) == 4);
+            if (context_read_mem(ctx, addr + 1, &disp32, 4) < 0) return addr;
+            dest = addr + 5 + disp32;
+        }
+	else {
+	    break;
+        }
+	if (dest == addr) break;
+	addr = dest;
+        cnt++;
+    }
+    return addr;
+}
+
+static int trace_stack(Context * ctx, STACK_TRACE_CALLBAK callback) {
+    unsigned long pc = ctx->regs.eip;
+    unsigned long fp = ctx->regs.ebp;
+    unsigned long fp_prev = 0;
+
+    unsigned long addr = trace_jump(ctx, pc);
+    unsigned char code[4];
+    unsigned cnt = 0;
+
+    /*
+     * we don't have a stack frame in a few restricted but useful cases:
+     *  1) we are at a PUSH %EBP MOV %ESP %EBP or RET or ENTER instruction,
+     *  2) we are the first instruction of a subroutine (this may NOT be
+     *     a PUSH %EBP MOV %ESP %EBP instruction with some compilers)
+     */
+    if (context_read_mem(ctx, addr - 1, code, sizeof(code)) < 0) return -1;
+
+    if (code[1] == PUSH_EBP && code[2] == MOV_ESP0 && code[3] == MOV_ESP1 ||
+        code[1] == ENTER || code[1] == RET || code[1] == RETADD) {
+        fp_prev = fp;
+        fp = ctx->regs.esp - 4;
+    }
+    else if (code[0] == PUSH_EBP && code[1] == MOV_ESP0 && code[2] == MOV_ESP1) {
+        fp_prev = fp;
+        fp = ctx->regs.esp;
+    }
+
+    assert(stack_trace == NULL || stack_trace->frame_cnt == 0);
+    while (fp != 0 && cnt < MAX_FRAMES) {
+        unsigned long frame[2];
+        unsigned long fp_next;
+        if (context_read_mem(ctx, fp, frame, sizeof(frame)) < 0) return -1;
+        callback((void *)frame[1], 0, 0, 0, ctx->pid, 0);
+        stack_trace->frames[stack_trace->frame_cnt - 1].fp = fp;
+        stack_trace->top_first = 1;
+        cnt++;
+        fp_next = fp_prev != 0 ? fp_prev : frame[0];
+        fp_prev = 0;
+        if (fp_next <= fp) break;
+        fp = fp_next;
+    }
+
+    return 0;
+}
+
+#endif
+
+static void create_stack_trace(Context * ctx) {
+    stack_trace = NULL;
+    stack_trace_max = 0;
+    if (ctx->regs_error != 0) {
+        stack_trace = (StackTrace *)loc_alloc_zero(sizeof(StackTrace));
+        stack_trace->error = ctx->regs_error;
+    }
+    else {
+        trace_stack(ctx, stack_trace_callback);
+    }
+    ctx->stack_trace = stack_trace;
+    stack_trace = NULL;
+}
+
+static int id2frame(char * id, Context ** ctx, int * idx) {
+    int i;
+    char pid[64];
+    int frame;
+    StackTrace * s = NULL;
+
+    *ctx = NULL;
+    *idx = 0;
+    if (*id++ != 'F') {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    if (*id++ != 'P') {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    i = 0;
+    while (*id != '.') {
+        if (*id == 0) {
+            errno = ERR_INV_CONTEXT;
+            return -1;
+        }
+        pid[i++] = *id++;
+    }
+    pid[i++] = 0;
+    id++;
+    *ctx = context_find_from_pid(strtol(pid, NULL, 10));
+    s = (*ctx)->stack_trace;
+    if (s == NULL) {
+        errno = ERR_INV_CONTEXT;
+        return -1;
+    }
+    frame = strtol(id, NULL, 10);
+    *idx = s->top_first ? s->frame_cnt - frame - 1 : frame;
+    return 0;
+}
+
+static void write_context(OutputStream * out, char * id, Context * ctx, int level, StackFrame * frame) {
+    out->write(out, '{');
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, id);
+
+    out->write(out, ',');
+    json_write_string(out, "ParentID");
+    out->write(out, ':');
+    json_write_string(out, thread_id(ctx));
+
+#if !defined(_WRS_KERNEL)
+    out->write(out, ',');
+    json_write_string(out, "ProcessID");
+    out->write(out, ':');
+    json_write_string(out, pid2id(ctx->mem, 0));
+#endif
+
+    if (frame->fp) {
+        out->write(out, ',');
+        json_write_string(out, "FP");
+        out->write(out, ':');
+        json_write_ulong(out, frame->fp);
+    }
+
+    if (frame->pc) {
+        out->write(out, ',');
+        json_write_string(out, "RP");
+        out->write(out, ':');
+        json_write_ulong(out, frame->pc);
+    }
+
+    if (frame->arg_cnt) {
+        out->write(out, ',');
+        json_write_string(out, "ArgsCnt");
+        out->write(out, ':');
+        json_write_ulong(out, frame->arg_cnt);
+    }
+
+    if (frame->args) {
+        out->write(out, ',');
+        json_write_string(out, "ArgsAddr");
+        out->write(out, ':');
+        json_write_ulong(out, frame->args);
+    }
+
+    out->write(out, '}');
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    int err = 0;
+    char ** ids;
+    int id_cnt = 0;
+    int i;
+
+    ids = json_read_alloc_string_array(inp, &id_cnt);
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+    out->write(out, '[');
+    for (i = 0; i < id_cnt; i++) {
+        StackTrace * s = NULL;
+        Context * ctx = NULL;
+        int idx = 0;
+        if (i > 0) out->write(out, ',');
+        if (id2frame(ids[i], &ctx, &idx) < 0) {
+            err = errno;
+        }
+        else if (!ctx->intercepted) {
+            err = ERR_IS_RUNNING;
+        }
+        else {
+            if (ctx->stack_trace == NULL) create_stack_trace(ctx);
+            s = (StackTrace *)ctx->stack_trace;
+        }
+        if (s == NULL || idx < 0 || idx >= s->frame_cnt) {
+            write_string(out, "null");
+        }
+        else {
+            int level = s->top_first ? s->frame_cnt - idx - 1 : idx;
+            write_context(out, ids[i], ctx, level, s->frames + idx);
+        }
+    }
+    out->write(out, ']');
+    out->write(out, 0);
+    write_errno(out, err);
+    out->write(out, MARKER_EOM);
+    loc_free(ids);
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    int err = 0;
+    pid_t pid, parent;
+    Context * ctx = NULL;
+    StackTrace * s = NULL;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    pid = id2pid(id, &parent);
+    if (pid != 0 && parent != 0) {
+        ctx = context_find_from_pid(pid);
+        if (ctx != NULL) {
+            if (!ctx->intercepted) {
+                err = ERR_IS_RUNNING;
+            }
+            else {
+                if (ctx->stack_trace == NULL) create_stack_trace(ctx);
+                s = (StackTrace *)ctx->stack_trace;
+            }
+        }
+    }
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    write_errno(out, s != NULL ? s->error : err);
+
+    if (s == NULL) {
+        write_stringz(out, "null");
+    }
+    else {
+        int i;
+        char frame_id[64];
+        out->write(out, '[');
+        for (i = 0; i < s->frame_cnt; i++) {
+            if (i > 0) out->write(out, ',');
+            snprintf(frame_id, sizeof(frame_id), "FP%d.%d", ctx->pid, i);
+            json_write_string(out, frame_id);
+        }
+        out->write(out, ']');
+        out->write(out, 0);
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void delete_stack_trace(Context * ctx) {
+    if (ctx->stack_trace != NULL) {
+        loc_free(ctx->stack_trace);
+        ctx->stack_trace = NULL;
+    }
+}
+
+void ini_stack_trace_service(void) {
+    static ContextEventListener listener = {
+        NULL,
+        delete_stack_trace,
+        delete_stack_trace,
+        delete_stack_trace,
+        delete_stack_trace,
+        NULL
+    };
+    add_context_event_listener(&listener);
+    add_command_handler(STACKTRACE, "getContext", command_get_context);
+    add_command_handler(STACKTRACE, "getChildren", command_get_children);
+}
+
+#endif
+
diff --git a/stacktrace.h b/stacktrace.h
new file mode 100644
index 0000000..a47329a
--- /dev/null
+++ b/stacktrace.h
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: stack trace (TCF name StackTrace)
+ */
+
+#ifndef D_stacktrace
+#define D_stacktrace
+
+/*
+ * Initialize stack trace service.
+ */
+extern void ini_stack_trace_service(void);
+
+
+#endif
diff --git a/streams.c b/streams.c
new file mode 100644
index 0000000..86fe407
--- /dev/null
+++ b/streams.c
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Abstract byte stream. Bytes in the stream can be divided into groups - messages.
+ */
+
+#include "streams.h"
+
+void write_string(OutputStream * out, const char * str) {
+    while (*str) out->write(out, (*str++) & 0xff);
+}
+
+void write_stringz(OutputStream * out, const char * str) {
+    while (*str) out->write(out, (*str++) & 0xff);
+    out->write(out, 0);
+}
diff --git a/streams.h b/streams.h
new file mode 100644
index 0000000..e15e62e
--- /dev/null
+++ b/streams.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Abstract byte stream. Bytes in the stream can be divided into groups - messages.
+ */
+
+#ifndef D_streams
+#define D_streams
+
+/* 
+ * MARKER_EOM - end of message
+ * MARKER_EOS - end of stream
+ */
+#define MARKER_EOM  (-1)
+#define MARKER_EOS  (-2)
+#define MARKER_NULL (-3)
+
+typedef struct OutputStream OutputStream;
+
+struct OutputStream {
+    void (*write)(OutputStream * stream, int byte);
+    void (*flush)(OutputStream * stream);
+};
+
+typedef struct InputStream InputStream;
+
+struct InputStream {
+    int (*read)(InputStream * stream);
+    int (*peek)(InputStream * stream);
+};
+
+extern void write_string(OutputStream * out, const char * str);
+extern void write_stringz(OutputStream * out, const char * str);
+
+#endif
diff --git a/symbols.c b/symbols.c
new file mode 100644
index 0000000..132892a
--- /dev/null
+++ b/symbols.c
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Symbols service.
+ */
+#include "config.h"
+#if SERVICE_Symbols
+
+#if defined(_WRS_KERNEL)
+#  include <vxWorks.h>
+#  include <symLib.h>
+#  include <sysSymTbl.h>
+#elif defined(WIN32)
+#else
+#  include <elf.h>
+#  include <libelf.h>
+#  include <fcntl.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "errors.h"
+#include "elf.h"
+#include "myalloc.h"
+#include "symbols.h"
+
+#define SYM_HASH_SIZE 1023
+
+typedef struct SymbolTable SymbolTable;
+
+struct SymbolTable {
+    SymbolTable * next;
+    char * str;
+    int str_size;
+    int sym_cnt;
+    void * syms;    /* pointer to ELF section data: Elf32_Sym* or Elf64_Sym* */
+    int hash[SYM_HASH_SIZE];
+    int * hash_next;
+};
+
+static int calc_hash(char * s) {
+    unsigned h = 0;
+    while (*s) {
+        unsigned g;
+	h = (h << 4) + *s++;
+	if (g = h & 0xf0000000) h ^= g >> 24;
+	h &= ~g;
+    }
+    return h % SYM_HASH_SIZE;
+}
+
+static void free_sym_cache(ELF_File * file) {
+    SymbolTable * tables = (SymbolTable *)file->sym_cache;
+    while (tables != NULL) {
+        SymbolTable * tbl = tables;
+        tables = tbl->next;
+        loc_free(tbl->hash_next);
+        loc_free(tbl);
+    }
+}
+
+static int load_tables(ELF_File * file) {
+    int error = 0;
+
+#ifdef ELFMAG
+    unsigned idx;
+    for (idx = 0; idx < file->section_cnt; idx++) {
+        ELF_Section * sym_sec = file->sections[idx];
+        if (sym_sec == NULL) continue;
+        if (sym_sec->type == SHT_SYMTAB && sym_sec->size > 0) {
+            int i;
+            ELF_Section * str_sec;
+            U1_T * str_data = NULL;
+            U1_T * sym_data = NULL;
+            SymbolTable * tbl = (SymbolTable *)loc_alloc_zero(sizeof(SymbolTable));
+            tbl->next = (SymbolTable *)file->sym_cache;
+            file->sym_cache = tbl;
+            if (sym_sec->link >= file->section_cnt || (str_sec = file->sections[sym_sec->link]) == NULL) {
+                error = EINVAL;
+                break;
+            }
+            if (elf_load(sym_sec, &sym_data) < 0) {
+                error = errno;
+                assert(error != 0);
+                break;
+            }
+            if (elf_load(str_sec, &str_data) < 0) {
+                error = errno;
+                assert(error != 0);
+                break;
+            }
+            tbl->str = (char *)str_data;
+            tbl->str_size = str_sec->size;
+            tbl->syms = sym_data;
+            tbl->sym_cnt = sym_sec->size / sizeof(Elf32_Sym);
+            tbl->hash_next = (int *)loc_alloc(tbl->sym_cnt * sizeof(int));
+            for (i = 0; i < tbl->sym_cnt; i++) {
+                Elf32_Sym * s = (Elf32_Sym *)tbl->syms + i;
+                assert(s->st_name < tbl->str_size);
+                if (s->st_name == 0) {
+                    tbl->hash_next[i] = 0;
+                }
+                else {
+                    int h = calc_hash(tbl->str + s->st_name);
+                    tbl->hash_next[i] = tbl->hash[h];
+                    tbl->hash[h] = i;
+                }
+            }
+        }
+    }
+
+#else
+    error = EINVAL;
+#endif
+
+    if (error != 0) {
+        free_sym_cache(file);
+        errno = error;
+        return -1;
+    }
+
+    return 0;
+}
+
+int find_symbol(Context * ctx, char * name, Symbol * sym) {
+    int error = 0;
+
+#if defined(WIN32)
+
+    memset(sym, 0, sizeof(Symbol));
+    error = EINVAL;
+
+#elif defined(_WRS_KERNEL)
+    
+    char * ptr;
+    SYM_TYPE type;
+
+    memset(sym, 0, sizeof(Symbol));
+    if (symFindByName(sysSymTbl, name, &ptr, &type) != OK) {
+        error = errno;
+        if (error == S_symLib_SYMBOL_NOT_FOUND) error = ERR_SYM_NOT_FOUND;
+        assert(error != 0);
+    }
+    else {
+        sym->abs = 1;
+        sym->value = (unsigned long)ptr;
+        
+        if (SYM_IS_UNDF(type)) sym->storage = "UNDEF";
+        else if (SYM_IS_COMMON(type)) sym->storage = "COMMON";
+        else if (SYM_IS_GLOBAL(type)) sym->storage = "GLOBAL";
+        else if (SYM_IS_LOCAL(type)) sym->storage = "LOCAL";
+        
+        if (SYM_IS_TEXT(type)) sym->section = ".text";
+        else if (SYM_IS_DATA(type)) sym->section = ".data";
+        else if (SYM_IS_BSS(type)) sym->section = ".bss";
+        assert(!SYM_IS_ABS(type) || sym->section == NULL);
+    }
+
+#else
+
+    char fnm[FILE_PATH_SIZE];
+    int found = 0;
+    ELF_File * file;
+
+    memset(sym, 0, sizeof(Symbol));
+    snprintf(fnm, sizeof(fnm), "/proc/%d/exe", ctx->mem);
+    file = elf_open(fnm);
+    if (file == NULL) error = errno;
+
+    if (error == 0 && file->sym_cache == NULL) {
+        if (load_tables(file) < 0) error = errno;
+    }
+
+    if (error == 0) {
+        int h = calc_hash(name);
+        SymbolTable * tbl = (SymbolTable *)file->sym_cache;
+        while (tbl != NULL && !found) {
+            int n = tbl->hash[h];
+            while (n && !found) {
+                Elf32_Sym * s = (Elf32_Sym *)tbl->syms + n;
+                if (strcmp(name, tbl->str + s->st_name) == 0) {
+                    found = 1;
+                    sym->abs = 1;
+                    sym->value = s->st_value;
+                    switch (ELF32_ST_BIND(s->st_info)) {
+                    case STB_LOCAL: sym->storage = "LOCAL"; break;
+                    case STB_GLOBAL: sym->storage = "GLOBAL"; break;
+                    case STB_WEAK: sym->storage = "WEAK"; break;
+                    }
+                    if (s->st_shndx > 0 && s->st_shndx < file->section_cnt) {
+                        static char sec_name[128];
+                        ELF_Section * sec = file->sections[s->st_shndx];
+                        if (sec != NULL && sec->name != NULL) {
+                            sym->section = strncpy(sec_name, sec->name, sizeof(sec_name));
+                        }
+                    }
+                }
+                n = tbl->hash_next[n];
+            }
+            tbl = tbl->next;
+        }
+    }
+
+    if (error == 0 && !found) error = ERR_SYM_NOT_FOUND;
+
+#endif
+
+    if (error) {
+        errno = error;
+        return -1;
+    }
+    return 0;
+}
+
+void ini_symbols_service(void) {
+    elf_add_close_listener(free_sym_cache);
+}
+
+#endif
+
diff --git a/symbols.h b/symbols.h
new file mode 100644
index 0000000..e8d1bf9
--- /dev/null
+++ b/symbols.h
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Symbols service.
+ */
+
+#ifndef D_symbols
+#define D_symbols
+
+#include "context.h"
+
+typedef struct Symbol Symbol;
+
+struct Symbol {
+    unsigned long value;
+    char * section;
+    char * storage;
+    int abs;
+};
+
+extern int find_symbol(Context * ctx, char * name, Symbol * sym);
+
+extern void ini_symbols_service(void);
+
+#endif
diff --git a/sysmon.c b/sysmon.c
new file mode 100644
index 0000000..f9b9163
--- /dev/null
+++ b/sysmon.c
@@ -0,0 +1,657 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+#include "config.h"
+#if SERVICE_SysMonitor
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include "mdep.h"
+#include "sysmon.h"
+#include "protocol.h"
+#include "json.h"
+#include "context.h"
+#include "errors.h"
+
+static const char SYS_MON[] = "SysMonitor";
+
+#if defined(WIN32)
+#  error "SysMonitor service is not supported for Windows"
+#elif defined(_WRS_KERNEL)
+#  error "SysMonitor service is not supported for VxWorks"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <linux/param.h>
+
+#define BUF_EOF (-1)
+
+static char buf[1024];
+static int buf_fd = -1;
+static int buf_pos = 0;
+static int buf_len = 0;
+static int buf_ch = 0;
+
+static void next_ch(void) {
+    while (buf_len >= 0 && buf_pos >= buf_len) {
+        buf_pos = 0;
+        buf_len = read(buf_fd, buf, sizeof(buf));
+        if (buf_len == 0) buf_len = -1;
+    }
+    if (buf_len < 0) {
+        buf_ch = BUF_EOF;
+    }
+    else {
+        buf_ch = buf[buf_pos++];
+    }
+}
+
+static void first_ch(int fd) {
+    buf_fd = fd;
+    buf_pos = 0;
+    buf_len = 0;
+    next_ch();
+}
+
+static void write_string_array(OutputStream * out, int f) {
+    int cnt = 0;
+    first_ch(f);
+    out->write(out, '[');
+    while (buf_ch != BUF_EOF && buf_ch != 0) {
+        if (cnt > 0) out->write(out, ',');
+        out->write(out, '"');
+        do {
+            json_write_char(out, buf_ch);
+            next_ch();
+        }
+        while (buf_ch != BUF_EOF && buf_ch != 0);
+        next_ch();
+        out->write(out, '"');
+        cnt++;
+    }
+    out->write(out, ']');
+}
+
+static void write_context(OutputStream * out, char * id, char * parent_id, char * dir) {
+    char fnm[FILE_PATH_SIZE + 1];
+    int sz;
+    int f;
+
+    out->write(out, '{');
+
+    if (chdir(dir) >= 0) {
+        if ((sz = readlink("cwd", fnm, FILE_PATH_SIZE)) > 0) {
+            fnm[sz] = 0;
+            json_write_string(out, "CWD");
+            out->write(out, ':');
+            json_write_string(out, fnm);
+            out->write(out, ',');
+        }
+
+        if ((sz = readlink("root", fnm, FILE_PATH_SIZE)) > 0) {
+            fnm[sz] = 0;
+            json_write_string(out, "Root");
+            out->write(out, ':');
+            json_write_string(out, fnm);
+            out->write(out, ',');
+        }
+
+        f = open("stat", O_RDONLY);
+        if (f >= 0) {
+            struct_stat st;
+            if (fstat(f, &st) == 0) {
+                struct passwd * pwd;
+                struct group * grp;
+
+                json_write_string(out, "UID");
+                out->write(out, ':');
+                json_write_long(out, st.st_uid);
+                out->write(out, ',');
+
+                json_write_string(out, "UGID");
+                out->write(out, ':');
+                json_write_long(out, st.st_gid);
+                out->write(out, ',');
+
+                pwd = getpwuid(st.st_uid);
+                if (pwd != NULL) {
+                    json_write_string(out, "UserName");
+                    out->write(out, ':');
+                    json_write_string(out, pwd->pw_name);
+                    out->write(out, ',');
+                }
+
+                grp = getgrgid(st.st_gid);
+                if (grp != NULL) {
+                    json_write_string(out, "GroupName");
+                    out->write(out, ':');
+                    json_write_string(out, grp->gr_name);
+                    out->write(out, ',');
+                }
+            }
+
+            memset(buf, 0, sizeof(buf));
+            if ((sz = read(f, buf, sizeof(buf))) > 0) {
+                char * str = buf;
+                int pid = 0;                // The process ID.
+                char * comm = fnm;          // The  filename  of  the  executable,  in parentheses.  This is visible
+                                            // whether or not the executable is swapped out.
+                char state = 0;             // One character from the string "RSDZTW"  where  R  is  running,  S  is
+                                            // sleeping  in  an  interruptible wait, D is waiting in uninterruptible
+                                            // disk sleep, Z is zombie, T is traced or stopped (on a signal), and  W
+                                            // is paging.
+                int ppid = 0;               // The PID of the parent.
+                int pgrp = 0;               // The process group ID of the process.
+                int session = 0;            // The session ID of the process.
+                int tty_nr = 0;             // The tty the process uses.
+                int tpgid = 0;              // The process group ID of the process which currently owns the tty that
+                                            // the process is connected to.
+                unsigned long flags = 0;    // The kernel flags word of the process. For bit meanings, see the  PF_*
+                                            // defines in <linux/sched.h>.  Details depend on the kernel version.
+                unsigned long minflt = 0;   // The  number  of  minor  faults  the  process  has made which have not
+                                            // required loading a memory page from disk.
+                unsigned long cminflt = 0;  // The number of minor faults that  the  process's  waited-for  children
+                                            // have made.
+                unsigned long majflt = 0;   // The  number  of major faults the process has made which have required
+                                            // loading a memory page from disk.
+                unsigned long cmajflt = 0;  // The number of major faults that  the  process's  waited-for  children
+                                            // have made.
+                unsigned long utime = 0;    // The  number  of  jiffies that this process has been scheduled in user
+                                            // mode.
+                unsigned long stime = 0;    // The number of jiffies that this process has been scheduled in  kernel
+                                            // mode.
+                long cutime = 0;            // The  number  of  jiffies that this process's waited-for children have
+                                            // been scheduled in user mode. (See also times(2).)
+                long cstime = 0;            // The number of jiffies that this process's  waited-for  children  have
+                                            // been scheduled in kernel mode.
+                long priority = 0;          // The  standard  nice value, plus fifteen.  The value is never negative
+                                            // in the kernel.
+                long nice = 0;              // The nice value ranges from 19 (nicest) to -19 (not nice to others).
+                long dummy = 0;             // This value is hard coded to 0 as a placeholder for a removed field.
+                long itrealvalue = 0;       // The time in jiffies before the next SIGALRM is sent  to  the  process
+                                            // due to an interval timer.
+                unsigned long starttime = 0;// The time in jiffies the process started after system boot.
+                unsigned long vsize = 0;    // Virtual memory size in bytes.
+                long rss = 0;               // Resident  Set  Size:  number of pages the process has in real memory,
+                                            // minus 3 for administrative purposes. This is  just  the  pages  which
+                                            // count  towards  text,  data,  or  stack space.  This does not include
+                                            // pages which have not been demand-loaded in, or which are swapped out.
+                unsigned long rlim = 0;     // Current  limit in bytes on the rss of the process (usually 4294967295
+                                            // on i386).
+                unsigned long startcode = 0;// The address above which program text can run.
+                unsigned long endcode = 0;  // The address below which program text can run.
+                unsigned long startstack =0;// The address of the start of the stack.
+                unsigned long kstkesp = 0;  // The current value of esp (stack pointer),  as  found  in  the  kernel
+                                            // stack page for the process.
+                unsigned long kstkeip = 0;  // The current EIP (instruction pointer).
+                unsigned long signal = 0;   // The bitmap of pending signals.
+                unsigned long blocked = 0;  // The bitmap of blocked signals.
+                unsigned long sigignore = 0;// The bitmap of ignored signals.
+                unsigned long sigcatch = 0; // The bitmap of caught signals.
+                unsigned long wchan = 0;    // This  is  the  "channel"  in which the process is waiting.  It is the
+                                            // address of a system call, and can be looked up in a namelist  if  you
+                                            // need  a  textual  name.   (If you have an up-to-date /etc/psdatabase,
+                                            // then try ps -l to see the WCHAN field in action.)
+                unsigned long nswap = 0;    // Number of pages swapped (not maintained).
+                unsigned long cnswap = 0;   // Cumulative nswap for child processes (not maintained).
+                int exit_signal = 0;        // Signal to be sent to parent when we die.
+                int processor = 0;          // CPU number last executed on.
+                unsigned long rt_priority=0;// Real-time scheduling priority (see sched_setscheduler(2)).
+                unsigned long policy = 0;   // Scheduling policy (see sched_setscheduler(2)).
+
+                assert(sz < sizeof(buf));
+                buf[sz] = 0;
+
+                pid = (int)strtol(str, &str, 10);
+                while (*str == ' ') str++;
+                if (*str == '(') str++;
+                sz = 0;
+                while (*str && *str != ')') comm[sz++] = *str++;
+                comm[sz] = 0;
+                if (*str == ')') str++;
+                while (*str == ' ') str++;
+
+                sscanf(str,
+                    "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu",
+                    &state, &ppid, &pgrp, &session, &tty_nr, &tpgid, &flags,
+                    &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime, &cutime, &cstime,
+                    &priority, &nice, &dummy, &itrealvalue, &starttime, &vsize, &rss, &rlim,
+                    &startcode, &endcode, &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore, &sigcatch,
+                    &wchan, &nswap, &cnswap, &exit_signal, &processor, &rt_priority, &policy);
+
+                json_write_string(out, "PID");
+                out->write(out, ':');
+                json_write_long(out, pid);
+                out->write(out, ',');
+
+                json_write_string(out, "File");
+                out->write(out, ':');
+                json_write_string(out, comm);
+                out->write(out, ',');
+
+                json_write_string(out, "State");
+                out->write(out, ':');
+                out->write(out, '"');
+                json_write_char(out, state);
+                out->write(out, '"');
+                out->write(out, ',');
+
+                if (ppid > 0) {
+                    json_write_string(out, "PPID");
+                    out->write(out, ':');
+                    json_write_long(out, ppid);
+                    out->write(out, ',');
+                }
+
+                json_write_string(out, "PGRP");
+                out->write(out, ':');
+                json_write_long(out, pgrp);
+                out->write(out, ',');
+
+                json_write_string(out, "Session");
+                out->write(out, ':');
+                json_write_long(out, session);
+                out->write(out, ',');
+
+                if (tty_nr > 0) {
+                    json_write_string(out, "TTY");
+                    out->write(out, ':');
+                    json_write_long(out, tty_nr);
+                    out->write(out, ',');
+                }
+
+                if (tpgid > 0) {
+                    json_write_string(out, "TGID");
+                    out->write(out, ':');
+                    json_write_long(out, tpgid);
+                    out->write(out, ',');
+                }
+
+                json_write_string(out, "Flags");
+                out->write(out, ':');
+                json_write_ulong(out, flags);
+                out->write(out, ',');
+
+                json_write_string(out, "MinFlt");
+                out->write(out, ':');
+                json_write_ulong(out, minflt);
+                out->write(out, ',');
+
+                json_write_string(out, "CMinFlt");
+                out->write(out, ':');
+                json_write_ulong(out, cminflt);
+                out->write(out, ',');
+
+                json_write_string(out, "MajFlt");
+                out->write(out, ':');
+                json_write_ulong(out, majflt);
+                out->write(out, ',');
+
+                json_write_string(out, "CMajFlt");
+                out->write(out, ':');
+                json_write_ulong(out, cmajflt);
+                out->write(out, ',');
+
+                json_write_string(out, "UTime");
+                out->write(out, ':');
+                json_write_int64(out, (int64)utime * 1000 / HZ);
+                out->write(out, ',');
+
+                json_write_string(out, "STime");
+                out->write(out, ':');
+                json_write_int64(out, (int64)stime * 1000 / HZ);
+                out->write(out, ',');
+
+                json_write_string(out, "CUTime");
+                out->write(out, ':');
+                json_write_int64(out, (int64)cutime * 1000 / HZ);
+                out->write(out, ',');
+
+                json_write_string(out, "CSTime");
+                out->write(out, ':');
+                json_write_int64(out, (int64)cstime * 1000 / HZ);
+                out->write(out, ',');
+
+                json_write_string(out, "Priority");
+                out->write(out, ':');
+                json_write_long(out, (long)priority - 15);
+                out->write(out, ',');
+
+                if (nice != 0) {
+                    json_write_string(out, "Nice");
+                    out->write(out, ':');
+                    json_write_long(out, nice);
+                    out->write(out, ',');
+                }
+
+                if (itrealvalue != 0) {
+                    json_write_string(out, "ITRealValue");
+                    out->write(out, ':');
+                    json_write_int64(out, (int64)itrealvalue * 1000 / HZ);
+                    out->write(out, ',');
+                }
+
+                json_write_string(out, "StartTime");
+                out->write(out, ':');
+                json_write_int64(out, (int64)starttime * 1000 / HZ);
+                out->write(out, ',');
+
+                json_write_string(out, "VSize");
+                out->write(out, ':');
+                json_write_ulong(out, vsize);
+                out->write(out, ',');
+
+                json_write_string(out, "PSize");
+                out->write(out, ':');
+                json_write_ulong(out, getpagesize());
+                out->write(out, ',');
+
+                json_write_string(out, "RSS");
+                out->write(out, ':');
+                json_write_long(out, rss);
+                out->write(out, ',');
+
+                json_write_string(out, "RLimit");
+                out->write(out, ':');
+                json_write_ulong(out, rlim);
+                out->write(out, ',');
+
+                if (startcode != 0) {
+                    json_write_string(out, "CodeStart");
+                    out->write(out, ':');
+                    json_write_ulong(out, startcode);
+                    out->write(out, ',');
+                }
+
+                if (endcode != 0) {
+                    json_write_string(out, "CodeEnd");
+                    out->write(out, ':');
+                    json_write_ulong(out, endcode);
+                    out->write(out, ',');
+                }
+
+                if (startstack != 0) {
+                    json_write_string(out, "StackStart");
+                    out->write(out, ':');
+                    json_write_ulong(out, startstack);
+                    out->write(out, ',');
+                }
+
+                json_write_string(out, "Signals");
+                out->write(out, ':');
+                json_write_ulong(out, signal);
+                out->write(out, ',');
+
+                json_write_string(out, "SigBlock");
+                out->write(out, ':');
+                json_write_ulong(out, blocked);
+                out->write(out, ',');
+
+                json_write_string(out, "SigIgnore");
+                out->write(out, ':');
+                json_write_ulong(out, sigignore);
+                out->write(out, ',');
+
+                json_write_string(out, "SigCatch");
+                out->write(out, ':');
+                json_write_ulong(out, sigcatch);
+                out->write(out, ',');
+
+                if (wchan != 0) {
+                    json_write_string(out, "WChan");
+                    out->write(out, ':');
+                    json_write_ulong(out, wchan);
+                    out->write(out, ',');
+                }
+
+                json_write_string(out, "NSwap");
+                out->write(out, ':');
+                json_write_ulong(out, nswap);
+                out->write(out, ',');
+
+                json_write_string(out, "CNSwap");
+                out->write(out, ':');
+                json_write_ulong(out, cnswap);
+                out->write(out, ',');
+
+                json_write_string(out, "ExitSignal");
+                out->write(out, ':');
+                json_write_long(out, exit_signal);
+                out->write(out, ',');
+
+                json_write_string(out, "Processor");
+                out->write(out, ':');
+                json_write_long(out, processor);
+                out->write(out, ',');
+
+                json_write_string(out, "RTPriority");
+                out->write(out, ':');
+                json_write_ulong(out, rt_priority);
+                out->write(out, ',');
+
+                json_write_string(out, "Policy");
+                out->write(out, ':');
+                json_write_ulong(out, policy);
+                out->write(out, ',');
+            }
+            close(f);
+        }
+    }
+
+    if (parent_id != NULL && parent_id[0] != 0) {
+        json_write_string(out, "ParentID");
+        out->write(out, ':');
+        json_write_string(out, parent_id);
+        out->write(out, ',');
+    }
+
+    json_write_string(out, "ID");
+    out->write(out, ':');
+    json_write_string(out, id);
+
+    out->write(out, '}');
+}
+
+static void command_get_context(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    pid_t pid = 0;
+    pid_t parent = 0;
+    int err = 0;
+    char dir[FILE_PATH_SIZE];
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    pid = id2pid(id, &parent);
+    if (pid != 0) {
+        struct_stat st;
+        if (parent != 0) {
+            snprintf(dir, sizeof(dir), "/proc/%d/task/%d", parent, pid);
+        }
+        else {
+            snprintf(dir, sizeof(dir), "/proc/%d", pid);
+        }
+        if (lstat(dir, &st) < 0) err = errno;
+        else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+    }
+
+    write_errno(out, err);
+    
+    if (err == 0 && pid != 0) {
+        char bf[256];
+        write_context(out, id, parent == 0 ? NULL : strcpy(bf, pid2id(parent, 0)), dir);
+        out->write(out, 0);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    DIR * proc = NULL;
+    char dir[FILE_PATH_SIZE];
+    pid_t pid = 0;
+    pid_t parent = 0;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    pid = id2pid(id, &parent);
+    if (pid == 0) strcpy(dir, "/proc");
+    else snprintf(dir, sizeof(dir), "/proc/%d/task", pid);
+
+    if (parent != 0) {
+        write_errno(out, 0);
+        write_stringz(out, "null");
+    }
+    else {
+        proc = opendir(dir);
+        if (proc == NULL) {
+            write_errno(out, errno);
+            write_stringz(out, "null");
+        }
+        else {
+            int cnt = 0;
+            write_errno(out, 0);
+            out->write(out, '[');
+            for (;;) {
+                struct dirent * ent = readdir(proc);
+                if (ent == NULL) break;
+                if (ent->d_name[0] >= '1' && ent->d_name[0] <= '9') {
+                    if (cnt > 0) out->write(out, ',');
+                    json_write_string(out, pid2id(atol(ent->d_name), pid));
+                    cnt++;
+                }
+            }
+            out->write(out, ']');
+            out->write(out, 0);
+            closedir(proc);
+        }
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_command_line(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    pid_t pid = 0;
+    pid_t parent = 0;
+    int err = 0;
+    char dir[256];
+    int f;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    pid = id2pid(id, &parent);
+    if (pid != 0 && parent == 0) {
+        struct_stat st;
+        snprintf(dir, sizeof(dir), "/proc/%d", pid);
+        if (lstat(dir, &st) < 0) err = errno;
+        else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+    }
+    else {
+        err = ERR_INV_CONTEXT;
+    }
+
+    if (err == 0 && chdir(dir) < 0) err = errno;
+    if (err == 0 && (f = open("cmdline", O_RDONLY)) < 0) err = errno;
+
+    write_errno(out, err);
+    
+    if (err == 0) {
+        write_string_array(out, f);
+        close(f);
+        out->write(out, 0);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+static void command_get_environment(char * token, InputStream * inp, OutputStream * out) {
+    char id[256];
+    pid_t pid = 0;
+    pid_t parent = 0;
+    int err = 0;
+    char dir[256];
+    int f;
+
+    json_read_string(inp, id, sizeof(id));
+    if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX);
+    if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+    write_stringz(out, "R");
+    write_stringz(out, token);
+
+    pid = id2pid(id, &parent);
+    if (pid != 0 && parent == 0) {
+        struct_stat st;
+        snprintf(dir, sizeof(dir), "/proc/%d", pid);
+        if (lstat(dir, &st) < 0) err = errno;
+        else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+    }
+    else {
+        err = ERR_INV_CONTEXT;
+    }
+
+    if (err == 0 && chdir(dir) < 0) err = errno;
+    if (err == 0 && (f = open("environ", O_RDONLY)) < 0) err = errno;
+
+    write_errno(out, err);
+    
+    if (err == 0) {
+        write_string_array(out, f);
+        close(f);
+        out->write(out, 0);
+    }
+    else {
+        write_stringz(out, "null");
+    }
+
+    out->write(out, MARKER_EOM);
+}
+
+extern void ini_sys_mon_service(void) {
+    add_command_handler(SYS_MON, "getContext", command_get_context);
+    add_command_handler(SYS_MON, "getChildren", command_get_children);
+    add_command_handler(SYS_MON, "getCommandLine", command_get_command_line);
+    add_command_handler(SYS_MON, "getEnvironment", command_get_environment);
+}
+
+#endif
+
diff --git a/sysmon.h b/sysmon.h
new file mode 100644
index 0000000..ef40aef
--- /dev/null
+++ b/sysmon.h
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Target service implementation: system monitor (TCF name SysMonitor)
+ */
+
+#ifndef D_sysmon
+#define D_sysmon
+
+/*
+ * Initialize system monitor service.
+ */
+extern void ini_sys_mon_service(void);
+
+#endif
diff --git a/tcf.h b/tcf.h
new file mode 100644
index 0000000..034ea3e
--- /dev/null
+++ b/tcf.h
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+#ifndef D_tcf
+#define D_tcf
+
+#define PKT_SIZE 0x1000
+
+#define UDP_REQ_INFO 1
+#define UDP_ACK_INFO 2
+
+#endif
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..1289ba2
--- /dev/null
+++ b/test.c
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Agent self-testing service.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+#include "myalloc.h"
+#include "mdep.h"
+#include "test.h"
+#include "trace.h"
+#include "context.h"
+
+void tcf_test_func2(void) {
+    usleep(1000);
+}
+
+void tcf_test_func1(void) {
+    tcf_test_func2();
+}
+
+void tcf_test_func0(void) {
+    tcf_test_func1();
+}
+
+char * tcf_test_array = NULL;
+
+static void * test_sub(void * x) {
+    volatile int * test_done = (int *)x;
+    while (!*test_done) {
+        tcf_test_func0();
+    }
+    return NULL;
+}
+
+static void test_proc(void) {
+    int i;
+    pthread_t thread[4];
+    int test_done = 0;
+    for (i = 0; i < 4; i++) {
+        thread[i] = 0;
+    }
+    for (i = 0; i < 4; i++) {
+        if (pthread_create(thread + i, &pthread_create_attr, test_sub, &test_done) != 0) {
+            perror("pthread_create");
+            break;
+        }
+    }
+    for (i = 0; i < 10; i++) {
+        tcf_test_func0();
+    }
+    test_done = 1;
+    for (i = 0; i < 4; i++) {
+        if (thread[i]) pthread_join(thread[i], NULL);
+    }
+}
+
+int run_test_process(pid_t * res) {
+#if defined(WIN32)
+    errno = EINVAL;
+    return -1;
+#elif defined(_WRS_KERNEL)
+    int tid = taskCreate("tTcf", 100, 0, 0x4000, (FUNCPTR)test_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    if (tid == 0) return -1;
+    taskStop(tid);
+    taskActivate(tid);
+    assert(taskIsStopped(tid));
+    if (tcf_test_array == NULL) tcf_test_array = loc_alloc(0x1000);
+    if (res != NULL) *res = tid;
+    return context_attach(tid, NULL);
+#else
+    /* Create child process to debug */
+    Context * ctx = NULL;
+    int pid = fork();
+    if (pid < 0) return -1;
+    if (pid == 0) {
+        tcf_test_array = loc_alloc(0x1000);
+        tkill(getpid(), SIGSTOP);
+        test_proc();
+        exit(0);
+    }
+    if (res != NULL) *res = pid;
+    if (context_attach(pid, &ctx) < 0) return -1;
+    ctx->pending_intercept = 1;
+    return 0;
+#endif
+}
+
diff --git a/test.h b/test.h
new file mode 100644
index 0000000..6baec28
--- /dev/null
+++ b/test.h
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Agent self-testing service.
+ */
+
+#ifndef D_test
+#define D_test
+
+#include "context.h"
+
+extern int run_test_process(pid_t * pid);
+
+#endif
diff --git a/trace.c b/trace.c
new file mode 100644
index 0000000..dffa79e
--- /dev/null
+++ b/trace.c
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include "mdep.h"
+#include "trace.h"
+
+FILE * log_file = NULL;
+int log_mode = LOG_EVENTS | LOG_CHILD | LOG_WAITPID | LOG_CONTEXT | LOG_PROTOCOL;
+
+static pthread_mutex_t mutex;
+
+int print_trace(int mode, char *fmt, ...) {
+    va_list ap;
+    struct timespec timenow;
+    char tmpbuf[1000];
+
+    if (log_file == NULL || mode != LOG_ALWAYS && (log_mode & mode) == 0) {
+        return 0;
+    }
+
+    if (clock_gettime(CLOCK_REALTIME, &timenow)) {
+        perror("clock_gettime");
+        exit(1);
+    }
+
+    va_start(ap, fmt);
+    vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
+    va_end(ap);
+
+    pthread_mutex_lock(&mutex);
+
+    fprintf(log_file, "TCF %02d%02d.%03d: %s\n",
+        timenow.tv_sec / 60 % 60,
+        timenow.tv_sec % 60,
+        timenow.tv_nsec / 1000000,
+        tmpbuf);
+    fflush(log_file);
+
+    pthread_mutex_unlock(&mutex);
+
+    return 1;
+}
+
+void ini_trace(void) {
+    pthread_mutex_init(&mutex, NULL);
+}
+
+
diff --git a/trace.h b/trace.h
new file mode 100644
index 0000000..290b5f7
--- /dev/null
+++ b/trace.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution, and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Log file and tracing.
+ */
+
+#ifndef D_trace
+#define D_trace
+
+#include <stdio.h>
+
+#define LOG_ALWAYS      0x0
+#define LOG_ALLOC       0x1
+#define LOG_EVENTCORE   0x2
+#define LOG_WAITPID     0x4
+#define LOG_EVENTS      0x8
+#define LOG_CHILD       0x10
+#define LOG_PROTOCOL    0x20
+#define LOG_CONTEXT     0x40
+
+extern FILE * log_file;
+extern int log_mode;
+
+/*
+ * Print a trace message into log file.
+ * Use macro 'trace' intead of calling this function directly.
+ */
+extern int print_trace(int mode, char *fmt, ...);
+
+#define trace log_file && print_trace
+
+extern void ini_trace(void);
+
+#endif