layers: Prevent layer calls with null dispatches.

Change GetDeviceProcAddr policy such that nullptr are returned for any
entry point which has a nullptr in the dispatch table.

Change-Id: I848a7ad1eadbe45ec2e170359b5acf72347936de
diff --git a/scripts/dispatch_table_helper_generator.py b/scripts/dispatch_table_helper_generator.py
index 6ecd43b..081c953 100644
--- a/scripts/dispatch_table_helper_generator.py
+++ b/scripts/dispatch_table_helper_generator.py
@@ -238,7 +238,16 @@
         table = ''
         if table_type == 'device':
             entries = self.device_dispatch_list
-            table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n'
+            table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa_func,\n'
+            table += '                                                    std::unordered_map<std::string, void *> *layer_entrypoint_map = nullptr) {\n'
+            table += '    // Wrap the gpa function to update the supplied map\n'
+            table += '    auto gpa = [gpa_func, layer_entrypoint_map] (VkDevice device, const char *entry_point) {\n'
+            table += '        PFN_vkVoidFunction proc_addr = gpa_func(device, entry_point);\n'
+            table += '        if (!proc_addr && layer_entrypoint_map) {\n'
+            table += '            (*layer_entrypoint_map)[entry_point] = nullptr;\n'
+            table += '        }\n'
+            table += '        return proc_addr;\n'
+            table += '    };\n\n'
             table += '    memset(table, 0, sizeof(*table));\n'
             table += '    // Device function pointers\n'
         else:
@@ -258,7 +267,7 @@
             # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
             # a layer overrides the function name for the loader.
             if ('device' in table_type and base_name == 'GetDeviceProcAddr'):
-                table += '    table->GetDeviceProcAddr = gpa;\n'
+                table += '    table->GetDeviceProcAddr = gpa_func;\n'
             elif ('device' not in table_type and base_name == 'GetInstanceProcAddr'):
                 table += '    table->GetInstanceProcAddr = gpa;\n'
             else:
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 8608605..6d16dce 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -447,7 +447,7 @@
 
         # Record intercepted procedures
         write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+        write('std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
         write('\n'.join(self.intercepts), file=self.outFile)
         write('};\n', file=self.outFile)
         self.newline()
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index 735916c..0119f12 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -357,7 +357,7 @@
         write('// Declarations', file=self.outFile)
         write('\n'.join(self.declarations), file=self.outFile)
         write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+        write('std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
         write('\n'.join(self.intercepts), file=self.outFile)
         write('};\n', file=self.outFile)
         self.newline()
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
index 5cfb4d7..7475898 100644
--- a/scripts/threading_generator.py
+++ b/scripts/threading_generator.py
@@ -274,7 +274,7 @@
         self.newline()
         # record intercepted procedures
         write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+        write('static std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
         write('\n'.join(self.intercepts), file=self.outFile)
         write('};\n', file=self.outFile)
         self.newline()
diff --git a/scripts/unique_objects_generator.py b/scripts/unique_objects_generator.py
index 9fd6328..5b5138b 100644
--- a/scripts/unique_objects_generator.py
+++ b/scripts/unique_objects_generator.py
@@ -250,7 +250,7 @@
 
         # Record intercepted procedures
         write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+        write('static std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
         write('\n'.join(self.intercepts), file=self.outFile)
         write('};\n', file=self.outFile)
         self.newline()