diff --git a/src/libcamera/pipeline/ipu3/frames.cpp b/src/libcamera/pipeline/ipu3/frames.cpp
index 4198e2019f3f..b8b471c3c561 100644
--- a/src/libcamera/pipeline/ipu3/frames.cpp
+++ b/src/libcamera/pipeline/ipu3/frames.cpp
@@ -131,4 +131,27 @@ IPU3Frames::Info *IPU3Frames::find(FrameBuffer *buffer)
 	return nullptr;
 }
 
+const std::string IPU3Frames::Info::toString() const
+{
+	std::stringstream ss;
+
+	ss << request->toString()
+	   << (metadataProcessed ? "" : "[!metadata]")
+	   << (paramDequeued ? "" : "[!param]");
+
+	return ss.str();
+}
+
+void IPU3Frames::dump() const
+{
+	LOG(IPU3, Error) << "Frames:";
+
+	for (auto const &itInfo : frameInfo_) {
+		Info *info = itInfo.second.get();
+
+		LOG(IPU3, Error)
+			<< " - " << info->toString();
+	}
+}
+
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/ipu3/frames.h b/src/libcamera/pipeline/ipu3/frames.h
index 4acdf48eca9d..c769ae864d32 100644
--- a/src/libcamera/pipeline/ipu3/frames.h
+++ b/src/libcamera/pipeline/ipu3/frames.h
@@ -34,6 +34,8 @@ public:
 
 		bool paramDequeued;
 		bool metadataProcessed;
+
+		const std::string toString() const;
 	};
 
 	IPU3Frames();
@@ -49,6 +51,8 @@ public:
 	Info *find(unsigned int id);
 	Info *find(FrameBuffer *buffer);
 
+	void dump() const;
+
 private:
 	std::queue<FrameBuffer *> availableParamBuffers_;
 	std::queue<FrameBuffer *> availableStatBuffers_;
