diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
index 880562157fbcdb6f4f6cd8a8481ec6e4993d71c6..929d547f6edbd43bc54262a976be787dd9ef1294 100644
--- a/indra/llcommon/llprocesslauncher.h
+++ b/indra/llcommon/llprocesslauncher.h
@@ -70,6 +70,14 @@ class LL_COMMON_API LLProcessLauncher
 	
 	// This needs to be called periodically on Mac/Linux to clean up zombie processes.
 	static void reap(void);
+	
+	// Accessors for platform-specific process ID
+#if LL_WINDOWS
+	HANDLE getProcessHandle() { return mProcessHandle; };
+#else
+	pid_t getProcessID() { return mProcessID; };
+#endif	
+	
 private:
 	std::string mExecutable;
 	std::string mWorkingDir;
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 457c074ef1e6046b92c69f2a8a50198fdfb7a600..42d5ec49cd302da5bb2c1e226ca9435e6e69d7a5 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -61,14 +61,14 @@ LLPluginClassMedia::~LLPluginClassMedia()
 	reset();
 }
 
-bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename)
+bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
 {	
 	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
 	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
 	
 	mPlugin = new LLPluginProcessParent(this);
 	mPlugin->setSleepTime(mSleepTime);
-	mPlugin->init(launcher_filename, plugin_filename);
+	mPlugin->init(launcher_filename, plugin_filename, debug);
 
 	return true;
 }
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 90ecd1e0735d3792699f7a332ae4264dc8bf2b7d..dcc4a3bd6a257c6e1993f1372b083f7e6c3a0de8 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -47,7 +47,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	virtual ~LLPluginClassMedia();
 
 	// local initialization, called by the media manager when creating a source
-	virtual bool init(const std::string &launcher_filename, const std::string &plugin_filename);
+	virtual bool init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug = false);
 
 	// undoes everything init() didm called by the media manager when destroying a source
 	virtual void reset();
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 39f9438fb3de59279cbf173ed2b5ec650cd074e7..b7ce800c3aba27263f479d1f0255cd72147192be 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -55,6 +55,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
 	mBoundPort = 0;
 	mState = STATE_UNINITIALIZED;
 	mDisableTimeout = false;
+	mDebug = false;
 
 	// initialize timer - heartbeat test (mHeartbeat.hasExpired()) 
 	// can sometimes return true immediately otherwise and plugins 
@@ -96,11 +97,12 @@ void LLPluginProcessParent::errorState(void)
 		setState(STATE_ERROR);
 }
 
-void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename)
+void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
 {	
 	mProcess.setExecutable(launcher_filename);
 	mPluginFile = plugin_filename;
 	mCPUUsage = 0.0f;
+	mDebug = debug;
 	
 	setState(STATE_INITIALIZED);
 }
@@ -291,6 +293,31 @@ void LLPluginProcessParent::idle(void)
 				}
 				else
 				{
+					if(mDebug)
+					{
+						#if LL_DARWIN
+						// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
+						
+						// The command we're constructing would look like this on the command line:
+						// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
+
+						std::stringstream cmd;
+						
+						mDebugger.setExecutable("/usr/bin/osascript");
+						mDebugger.addArgument("-e");
+						mDebugger.addArgument("tell application \"Terminal\"");
+						mDebugger.addArgument("-e");
+						cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\"";
+						mDebugger.addArgument(cmd.str());
+						mDebugger.addArgument("-e");
+						mDebugger.addArgument("do script \"continue\" in win");
+						mDebugger.addArgument("-e");
+						mDebugger.addArgument("end tell");
+						mDebugger.launch();
+
+						#endif
+					}
+					
 					// This will allow us to time out if the process never starts.
 					mHeartbeat.start();
 					mHeartbeat.setTimerExpirySec(PLUGIN_LAUNCH_SECONDS);
@@ -661,7 +688,7 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
 {
 	bool result = false;
 	
-	if(!mDisableTimeout)
+	if(!mDisableTimeout && !mDebug)
 	{
 		if(!mProcess.isRunning())
 		{
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 754ebeb94683efc033c077013f0f06bc48dde25b..1289e86c1365521be3ecea831ab895c9ce1303a9 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -56,7 +56,7 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	LLPluginProcessParent(LLPluginProcessParentOwner *owner);
 	~LLPluginProcessParent();
 		
-	void init(const std::string &launcher_filename, const std::string &plugin_filename);
+	void init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug = false);
 	void idle(void);
 	
 	// returns true if the plugin is on its way to steady state
@@ -150,6 +150,9 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	F64		mCPUUsage;
 	
 	bool mDisableTimeout;
+	bool mDebug;
+
+	LLProcessLauncher mDebugger;
 };
 
 #endif // LL_LLPLUGINPROCESSPARENT_H
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 55ff255c38e82a6ddb4f2ca2d8584d645c5ccfed..15c9499bbc825a8257c93f40d89a6c5fd2748195 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5327,6 +5327,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>PluginAttachDebuggerToPlugins</key>
+    <map>
+      <key>Comment</key>
+      <string>If true, attach a debugger session to each plugin process as it's launched.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>PluginInstancesCPULimit</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 69650425cb437228f7dab228986e2114a56cf36a..66d48fadd18c1e823e1da515af249b517c5c7f31 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -847,7 +847,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 		{
 			LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
 			media_source->setSize(default_width, default_height);
-			if (media_source->init(launcher_name, plugin_name))
+			if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
 			{
 				return media_source;
 			}